# -*- coding: utf-8 -*-
import requests
import logging
from odoo import models, fields, api, _
from odoo.exceptions import UserError

_logger = logging.getLogger(__name__)


class ShopifyRefundWizard(models.TransientModel):
    _name = 'shopify.refund.wizard'
    _description = 'Asistente de Reembolso Shopify'

    order_id = fields.Many2one('sale.order', string='Pedido de Venta', required=True)
    shopify_order_id = fields.Char(string='ID Orden Shopify', related='order_id.shopify_order_id', readonly=True)
    shopify_order_number = fields.Char(string='Pedido Shopify', related='order_id.shopify_order_number', readonly=True)

    line_ids = fields.One2many('shopify.refund.wizard.line', 'wizard_id', string='Productos a Reembolsar')
    note = fields.Text(string='Motivo del Reembolso')
    restock = fields.Boolean(
        string='Regresar Productos al Stock', default=True,
        help="Si está marcado, los artículos se devolverán al inventario en Shopify y Odoo."
    )
    notify_customer = fields.Boolean(
        string='Notificar al Cliente por Email', default=True,
        help="Si está activo, Shopify le enviará un correo automático de reembolso al cliente."
    )
    amount_to_refund = fields.Float(
        string='Monto Estimado a Reembolsar',
        compute='_compute_amount_to_refund',
        readonly=True,
        help="Suma de los precios de venta de las cantidades seleccionadas."
    )

    @api.depends('line_ids.quantity_to_refund', 'line_ids.price_unit')
    def _compute_amount_to_refund(self):
        for rec in self:
            rec.amount_to_refund = sum(
                line.price_unit * line.quantity_to_refund
                for line in rec.line_ids
            )

    @api.model
    def default_get(self, fields_list):
        """
        Carga el order_id y sus líneas de productos asociadas directamente.
        """
        res = super().default_get(fields_list)
        active_id = self.env.context.get('active_id')
        if active_id:
            order = self.env['sale.order'].sudo().browse(active_id)
            if order.exists():
                res['order_id'] = order.id
                
                # Cargar líneas directamente en el default_get
                new_lines = []
                for line in order.order_line.filtered(lambda l: not l.display_type and l.product_id):
                    new_lines.append((0, 0, {
                        'product_id': line.product_id.id,
                        'odoo_sku': line.product_id.default_code or '',
                        'product_name': line.product_id.name or '',
                        'shopify_line_item_id': '',
                        'quantity_ordered': line.product_uom_qty,
                        'quantity_refunded': 0.0,
                        'quantity_to_refund': 0.0,
                        'price_unit': line.price_unit,
                    }))
                res['line_ids'] = new_lines
                _logger.info(
                    "[Reembolso Wizard] [default_get] Cargadas %s líneas de productos para pedido %s",
                    len(new_lines), order.name
                )
        return res

    @api.onchange('order_id')
    def _onchange_order_id(self):
        """
        Cuando se fija el pedido de venta, carga automáticamente los productos
        de las líneas del pedido de Odoo para mostrarlos en el wizard.
        NO llama a Shopify en este paso — los IDs de línea de Shopify
        se resuelven en el momento de confirmar el reembolso.
        """
        self.line_ids = [(5, 0, 0)]  # Limpia líneas anteriores
        if not self.order_id:
            return

        order = self.order_id.sudo()
        new_lines = []
        for line in order.order_line.filtered(lambda l: not l.display_type and l.product_id):
            new_lines.append((0, 0, {
                'product_id': line.product_id.id,
                'odoo_sku': line.product_id.default_code or '',
                'product_name': line.product_id.name or '',
                'shopify_line_item_id': '',   # Se resuelve al confirmar
                'quantity_ordered': line.product_uom_qty,
                'quantity_refunded': 0.0,
                'quantity_to_refund': 0.0,
                'price_unit': line.price_unit,
            }))

        self.line_ids = new_lines
        _logger.info(
            "[Reembolso Wizard] Cargadas %s líneas de productos para pedido %s",
            len(new_lines), order.name
        )

    def action_confirm_refund(self):
        self.ensure_one()

        # ── LOGGING EXTENSIVO SOLICITADO POR EL USUARIO ───────────────────────
        _logger.info("=" * 60)
        _logger.info("[Reembolso Wizard] action_confirm_refund llamada.")
        _logger.info("[Reembolso Wizard] ID del Registro Wizard: %s", self.id)
        _logger.info("[Reembolso Wizard] Pedido Odoo ID: %s (%s)", self.order_id.id if self.order_id else 'None', self.order_id.name if self.order_id else 'None')
        _logger.info("[Reembolso Wizard] Pedido Shopify ID: %s, Número: %s", self.shopify_order_id, self.shopify_order_number)
        _logger.info("[Reembolso Wizard] Total de líneas en wizard (self.line_ids): %s", len(self.line_ids))
        for idx, line in enumerate(self.line_ids, 1):
            _logger.info(
                "[Reembolso Wizard] Línea #%s -> ID: %s, product_id: %s (%s), SKU: %s, "
                "Cant. Original: %s, Cant. Reembolsada: %s, A Reembolsar: %s, Precio Unitario: %s",
                idx, line.id, line.product_id.id if line.product_id else 'None',
                line.product_name or 'None', line.odoo_sku or 'None',
                line.quantity_ordered, line.quantity_refunded, line.quantity_to_refund, line.price_unit
            )
        _logger.info("=" * 60)

        # ── 1. Validar que hay al menos un producto seleccionado ──────────────
        refund_lines = self.line_ids.filtered(lambda l: l.quantity_to_refund > 0)
        if not refund_lines:
            raise UserError(
                "Por favor selecciona al menos 1 artículo con cantidad "
                "mayor a 0 para reembolsar."
            )

        config = self.env['shopify.config'].sudo().search(
            [('state', '=', 'confirmed')], limit=1
        )
        if not config:
            raise UserError("No hay una configuración activa de Shopify para procesar el reembolso.")

        # ── 2. Candado Sandbox ────────────────────────────────────────────────
        if config.shopify_sandbox_mode:
            has_real_products = any(
                not l.display_type and l.product_id and
                'PRUEBA' not in (l.product_id.default_code or '').upper()
                for l in self.order_id.order_line
            )
            if has_real_products:
                raise UserError(
                    "🛡️ [SEGURIDAD SANDBOX] Bloqueo de Seguridad Activo.\n\n"
                    "Este pedido contiene artículos reales de producción. "
                    "No está permitido realizar reembolsos hacia Shopify en vivo "
                    "para pedidos reales mientras el 'Modo Sandbox' esté activo."
                )

        # ── 3. Conectar a Shopify y obtener el pedido actualizado ─────────────
        token = config._ensure_access_token()
        shop_domain = (
            config.shop_url.strip().lower()
            .replace('https://', '').replace('http://', '')
            .split('/')[0]
        )
        headers = {
            'X-Shopify-Access-Token': token,
            'Content-Type': 'application/json',
        }

        order_url = (
            f"https://{shop_domain}/admin/api/2024-01/orders/"
            f"{self.shopify_order_id}.json"
        )
        order_resp = requests.get(order_url, headers=headers, timeout=15)
        if order_resp.status_code != 200:
            raise UserError(
                "No se pudo consultar el pedido en Shopify.\n"
                "Código HTTP: %s\nDetalle: %s" % (order_resp.status_code, order_resp.text)
            )

        s_order = order_resp.json().get('order', {})

        # Indexar line_items de Shopify por SKU y por título para encontrar el ID
        shopify_items_by_sku = {}
        shopify_items_by_name = {}
        for item in s_order.get('line_items', []):
            sku = (item.get('sku') or '').strip()
            title = (item.get('title') or '').strip().lower()
            if sku:
                shopify_items_by_sku[sku] = item
            if title:
                shopify_items_by_name[title] = item

        # ── 4. Construir calc_line_items buscando el ID de Shopify ─────────────
        calc_line_items = []
        for line in refund_lines:
            sku = (line.odoo_sku or '').strip()
            name = (line.product_name or (line.product_id.name if line.product_id else '') or '').strip().lower()

            # Buscar por SKU exacto primero, luego por nombre
            s_item = shopify_items_by_sku.get(sku)
            if not s_item and name:
                s_item = shopify_items_by_name.get(name)

            if not s_item:
                product_display = line.product_id.display_name if line.product_id else '(sin producto)'
                raise UserError(
                    "No se encontró el producto '%s' en el pedido de Shopify %s.\n"
                    "Verifica que el SKU o nombre del producto coincida." % (
                        product_display, self.shopify_order_number or self.shopify_order_id
                    )
                )

            shopify_line_id = s_item.get('id')
            _logger.info(
                "[Reembolso] Mapeando '%s' → Shopify line_item_id=%s",
                line.product_id.display_name if line.product_id else sku,
                shopify_line_id
            )

            calc_line_item = {
                'line_item_id': int(shopify_line_id),
                'quantity': int(line.quantity_to_refund),
            }
            if self.restock:
                calc_line_item['restock_type'] = 'return'
                calc_line_item['location_id'] = int(config.shopify_location_id or 0)
            calc_line_items.append(calc_line_item)

        # ── 5. Paso A: Calculate ───────────────────────────────────────────────
        calc_url = (
            f"https://{shop_domain}/admin/api/2024-01/orders/"
            f"{self.shopify_order_id}/refunds/calculate.json"
        )
        calc_payload = {
            'refund': {
                'shipping': {'full_refund': False},
                'refund_line_items': calc_line_items,
            }
        }

        _logger.info("[Reembolso API] Calculando reembolso para orden Shopify %s", self.shopify_order_number)
        calc_resp = requests.post(calc_url, headers=headers, json=calc_payload, timeout=20)

        if calc_resp.status_code != 200:
            raise UserError(
                "Error al calcular el reembolso en Shopify.\n"
                "Código HTTP: %s\nDetalle: %s" % (calc_resp.status_code, calc_resp.text)
            )

        calc_data = calc_resp.json().get('refund', {})

        # ── 6. Paso B: Crear el Reembolso Definitivo ───────────────────────────
        refund_url = (
            f"https://{shop_domain}/admin/api/2024-01/orders/"
            f"{self.shopify_order_id}/refunds.json"
        )

        transactions = [
            {
                'parent_id': t.get('parent_id'),
                'amount': t.get('amount'),
                'kind': 'refund',
                'gateway': t.get('gateway'),
            }
            for t in calc_data.get('transactions', [])
        ]

        refund_payload = {
            'refund': {
                'currency': calc_data.get('currency', 'MXN'),
                'notify': self.notify_customer,
                'note': self.note or 'Reembolso procesado desde Odoo',
                'refund_line_items': calc_line_items,
                'transactions': transactions,
            }
        }

        _logger.info("[Reembolso API] Enviando reembolso para orden Shopify %s", self.shopify_order_number)
        refund_resp = requests.post(refund_url, headers=headers, json=refund_payload, timeout=20)

        if refund_resp.status_code not in (200, 201):
            raise UserError(
                "Shopify rechazó el reembolso definitivo.\n"
                "Código HTTP: %s\nDetalle: %s" % (refund_resp.status_code, refund_resp.text)
            )

        refund_data_final = refund_resp.json().get('refund', {})
        new_refund_id = str(refund_data_final.get('id'))
        _logger.info("[Reembolso API] ✅ Reembolso creado en Shopify: ID %s", new_refund_id)

        # ── 7. Sincronizar en Odoo para generar Nota de Crédito y Devolución ──
        try:
            sync_resp = requests.get(order_url, headers=headers, timeout=15)
            if sync_resp.status_code == 200:
                config._import_single_shopify_order(sync_resp.json().get('order', {}))
        except Exception as e_sync:
            _logger.error("Error al forzar sincronización del reembolso: %s", str(e_sync))

        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'title': '✅ Reembolso Procesado con Éxito',
                'message': (
                    f"El reembolso ID {new_refund_id} fue enviado a Shopify. "
                    f"Se han generado los documentos internos en Odoo."
                ),
                'type': 'success',
                'sticky': False,
                'next': {
                    'type': 'ir.actions.act_window',
                    'res_model': 'sale.order',
                    'res_id': self.order_id.id,
                    'view_mode': 'form',
                    'views': [(False, 'form')],
                    'target': 'main',
                }
            }
        }


class ShopifyRefundWizardLine(models.TransientModel):
    _name = 'shopify.refund.wizard.line'
    _description = 'Línea de Asistente de Reembolso'

    wizard_id = fields.Many2one('shopify.refund.wizard', string='Wizard', ondelete='cascade')
    product_id = fields.Many2one('product.product', string='Producto')
    # Campos auxiliares para mapeo a Shopify al momento de confirmar
    odoo_sku = fields.Char(string='SKU Odoo')
    product_name = fields.Char(string='Nombre Producto')
    # El ID de línea de Shopify se resuelve al confirmar, no al abrir
    shopify_line_item_id = fields.Char(string='ID Línea Shopify')

    quantity_ordered = fields.Float(string='Cant. Original')
    quantity_refunded = fields.Float(string='Cant. Reembolsada')
    quantity_to_refund = fields.Float(string='A Reembolsar', default=0.0)
    price_unit = fields.Float(string='Precio Unitario')

