import jsPDF from 'jspdf';
import QRCode from 'qrcode';
import { formatMoney, PAYMENT_METHODS } from '@/utils/formatters';
import { apiURL } from '@Services/Api';
import printService from '@Services/printService';

/**
 * Servicio para generar tickets de venta en formato PDF
 */
const ticketService = {

    /**
     * Detectar ubicación del usuario (ciudad y estado)
     */
    async getUserLocation() {
        return {
            city: import.meta.env.VITE_BUSINESS_CITY || 'Villahermosa',
            state: import.meta.env.VITE_BUSINESS_STATE || 'Tabasco',
            country: import.meta.env.VITE_BUSINESS_COUNTRY || 'México',
            phone: import.meta.env.VITE_BUSINESS_PHONE || '',
        };
    },

    /**
     * Obtener información de un bundle desde la API
     * @param {Number} bundleId - ID del bundle
     * @returns {Object|null}
     */
    async fetchBundleInfo(bundleId) {
        try {
            const { data: result } = await window.axios.get(
                apiURL(`bundles/${bundleId}`),
                {
                    headers: {
                        'Authorization': `Bearer ${sessionStorage.token}`,
                        'Accept': 'application/json'
                    }
                }
            );
            const bundle = result?.data?.model
                || result?.model
                || result?.data
                || result;

            if (!bundle || !bundle.name) {
                console.warn(`fetchBundleInfo: No se pudo extraer nombre del bundle ${bundleId}`);
                return null;
            }

            // Intentar obtener el precio de múltiples campos posibles
            const price = parseFloat(bundle.retail_price)
                || parseFloat(bundle.price?.retail_price)
                || parseFloat(bundle.prices?.retail_price)
                || parseFloat(bundle.bundle_price?.retail_price)
                || parseFloat(bundle.price)
                || 0;


            return {
                name: bundle.name,
                sku: bundle.sku || null,
                unit_price: price
            };
        } catch (e) {
            console.error(`Error al obtener bundle ${bundleId}:`, e);
            console.error('Response data:', e.response?.data);
        }
        return null;
    },

    /**
     * Generar ticket de venta
     * @param {Object} saleData - Datos de la venta
     * @param {Object} options - Opciones de configuración
     * @param {boolean} options.autoDownload - Descargar automáticamente el PDF
     * @param {boolean} options.autoPrint - Imprimir automáticamente (abre diálogo del navegador)
     */
    async generateSaleTicket(saleData, options = {}) {
        const {
            businessName = 'HIKVISION DISTRIBUIDOR',
            autoDownload = true,
            autoPrint = false,
            bundleMap = {},
            unitMap = {}
        } = options;

        // Detectar ubicación del usuario
        const location = await this.getUserLocation();
        const businessAddress = `${location.city}, ${location.state}, ${location.country}`;
        const businessPhone = location.phone;

        // Crear documento PDF - Ticket térmico 80mm de ancho
        const doc = new jsPDF({
            orientation: 'portrait',
            unit: 'mm',
            format: [80, 297]
        });

        let yPosition = 10;
        const leftMargin = 5;
        const rightMargin = 75;
        const centerX = 40;
        const lineHeight = 5;

        // Colores
        const blackColor = [0, 0, 0];
        const darkGrayColor = [80, 80, 80];

        // ===== HEADER =====
        // Nombre del negocio
        doc.setFontSize(14);
        doc.setFont('helvetica', 'bold');
        doc.setTextColor(...blackColor);
        doc.text(businessName, centerX, yPosition, { align: 'center' });
        yPosition += 6;

        // Dirección y teléfono
        doc.setFontSize(8);
        doc.setFont('helvetica', 'normal');
        doc.setTextColor(...darkGrayColor);
        doc.text(businessAddress, centerX, yPosition, { align: 'center' });
        yPosition += 4;
        doc.text(businessPhone, centerX, yPosition, { align: 'center' });
        yPosition += 6;

        // Línea separadora
        doc.setLineWidth(0.3);
        doc.setDrawColor(...blackColor);
        doc.line(leftMargin, yPosition, rightMargin, yPosition);
        yPosition += 5;

        // ===== TÍTULO =====
        doc.setFontSize(12);
        doc.setFont('helvetica', 'bold');
        doc.setTextColor(...blackColor);
        doc.text('TICKET DE VENTA', centerX, yPosition, { align: 'center' });
        yPosition += 7;

        // ===== INFORMACIÓN DE LA VENTA =====
        doc.setFontSize(8);
        doc.setFont('helvetica', 'normal');
        doc.setTextColor(...darkGrayColor);

        // Folio
        const folio = saleData.invoice_number || `INV-${String(saleData.id || '').padStart(7, '0')}`;
        doc.text(`Folio: ${folio}`, leftMargin, yPosition);
        yPosition += 4;

        // Fecha
        const saleDate = new Date(saleData.created_at || Date.now());
        const formattedDate = saleDate.toLocaleDateString('es-MX', {
            year: 'numeric',
            month: 'long',
            day: 'numeric'
        });
        doc.text(`Fecha: ${formattedDate}`, leftMargin, yPosition);
        yPosition += 4;

        // Hora
        const formattedTime = saleDate.toLocaleTimeString('es-MX', {
            hour: '2-digit',
            minute: '2-digit'
        });
        doc.text(`Hora: ${formattedTime}`, leftMargin, yPosition);
        yPosition += 4;

        // Cajero
        if (saleData.user?.name) {
            doc.text(`Cajero: ${saleData.user.name}`, leftMargin, yPosition);
            yPosition += 4;
        }

        // Método de pago
        const paymentLabel = PAYMENT_METHODS[saleData.payment_method] || saleData.payment_method;
        doc.text(`Pago: ${paymentLabel}`, leftMargin, yPosition);
        yPosition += 6;

        // Línea separadora
        doc.line(leftMargin, yPosition, rightMargin, yPosition);
        yPosition += 5;

        // ===== PRODUCTOS =====
        doc.setFontSize(9);
        doc.setFont('helvetica', 'bold');
        doc.setTextColor(...blackColor);
        doc.text('PRODUCTOS', centerX, yPosition, { align: 'center' });
        yPosition += 5;

        // Header de tabla
        doc.setFontSize(7);
        doc.setFont('helvetica', 'bold');
        doc.setTextColor(...darkGrayColor);
        doc.text('DESCRIPCIÓN', leftMargin, yPosition);
        doc.text('CANT', 52, yPosition, { align: 'center' });
        doc.text('PRECIO', rightMargin, yPosition, { align: 'right' });
        yPosition += 4;

        // Línea bajo header
        doc.setLineWidth(0.2);
        doc.line(leftMargin, yPosition, rightMargin, yPosition);
        yPosition += 4;

        // Separar details: agrupar los de bundle por bundle_sale_group, dejar individuales aparte
        const rawDetails = saleData.details || saleData.items || [];
        const bundleGroupMap = {};
        const regularItems = [];

        rawDetails.forEach(item => {
            if (item.bundle_id) {
                const groupKey = item.bundle_sale_group || `bundle-${item.bundle_id}`;
                if (!bundleGroupMap[groupKey]) {
                    bundleGroupMap[groupKey] = {
                        bundle_id: item.bundle_id,
                        components: [],
                        total_subtotal: 0,
                        serials: []
                    };
                }
                bundleGroupMap[groupKey].components.push(item);
                const itemSubtotal = parseFloat(item.subtotal)
                    || (parseFloat(item.unit_price) * parseFloat(item.quantity))
                    || 0;
                bundleGroupMap[groupKey].total_subtotal += itemSubtotal;
                const itemSerials = item.serial_numbers || item.serials || [];
                itemSerials.forEach(s => bundleGroupMap[groupKey].serials.push(s));
            } else {
                regularItems.push(item);
            }
        });

        // Obtener IDs únicos de bundles que NO están en bundleMap
        const missingBundleIds = [...new Set(
            Object.values(bundleGroupMap)
                .map(d => d.bundle_id)
                .filter(id => !bundleMap[id])
        )];

        // Fetch de bundles faltantes en paralelo
        if (missingBundleIds.length > 0) {
            const fetched = await Promise.all(
                missingBundleIds.map(id => this.fetchBundleInfo(id))
            );
            missingBundleIds.forEach((id, i) => {
                if (fetched[i]) {
                    bundleMap[id] = fetched[i];
                }
            });
        }

        // Construir lista final
        const displayItems = [
            ...regularItems,
            ...Object.values(bundleGroupMap).map((data) => {
                const info = bundleMap[data.bundle_id] || {};

                const bundleName = info.name || `Paquete #${data.bundle_id}`;

                // Calcular precio con fallbacks múltiples
                let bundlePrice = 0;

                // 1. Precio del bundleMap (viene del fetch o de Point.vue)
                if (info.unit_price && parseFloat(info.unit_price) > 0) {
                    bundlePrice = parseFloat(info.unit_price);
                }
                // 2. Suma de subtotales de los componentes
                else if (data.total_subtotal > 0) {
                    bundlePrice = data.total_subtotal;
                }
                // 3. Recalcular desde unit_price × quantity de cada componente
                else {
                    bundlePrice = data.components.reduce((sum, c) => {
                        const price = parseFloat(c.unit_price || c.price || 0);
                        const qty = parseFloat(c.quantity || 1);
                        return sum + (price * qty);
                    }, 0);
                }

                // 4. Si aún es 0, usar el subtotal de la venta dividido
                if (bundlePrice === 0) {
                    const saleSubtotal = parseFloat(saleData.subtotal || 0);
                    const regularSubtotal = regularItems.reduce((sum, i) => {
                        return sum + (parseFloat(i.unit_price || 0) * parseFloat(i.quantity || 1));
                    }, 0);
                    bundlePrice = saleSubtotal - regularSubtotal;
                    if (bundlePrice < 0) bundlePrice = 0;
                }

                return {
                    product_name: bundleName,
                    sku: info.sku || '',
                    quantity: 1,
                    unit_price: bundlePrice,
                    serials: data.serials,
                    is_bundle: true,
                    components: data.components
                };
            })
        ];

        // Iterar sobre los items a mostrar
        doc.setFont('helvetica', 'normal');
        doc.setTextColor(...blackColor);

        displayItems.forEach((item) => {
            // Nombre del producto
            const productName = item.product_name || item.name || 'Producto';
            const nameLines = doc.splitTextToSize(productName, 45);

            doc.setFontSize(8);
            doc.setFont('helvetica', 'bold');
            doc.text(nameLines, leftMargin, yPosition);
            yPosition += nameLines.length * 3.5;

            // SKU (opcional)
            if (item.inventory?.sku || item.sku) {
                doc.setFontSize(7);
                doc.setFont('helvetica', 'normal');
                doc.setTextColor(...darkGrayColor);
                doc.text(`SKU: ${item.inventory?.sku || item.sku}`, leftMargin, yPosition);
                yPosition += 3;
            }

            // Cantidad y Precio
            const unitInfo = unitMap[item.inventory_id];
            const displayQty = unitInfo?.quantity
                ?? ((item.unit_of_measure_id && item.unit_quantity)
                    ? parseFloat(item.unit_quantity)
                    : (item.quantity || 1));
            const unitAbbr = unitInfo?.unit_name
                || (item.unit_of_measure_id
                    ? (item.unit_of_measure?.abbreviation || item.unit_of_measure?.name || '')
                    : '');
            const qtyText = unitAbbr ? `${displayQty} ${unitAbbr}` : String(displayQty);

            const unitPrice = formatMoney(item.unit_price);

            doc.setFontSize(8);
            doc.setFont('helvetica', 'normal');
            doc.setTextColor(...blackColor);

            doc.text(qtyText, 52, yPosition, { align: 'center' });
            doc.text(`$${unitPrice}`, rightMargin, yPosition, { align: 'right' });

            yPosition += 4;

            // Componentes del paquete (mostrar productos con SKU y sus seriales)
            if (item.is_bundle && item.components && item.components.length > 0) {
                doc.setFontSize(7);
                doc.setFont('helvetica', 'normal');
                doc.setTextColor(...darkGrayColor);

                item.components.forEach((comp) => {
                    const compName = comp.product_name || comp.name || comp.inventory?.name || '';
                    const compSku = comp.sku || comp.inventory?.sku || '';
                    const label = compSku ? `  - ${compSku}` : `  - ${compName}`;
                    doc.text(label, leftMargin, yPosition);
                    yPosition += 3;

                    // Seriales del componente
                    const compSerials = comp.serial_numbers || comp.serials || [];
                    compSerials.forEach((serial) => {
                        const serialNumber = typeof serial === 'string' ? serial : serial.serial_number;
                        doc.text(`S/N: ${serialNumber}`, leftMargin, yPosition);
                        yPosition += 3;
                    });
                });
            } else {
                // Números de serie para productos individuales (no bundle)
                const serials = item.serials || item.serial_numbers || [];
                if (serials.length > 0) {
                    doc.setFontSize(7);
                    doc.setFont('helvetica', 'normal');
                    doc.setTextColor(...darkGrayColor);

                    serials.forEach((serial) => {
                        const serialNumber = typeof serial === 'string' ? serial : serial.serial_number;
                        doc.text(`  S/N: ${serialNumber}`, leftMargin, yPosition);
                        yPosition += 3;
                    });
                }
            }

            yPosition += 2;
        });

        yPosition += 2;

        // Línea separadora
        doc.setLineWidth(0.3);
        doc.setDrawColor(...blackColor);
        doc.line(leftMargin, yPosition, rightMargin, yPosition);
        yPosition += 5;

        // ===== TOTALES =====
        doc.setFontSize(9);
        doc.setFont('helvetica', 'normal');
        doc.setTextColor(...darkGrayColor);

        // Subtotal
        doc.text('Subtotal:', leftMargin, yPosition);
        doc.text(`$${formatMoney(saleData.subtotal)}`, rightMargin, yPosition, { align: 'right' });
        yPosition += 5;

        // IVA
        doc.text('IVA:', leftMargin, yPosition);
        doc.text(`$${formatMoney(saleData.tax)}`, rightMargin, yPosition, { align: 'right' });
        yPosition += 5;

        // Descuento (si existe)
        if (saleData.discount_amount && parseFloat(saleData.discount_amount) > 0) {
            const discountPercent = saleData.discount_percentage || 0;
            const tierName = saleData.client_tier_name || 'Cliente';
            
            doc.text(`Descuento (${tierName} ${discountPercent}%):`, leftMargin, yPosition);
            doc.text(`-$${formatMoney(saleData.discount_amount)}`, rightMargin, yPosition, { align: 'right' });
            yPosition += 5;
            doc.setTextColor(...darkGrayColor); // Restaurar color
        }

        yPosition += 1;

        // Línea antes del total
        doc.setLineWidth(0.4);
        doc.line(leftMargin, yPosition, rightMargin, yPosition);
        yPosition += 5;

        // Total
        doc.setFontSize(12);
        doc.setFont('helvetica', 'bold');
        doc.setTextColor(...blackColor);
        doc.text('TOTAL:', leftMargin, yPosition);
        doc.text(`$${formatMoney(saleData.total)}`, rightMargin, yPosition, { align: 'right' });
        yPosition += 6;

        // Si es pago en efectivo, mostrar monto pagado y cambio
        if (saleData.payment_method === 'cash' || saleData.payment_method === 'efectivo') {
            if (saleData.cash_received) {
                doc.setFontSize(9);
                doc.setFont('helvetica', 'normal');
                doc.setTextColor(...darkGrayColor);
                
                doc.text('Pagó con:', leftMargin, yPosition);
                doc.text(`$${formatMoney(saleData.cash_received)}`, rightMargin, yPosition, { align: 'right' });
                yPosition += 5;
                
                if (saleData.change && parseFloat(saleData.change) > 0) {
                    doc.setFont('helvetica', 'bold');
                    doc.setTextColor(...blackColor);
                    doc.text('Cambio:', leftMargin, yPosition);
                    doc.text(`$${formatMoney(saleData.change)}`, rightMargin, yPosition, { align: 'right' });
                    yPosition += 5;
                }
            }
        }
        yPosition += 3;

        // Línea decorativa doble
        doc.setLineWidth(0.3);
        doc.setTextColor(...darkGrayColor);
        doc.line(leftMargin, yPosition, rightMargin, yPosition);
        yPosition += 0.5;
        doc.setLineWidth(0.2);
        doc.line(leftMargin, yPosition, rightMargin, yPosition);
        yPosition += 6;

        // ===== FOOTER =====
        doc.setFontSize(9);
        doc.setFont('helvetica', 'bold');
        doc.setTextColor(...blackColor);
        doc.text('¡Gracias por su compra!', centerX, yPosition, { align: 'center' });
        yPosition += 5;

        doc.setFontSize(8);
        doc.setFont('helvetica', 'normal');
        doc.setTextColor(...darkGrayColor);
        doc.text('Vuelva pronto', centerX, yPosition, { align: 'center' });
        yPosition += 6;

        // Información de impresión
        doc.setFontSize(7);
        const currentDate = new Date().toLocaleString('es-MX', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit'
        });
        doc.text(`Impreso: ${currentDate}`, centerX, yPosition, { align: 'center' });
        yPosition += 3;
        doc.text(`ID de venta: ${saleData.id || 'N/A'}`, centerX, yPosition, { align: 'center' });
        yPosition += 8;

        // ===== QR =====
        const invoiceNumber = saleData.invoice_number || saleData.id;
        const facturacionUrl = `${window.location.origin}/#/facturacion/${invoiceNumber}`;

        try {
            // Generar QR como data URL
            const qrDataUrl = await QRCode.toDataURL(facturacionUrl, {
                width: 150,
                margin: 1,
                color: {
                    dark: '#000000',
                    light: '#ffffff'
                }
            });

            // Línea separadora antes del QR
            doc.setDrawColor(...darkGrayColor);
            doc.setLineWidth(0.2);
            doc.line(leftMargin, yPosition, rightMargin, yPosition);
            yPosition += 5;

            // Texto invitación a facturar
            doc.setFontSize(8);
            doc.setFont('helvetica', 'bold');
            doc.setTextColor(...blackColor);
            doc.text('¿Necesitas factura?', centerX, yPosition, { align: 'center' });
            yPosition += 4;

            doc.setFontSize(7);
            doc.setFont('helvetica', 'normal');
            doc.setTextColor(...darkGrayColor);
            doc.text('Escanea el código QR para', centerX, yPosition, { align: 'center' });
            yPosition += 3;
            doc.text('enviar tus datos de facturación', centerX, yPosition, { align: 'center' });
            yPosition += 5;

            // Agregar imagen QR centrada
            const qrSize = 25;
            const qrX = centerX - (qrSize / 2);
            doc.addImage(qrDataUrl, 'PNG', qrX, yPosition, qrSize, qrSize);
            yPosition += qrSize + 3;

        } catch (error) {
            console.error('Error generando QR:', error);
        }

        // Guardar o retornar el PDF
        if (autoDownload) {
            const fileName = `ticket-${folio}.pdf`;
            doc.save(fileName);
        }

        // Imprimir automáticamente si se solicita
        if (autoPrint) {
            try {
                // Convertir PDF a base64 data URI
                const pdfBase64 = doc.output('datauristring');

                // Abrir diálogo de impresión del navegador
                await printService.printPDF(pdfBase64);

            } catch (error) {
                console.error('Error imprimiendo ticket:', error);
                window.Notify.warning('No se pudo abrir el diálogo de impresión. Usa el PDF descargado para imprimir.');
            }
        }

        return doc;
    },

    /**
     * Generar ticket de corte de caja
     * @param {Object} cashRegisterData - Datos del corte de caja
     * @param {Object} options - Opciones de configuración
     */
    async generateCashRegisterTicket(cashRegisterData, options = {}) {
        const {
            businessName = 'HIKVISION DISTRIBUIDOR',
            autoDownload = true
        } = options;

        // Detectar ubicación del usuario
        const location = await this.getUserLocation();

        const doc = new jsPDF({
            orientation: 'portrait',
            unit: 'mm',
            format: [80, 297]
        });

        let yPosition = 10;
        const leftMargin = 5;
        const rightMargin = 75;
        const centerX = 40;
        const lineHeight = 5;

        // Colores
        const blackColor = [0, 0, 0];
        const darkGrayColor = [80, 80, 80];

        // Header
        doc.setFontSize(14);
        doc.setFont('helvetica', 'bold');
        doc.setTextColor(...blackColor);
        doc.text(businessName, centerX, yPosition, { align: 'center' });
        yPosition += 6;

        doc.setFontSize(8);
        doc.setFont('helvetica', 'normal');
        doc.setTextColor(...darkGrayColor);
        doc.text(`${location.city}, ${location.state}, ${location.country}`, centerX, yPosition, { align: 'center' });
        yPosition += 4;
        doc.text(location.phone, centerX, yPosition, { align: 'center' });
        yPosition += 6;

        // Línea
        doc.setDrawColor(...darkGrayColor);
        doc.setLineWidth(0.3);
        doc.line(leftMargin, yPosition, rightMargin, yPosition);
        yPosition += 5;

        // Título
        doc.setFontSize(12);
        doc.setFont('helvetica', 'bold');
        doc.setTextColor(...blackColor);
        doc.text('CORTE DE CAJA', centerX, yPosition, { align: 'center' });
        yPosition += 7;

        // Información
        doc.setFontSize(8);
        doc.setFont('helvetica', 'normal');
        doc.setTextColor(...darkGrayColor);

        const closeDate = new Date(cashRegisterData.closed_at || Date.now());
        doc.text(`Fecha: ${closeDate.toLocaleDateString('es-MX')}`, leftMargin, yPosition);
        yPosition += 4;
        doc.text(`Hora: ${closeDate.toLocaleTimeString('es-MX', { hour: '2-digit', minute: '2-digit' })}`, leftMargin, yPosition);
        yPosition += 4;
        doc.text(`Cajero: ${cashRegisterData.user?.name || 'N/A'}`, leftMargin, yPosition);
        yPosition += 6;

        // Línea
        doc.line(leftMargin, yPosition, rightMargin, yPosition);
        yPosition += 5;

        // Detalle
        doc.setFont('helvetica', 'normal');
        doc.setTextColor(...blackColor);

        doc.text('Efectivo Inicial:', leftMargin, yPosition);
        doc.text(`$${formatMoney(cashRegisterData.initial_cash)}`, rightMargin, yPosition, { align: 'right' });
        yPosition += 5;

        doc.text('Ventas Totales:', leftMargin, yPosition);
        doc.text(`$${formatMoney(cashRegisterData.total_sales)}`, rightMargin, yPosition, { align: 'right' });
        yPosition += 5;

        doc.text('Efectivo Final:', leftMargin, yPosition);
        doc.text(`$${formatMoney(cashRegisterData.final_cash)}`, rightMargin, yPosition, { align: 'right' });
        yPosition += 6;

        // Total
        doc.setFont('helvetica', 'bold');
        doc.text('Diferencia:', leftMargin, yPosition);
        const difference = parseFloat(cashRegisterData.final_cash || 0) -
                          (parseFloat(cashRegisterData.initial_cash || 0) + parseFloat(cashRegisterData.cash_sales || 0));
        doc.text(`$${formatMoney(difference)}`, rightMargin, yPosition, { align: 'right' });
        yPosition += 8;

        // Footer
        doc.setFontSize(9);
        doc.setFont('helvetica', 'bold');
        doc.text('Cierre de turno', centerX, yPosition, { align: 'center' });

        if (autoDownload) {
            doc.save(`corte-caja-${cashRegisterData.id}.pdf`);
            return doc;
        } else {
            return doc;
        }
    }
};

export default ticketService;
