'use strict';

(function () {
    const form = document.getElementById('posForm');
    if (!form) {
        return;
    }

    const posEnabled = String(form.dataset.enabled || '0') === '1';

    const customerInput = document.getElementById('cliente_id');
    const customerInfo = document.getElementById('cliente_info');
    const saleTypeInput = document.getElementById('tipo_venta');
    const paymentMethodInput = document.getElementById('metodo_pago');
    const paymentReferenceContainer = document.getElementById('paymentReferenceContainer');
    const paymentReferenceInput = document.getElementById('referencia_pago');
    const dataphonePaymentCodes = new Set([
        'bold',
        'bold_dataphone',
        'bold_button',
        'credibanco',
        'credibanco_dataphone',
        'credibanco_datafono',
    ]);

    const globalDiscountInput = document.getElementById('descuento');
    const globalDiscountDisplayInput = document.getElementById('descuento_display');
    const globalDiscountModeInput = document.getElementById('descuento_modo');
    const globalDiscountModeSelector = document.getElementById('descuento_modo_selector');

    const abonoContainer = document.getElementById('abonoContainer');
    const abonoInput = document.getElementById('abono_inicial');
    const creditNotice = document.getElementById('creditNotice');

    const productGrid = document.getElementById('productGrid');
    const productCards = Array.from(document.querySelectorAll('.vx-pos-product-card'));
    const productSearchInput = document.getElementById('productSearchInput');
    const clearProductSearchButton = document.getElementById('clearProductSearch');
    const categoryTabs = document.getElementById('categoryTabs');
    const noProductResults = document.getElementById('noProductResults');

    const checkoutList = document.getElementById('checkoutList');
    const checkoutEmpty = document.getElementById('checkoutEmpty');
    const checkoutSubtotal = document.getElementById('checkoutSubtotal');
    const checkoutDiscountDisplay = document.getElementById('checkoutDiscountDisplay');
    const checkoutTaxes = document.getElementById('checkoutTaxes');
    const checkoutTotal = document.getElementById('checkoutTotal');
    const cartItemsCount = document.getElementById('cartItemsCount');
    const cashAmountContainer = document.getElementById('cashAmountContainer');
    const cashAmountInput = document.getElementById('pago_cliente');
    const cashChangeRow = document.getElementById('cashChangeRow');
    const cashChangeAmount = document.getElementById('cashChangeAmount');
    const clearCartButton = document.getElementById('clearCart');
    const checkoutSubmit = document.getElementById('checkoutSubmit');
    const hiddenContainer = document.getElementById('cartHiddenContainer');

    const customerModal = document.getElementById('posCustomerModal');
    const customerForm = document.getElementById('posCustomerForm');
    const variantModalElement = document.getElementById('posVariantModal');
    const variantModalProductName = document.getElementById('posVariantProductName');
    const variantModalHelper = document.getElementById('posVariantHelper');
    const variantAttributesContainer = document.getElementById('posVariantAttributesContainer');
    const variantPriceDisplay = document.getElementById('posVariantPriceDisplay');
    const variantQtyInput = document.getElementById('posVariantQtyInput');
    const variantStockBadge = document.getElementById('posVariantStockBadge');
    const variantAddButton = document.getElementById('posVariantAddButton');

    if (!checkoutList || !checkoutSubtotal || !checkoutTotal || !hiddenContainer) {
        return;
    }

    const cart = new Map();
    const productCatalog = new Map();
    let activeCategory = 'all';
    let customerSelectInstance = null;
    let variantModalInstance = null;
    let variantSelectionState = null;

    const currencyFormatter = new Intl.NumberFormat('es-CO', {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
    });

    const discountFormatter = new Intl.NumberFormat('es-CO', {
        minimumFractionDigits: 0,
        maximumFractionDigits: 2,
    });

    const formatMoney = (value) => {
        const numeric = Number(value);
        if (!Number.isFinite(numeric)) {
            return '$0.00';
        }

        return '$' + currencyFormatter.format(numeric);
    };

    const showMessage = (icon, title, text) => {
        const palette = {
            success: 'success',
            error: 'error',
            warning: 'warning',
            info: 'info',
        };
        const type = palette[String(icon || '').toLowerCase()] || 'info';

        if (window.sileo && typeof window.sileo[type] === 'function') {
            window.sileo[type]({
                title: String(title || ''),
                description: String(text || ''),
                position: 'top-center',
            });
            return;
        }

        window.alert(text || title);
    };

    const parsePositiveNumber = (value) => {
        const numeric = Number(value);
        if (!Number.isFinite(numeric) || numeric < 0) {
            return 0;
        }
        return numeric;
    };

    const parseIntegerQty = (value) => {
        const numeric = Number(value);
        if (!Number.isFinite(numeric) || numeric <= 0) {
            return 1;
        }
        return Math.max(1, Math.floor(numeric));
    };

    const normalizeText = (value) => String(value || '').toLowerCase().trim();
    const normalizeKey = (value) => normalizeText(value);
    const escapeHtml = (value) => {
        return String(value ?? '')
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
    };
    const escapeSelectorValue = (value) => {
        const raw = String(value ?? '');
        if (window.CSS && typeof window.CSS.escape === 'function') {
            return window.CSS.escape(raw);
        }

        return raw.replace(/([ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, '\\$1');
    };

    const parseVariantDefinition = (name) => {
        const parts = String(name || '')
            .split(/\s*\/\s*/)
            .map((part) => part.trim())
            .filter((part) => part !== '');
        const attributes = [];

        parts.forEach((part, index) => {
            if (part.includes(':')) {
                const segments = part.split(':');
                const label = String(segments.shift() || '').trim();
                const value = String(segments.join(':') || '').trim();
                if (label !== '' && value !== '') {
                    attributes.push({label, value});
                    return;
                }
            }

            attributes.push({
                label: `Opción ${index + 1}`,
                value: part,
            });
        });

        return attributes;
    };

    const parseProductVariants = (rawValue) => {
        let variants = [];
        try {
            const parsed = JSON.parse(String(rawValue || '[]'));
            variants = Array.isArray(parsed) ? parsed : [];
        } catch (error) {
            variants = [];
        }

        const labelOrder = [];
        const labelValuesMap = new Map();
        const parsedVariants = [];

        variants.forEach((variant) => {
            const variantId = Number(variant && variant.id ? variant.id : 0);
            const variantName = String(variant && variant.nombre ? variant.nombre : '').trim();
            if (!Number.isFinite(variantId) || variantId <= 0 || variantName === '') {
                return;
            }

            const pairs = parseVariantDefinition(variantName);
            if (pairs.length === 0) {
                return;
            }

            const keyParts = [];
            const valuesByLabel = {};

            pairs.forEach((pair) => {
                const label = String(pair.label || '').trim();
                const value = String(pair.value || '').trim();
                if (label === '' || value === '') {
                    return;
                }

                const labelKey = normalizeKey(label);
                if (!labelValuesMap.has(labelKey)) {
                    labelOrder.push({key: labelKey, label});
                    labelValuesMap.set(labelKey, new Set());
                }

                labelValuesMap.get(labelKey).add(value);
                valuesByLabel[labelKey] = value;
                keyParts.push(`${labelKey}=${normalizeKey(value)}`);
            });

            const hasStock = variant && variant.cantidad !== undefined && variant.cantidad !== null && variant.cantidad !== '';
            const variantStock = hasStock ? Number(variant.cantidad) : null;
            const variantPrice = Number(variant && variant.precio_venta !== undefined ? variant.precio_venta : 0);

            parsedVariants.push({
                id: variantId,
                name: variantName,
                key: keyParts.join('|'),
                valuesByLabel,
                stock: Number.isFinite(variantStock) ? Math.max(0, Math.floor(variantStock)) : null,
                price: Number.isFinite(variantPrice) ? Math.max(0, variantPrice) : 0,
            });
        });

        const attributes = labelOrder.map((entry) => ({
            key: entry.key,
            label: entry.label,
            values: Array.from(labelValuesMap.get(entry.key) || [])
                .sort((a, b) => String(a).localeCompare(String(b), 'es', {sensitivity: 'base'})),
        }));

        return {
            attributes,
            variants: parsedVariants,
        };
    };

    const parseAmountInput = (rawValue) => {
        let raw = String(rawValue || '').trim();
        if (raw === '') {
            return 0;
        }

        raw = raw.replace(/\s+/g, '').replace(/[^0-9.,]/g, '');
        if (raw === '') {
            return 0;
        }

        const lastComma = raw.lastIndexOf(',');
        const lastDot = raw.lastIndexOf('.');
        const lastSeparator = Math.max(lastComma, lastDot);

        if (lastSeparator >= 0) {
            const digitsAfter = raw.length - lastSeparator - 1;
            const separator = raw[lastSeparator];
            const treatAsDecimal = digitsAfter > 0 && digitsAfter <= 2;

            if (treatAsDecimal) {
                const integerPart = raw.slice(0, lastSeparator).replace(/[.,]/g, '');
                const decimalPart = raw.slice(lastSeparator + 1).replace(/[.,]/g, '');
                raw = integerPart + '.' + decimalPart;
            } else if (separator === '.' || separator === ',') {
                raw = raw.replace(/[.,]/g, '');
            }
        } else {
            raw = raw.replace(/[.,]/g, '');
        }

        const parsed = Number(raw);
        if (!Number.isFinite(parsed) || parsed < 0) {
            return 0;
        }

        return parsed;
    };

    const formatAmountInput = (value) => {
        const numeric = parsePositiveNumber(value);
        if (numeric <= 0) {
            return '0';
        }

        return discountFormatter.format(numeric);
    };

    const discountAmount = (baseAmount, discountValue, discountType) => {
        const base = parsePositiveNumber(baseAmount);
        let discount = parsePositiveNumber(discountValue);
        const type = String(discountType || 'valor').toLowerCase();

        if (base <= 0 || discount <= 0) {
            return 0;
        }

        if (type === 'porcentaje') {
            discount = Math.min(100, discount);
            return Number((base * (discount / 100)).toFixed(2));
        }

        return Number(Math.min(base, discount).toFixed(2));
    };

    const getGlobalDiscountMode = () => {
        const mode = String(globalDiscountModeInput?.value || globalDiscountModeSelector?.value || 'valor').toLowerCase();
        return mode === 'porcentaje' ? 'porcentaje' : 'valor';
    };

    const syncGlobalDiscountFromDisplay = (normalizeDisplay) => {
        if (!globalDiscountInput) {
            return 0;
        }

        let numeric = parsePositiveNumber(globalDiscountInput.value || 0);
        if (globalDiscountDisplayInput) {
            numeric = parseAmountInput(globalDiscountDisplayInput.value);
            globalDiscountInput.value = numeric.toFixed(2);

            if (normalizeDisplay) {
                globalDiscountDisplayInput.value = formatAmountInput(numeric);
            }
        }

        return numeric;
    };

    const calcLine = (item) => {
        const qty = parseIntegerQty(item.qty);
        const price = parsePositiveNumber(item.price);
        const base = qty * price;
        const lineDiscount = discountAmount(base, item.lineDiscountValue, item.lineDiscountType);
        const taxableBase = Math.max(0, base - lineDiscount);
        const taxRate = Math.max(0, Math.min(100, parsePositiveNumber(item.taxRate)));
        const lineTax = Number((taxableBase * (taxRate / 100)).toFixed(2));
        const lineTotal = Number((taxableBase + lineTax).toFixed(2));

        return {
            qty,
            price,
            base,
            lineDiscount,
            taxableBase,
            lineTax,
            lineTotal,
        };
    };

    const getCartTotals = () => {
        let subtotal = 0;
        let lineDiscountTotal = 0;
        let taxes = 0;
        let units = 0;

        cart.forEach((item) => {
            const line = calcLine(item);
            subtotal += line.base;
            lineDiscountTotal += line.lineDiscount;
            taxes += line.lineTax;
            units += line.qty;
        });

        const baseAfterLineDiscount = Math.max(0, subtotal - lineDiscountTotal);
        const globalDiscountValue = parsePositiveNumber(globalDiscountInput?.value || 0);
        const globalDiscountMode = getGlobalDiscountMode();
        const globalDiscount = discountAmount(baseAfterLineDiscount, globalDiscountValue, globalDiscountMode);
        const discount = lineDiscountTotal + globalDiscount;
        const total = Math.max(0, Number((baseAfterLineDiscount - globalDiscount + taxes).toFixed(2)));

        return {
            subtotal: Number(subtotal.toFixed(2)),
            lineDiscountTotal: Number(lineDiscountTotal.toFixed(2)),
            globalDiscount: Number(globalDiscount.toFixed(2)),
            discount: Number(discount.toFixed(2)),
            taxes: Number(taxes.toFixed(2)),
            total,
            units,
        };
    };

    const rebuildHiddenInputs = () => {
        hiddenContainer.innerHTML = '';

        cart.forEach((item) => {
            const line = calcLine(item);

            const productInput = document.createElement('input');
            productInput.type = 'hidden';
            productInput.name = 'producto_id[]';
            productInput.value = item.id;

            const variantIdInput = document.createElement('input');
            variantIdInput.type = 'hidden';
            variantIdInput.name = 'variante_id[]';
            variantIdInput.value = item.variantId ? String(item.variantId) : '';

            const variantNameInput = document.createElement('input');
            variantNameInput.type = 'hidden';
            variantNameInput.name = 'variante_nombre[]';
            variantNameInput.value = item.variantName || '';

            const qtyInput = document.createElement('input');
            qtyInput.type = 'hidden';
            qtyInput.name = 'cantidad[]';
            qtyInput.value = String(line.qty);

            const priceInput = document.createElement('input');
            priceInput.type = 'hidden';
            priceInput.name = 'precio_unitario[]';
            priceInput.value = String(line.price.toFixed(2));

            const lineDiscountInput = document.createElement('input');
            lineDiscountInput.type = 'hidden';
            lineDiscountInput.name = 'descuento_linea[]';
            lineDiscountInput.value = String(parsePositiveNumber(item.lineDiscountValue).toFixed(2));

            const lineDiscountTypeInput = document.createElement('input');
            lineDiscountTypeInput.type = 'hidden';
            lineDiscountTypeInput.name = 'descuento_linea_tipo[]';
            lineDiscountTypeInput.value = String(item.lineDiscountType || 'valor');

            hiddenContainer.appendChild(productInput);
            hiddenContainer.appendChild(variantIdInput);
            hiddenContainer.appendChild(variantNameInput);
            hiddenContainer.appendChild(qtyInput);
            hiddenContainer.appendChild(priceInput);
            hiddenContainer.appendChild(lineDiscountInput);
            hiddenContainer.appendChild(lineDiscountTypeInput);
        });
    };

    const syncCheckoutSummary = () => {
        const totals = getCartTotals();
        checkoutSubtotal.textContent = formatMoney(totals.subtotal);
        checkoutDiscountDisplay.textContent = formatMoney(totals.discount);
        if (checkoutTaxes) {
            checkoutTaxes.textContent = formatMoney(totals.taxes);
        }
        checkoutTotal.textContent = formatMoney(totals.total);
        syncCashChange();

        if (cartItemsCount) {
            cartItemsCount.textContent = totals.units + ' item' + (totals.units === 1 ? '' : 's');
        }

        if (abonoInput) {
            abonoInput.max = String(totals.total.toFixed(2));
            const abonoNumeric = parsePositiveNumber(abonoInput.value || 0);
            if (abonoNumeric > totals.total) {
                abonoInput.value = totals.total.toFixed(2);
            }
        }

        rebuildHiddenInputs();
        return totals;
    };

    const renderCart = () => {
        checkoutList.innerHTML = '';

        syncCheckoutSummary();

        if (cart.size === 0) {
            checkoutEmpty?.classList.remove('d-none');
            checkoutList.classList.add('d-none');
            return;
        }

        checkoutEmpty?.classList.add('d-none');
        checkoutList.classList.remove('d-none');

        cart.forEach((item) => {
            const line = calcLine(item);
            const lineDiscountValueText = formatAmountInput(item.lineDiscountValue || 0);

            const row = document.createElement('div');
            row.className = 'vx-pos-checkout-item';
            row.dataset.itemKey = item.key;
            const variantLabel = String(item.variantName || '').trim();
            row.innerHTML = `
                <div class="vx-pos-checkout-main">
                    <strong class="vx-pos-checkout-name">${escapeHtml(item.name)}</strong>
                    <small class="text-muted">
                        ${variantLabel !== '' ? `Variante: ${escapeHtml(variantLabel)} · ` : ''}
                        Stock ${item.stock} · ${formatMoney(item.price)} c/u · IVA ${Number(item.taxRate || 0).toFixed(2)}%
                    </small>
                </div>
                <div class="vx-pos-checkout-actions">
                    <button type="button" class="btn btn-sm btn-outline-secondary vx-qty-btn" data-action="minus" aria-label="Restar cantidad">-</button>
                    <input type="number" class="form-control form-control-sm vx-qty-input" min="1" step="1" inputmode="numeric" value="${line.qty}" aria-label="Cantidad">
                    <button type="button" class="btn btn-sm btn-outline-secondary vx-qty-btn" data-action="plus" aria-label="Sumar cantidad">+</button>
                    <span class="vx-pos-checkout-line-total">${formatMoney(line.lineTotal)}</span>
                    <button type="button" class="btn btn-sm btn-outline-danger" data-action="remove" aria-label="Quitar producto">
                        <i class="bx bx-trash"></i>
                    </button>
                </div>
                <div class="vx-pos-line-discount mt-2">
                    <small class="text-muted">Descuento línea</small>
                    <div class="input-group input-group-sm">
                        <select class="form-select vx-line-discount-type" aria-label="Tipo descuento línea">
                            <option value="valor" ${item.lineDiscountType === 'valor' ? 'selected' : ''}>$</option>
                            <option value="porcentaje" ${item.lineDiscountType === 'porcentaje' ? 'selected' : ''}>%</option>
                        </select>
                        <input type="text" class="form-control vx-line-discount-input" value="${lineDiscountValueText}" inputmode="decimal" aria-label="Valor descuento línea">
                    </div>
                </div>
            `;

            checkoutList.appendChild(row);
        });

    };

    const syncSaleTypeUI = () => {
        if (!saleTypeInput) {
            return;
        }

        const isCredit = saleTypeInput.value === 'credito';
        abonoContainer?.classList.toggle('d-none', !isCredit);
        creditNotice?.classList.toggle('d-none', !isCredit);

        if (!isCredit && abonoInput) {
            abonoInput.value = '0';
        }
    };

    const syncPaymentReferenceUI = () => {
        if (!paymentReferenceContainer || !paymentReferenceInput) {
            return;
        }

        const requiresReference = dataphonePaymentCodes.has(String(paymentMethodInput?.value || '').toLowerCase());
        paymentReferenceContainer.classList.toggle('d-none', !requiresReference);
        paymentReferenceInput.required = requiresReference;
        paymentReferenceInput.disabled = !requiresReference;

        if (!requiresReference) {
            paymentReferenceInput.value = '';
        }
    };

    const syncCashUI = () => {
        const isCash = String(paymentMethodInput?.value || '').toLowerCase() === 'efectivo';
        if (cashAmountContainer) {
            cashAmountContainer.classList.toggle('d-none', !isCash);
            if (cashAmountInput) {
                cashAmountInput.disabled = !isCash;
                if (!isCash) {
                    cashAmountInput.value = '';
                }
            }
        }
        syncCashChange();
    };

    const syncCashChange = () => {
        if (!cashChangeRow || !cashChangeAmount) {
            return;
        }
        const isCash = String(paymentMethodInput?.value || '').toLowerCase() === 'efectivo';
        if (!isCash) {
            cashChangeRow.classList.add('d-none');
            return;
        }
        const paid = parsePositiveNumber(cashAmountInput?.value || 0);
        const totals = getCartTotals();
        if (paid <= 0 || totals.total <= 0) {
            cashChangeRow.classList.add('d-none');
            return;
        }
        const change = Math.max(0, paid - totals.total);
        cashChangeAmount.textContent = formatMoney(change);
        cashChangeRow.classList.toggle('d-none', change <= 0 && paid < totals.total);
        // Mostrar aunque el cambio sea 0 (pago exacto)
        if (paid >= totals.total) {
            cashChangeRow.classList.remove('d-none');
        }
    };

    const syncCustomerInfo = () => {
        if (!customerInput || !customerInfo) {
            return;
        }

        const selected = customerInput.options[customerInput.selectedIndex];
        if (!selected || String(customerInput.value || '') === '') {
            customerInfo.textContent = 'Consumidor final.';
            return;
        }

        const name = String(selected.getAttribute('data-nombre') || selected.textContent || '').trim();
        const document = String(selected.getAttribute('data-documento-visible') || '').trim();
        const phone = String(selected.getAttribute('data-telefono') || '').trim();
        const email = String(selected.getAttribute('data-email') || '').trim();

        const parts = [];
        if (name !== '') {
            parts.push(name);
        }
        if (document !== '') {
            parts.push('Cédula: ' + document);
        }
        if (phone !== '') {
            parts.push('Tel: ' + phone);
        }
        if (email !== '') {
            parts.push(email);
        }

        customerInfo.textContent = parts.length > 0 ? parts.join(' | ') : 'Cliente seleccionado.';
    };

    const initCustomerSearch = () => {
        if (!customerInput || customerInput.disabled || typeof window.TomSelect === 'undefined' || customerInput.tomselect) {
            return;
        }

        customerSelectInstance = new window.TomSelect(customerInput, {
            create: false,
            allowEmptyOption: true,
            maxOptions: 500,
            searchField: ['text'],
            placeholder: 'Buscar por nombre o cédula...',
            render: {
                no_results: () => '<div class="no-results">Sin resultados</div>',
            },
            onChange: () => syncCustomerInfo(),
        });
    };

    const buildProductCatalog = () => {
        productCards.forEach((card) => {
            const id = String(card.dataset.productId || '').trim();
            if (id === '') {
                return;
            }

            const stockRaw = Number(card.dataset.stock || 0);
            const stock = Number.isFinite(stockRaw) ? Math.max(0, Math.floor(stockRaw)) : 0;
            const priceRaw = Number(card.dataset.price || 0);
            const price = Number.isFinite(priceRaw) ? Math.max(0, priceRaw) : 0;
            const taxRaw = Number(card.dataset.taxRate || 0);
            const taxRate = Number.isFinite(taxRaw) ? Math.max(0, taxRaw) : 0;
            const hasVariants = String(card.dataset.hasVariants || '0') === '1';
            const parsedVariants = hasVariants ? parseProductVariants(card.dataset.variants || '[]') : {attributes: [], variants: []};

            productCatalog.set(id, {
                id,
                name: String(card.dataset.name || 'Producto').trim(),
                price,
                stock,
                taxRate,
                category: String(card.dataset.category || '').trim(),
                hasVariants: hasVariants && parsedVariants.variants.length > 0,
                variantAttributes: parsedVariants.attributes,
                variants: parsedVariants.variants,
            });
        });
    };

    const updateItemQty = (itemKey, qty, notifyIfLimited) => {
        const key = String(itemKey || '');
        if (!cart.has(key)) {
            return;
        }

        const item = cart.get(key);
        let nextQty = parseIntegerQty(qty);

        if (nextQty > item.stock) {
            nextQty = item.stock;
            if (notifyIfLimited) {
                showMessage('warning', 'Stock límite', 'No puedes superar el stock disponible para este producto.');
            }
        }

        if (nextQty <= 0) {
            cart.delete(key);
        } else {
            cart.set(key, {
                ...item,
                qty: nextQty,
            });
        }

        renderCart();
    };

    const closeVariantModal = () => {
        if (!variantModalElement || typeof bootstrap === 'undefined') {
            return;
        }
        const modal = variantModalInstance || bootstrap.Modal.getOrCreateInstance(variantModalElement);
        modal.hide();
    };

    const addItemToCart = (product, options = {}) => {
        const variantId = Number(options.variantId || 0);
        const variantName = String(options.variantName || '').trim();
        const variantPrice = Number(options.price || 0);
        const rawVariantStock = options.stock;
        const hasVariantStock = rawVariantStock !== null
            && rawVariantStock !== undefined
            && rawVariantStock !== ''
            && Number.isFinite(Number(rawVariantStock));
        const variantStockValue = hasVariantStock ? Math.max(0, Math.floor(Number(rawVariantStock))) : null;
        const requestedQty = parseIntegerQty(options.qty || 1);
        const stockLimit = variantStockValue !== null ? Math.min(product.stock, variantStockValue) : product.stock;

        if (stockLimit <= 0) {
            showMessage('warning', 'Sin stock', 'Esta variación no tiene stock disponible.');
            return;
        }

        const itemKey = variantId > 0
            ? `${product.id}::v${variantId}`
            : (variantName !== '' ? `${product.id}::${normalizeKey(variantName)}` : product.id);
        const existing = cart.get(itemKey);
        const currentQty = existing ? parseIntegerQty(existing.qty) : 0;
        const nextQty = Math.min(stockLimit, currentQty + requestedQty);

        if (nextQty <= currentQty) {
            showMessage('warning', 'Stock límite', 'Ya alcanzaste el stock máximo de este item.');
            return;
        }

        cart.set(itemKey, {
            key: itemKey,
            id: product.id,
            name: product.name,
            price: variantPrice > 0 ? variantPrice : product.price,
            stock: stockLimit,
            taxRate: product.taxRate,
            variantId: variantId > 0 ? variantId : null,
            variantName: variantName,
            qty: nextQty,
            lineDiscountType: existing ? existing.lineDiscountType : 'valor',
            lineDiscountValue: existing ? existing.lineDiscountValue : 0,
        });

        renderCart();
    };

    const updateVariantOptionAvailability = () => {
        if (!variantSelectionState || !variantSelectionState.product || !variantAttributesContainer) {
            return;
        }

        const product = variantSelectionState.product;
        const attributes = Array.isArray(product.variantAttributes) ? product.variantAttributes : [];
        const variants = Array.isArray(product.variants) ? product.variants : [];
        const selects = Array.from(variantAttributesContainer.querySelectorAll('select[data-attr-key]'));

        const currentSelection = {};
        selects.forEach((select) => {
            const key = String(select.dataset.attrKey || '').trim();
            if (key === '') {
                return;
            }
            currentSelection[key] = String(select.value || '').trim();
        });

        selects.forEach((select) => {
            const attributeKey = String(select.dataset.attrKey || '').trim();
            if (attributeKey === '') {
                return;
            }

            const allowedValues = new Set();
            variants.forEach((variant) => {
                const matchesOthers = attributes.every((attribute) => {
                    if (attribute.key === attributeKey) {
                        return true;
                    }

                    const selectedValue = normalizeText(currentSelection[attribute.key] || '');
                    if (selectedValue === '') {
                        return true;
                    }

                    const variantValue = normalizeText(variant.valuesByLabel[attribute.key] || '');
                    return variantValue === selectedValue;
                });

                if (!matchesOthers) {
                    return;
                }

                const optionValue = normalizeText(variant.valuesByLabel[attributeKey] || '');
                if (optionValue !== '') {
                    allowedValues.add(optionValue);
                }
            });

            const currentValue = String(select.value || '').trim();
            let currentStillValid = currentValue === '';

            Array.from(select.options).forEach((option, index) => {
                if (index === 0) {
                    option.disabled = false;
                    return;
                }

                const normalizedOption = normalizeText(option.value);
                const enabled = allowedValues.has(normalizedOption);
                option.disabled = !enabled;

                if (enabled && normalizeText(currentValue) === normalizedOption) {
                    currentStillValid = true;
                }
            });

            if (!currentStillValid) {
                select.value = '';
            }
        });
    };

    const getSelectedVariantByAttributes = () => {
        if (!variantSelectionState || !variantSelectionState.product) {
            return null;
        }

        const product = variantSelectionState.product;
        const attributes = Array.isArray(product.variantAttributes) ? product.variantAttributes : [];
        const selection = {};

        for (const attribute of attributes) {
            const select = variantAttributesContainer?.querySelector(
                `select[data-attr-key="${escapeSelectorValue(attribute.key)}"]`
            );
            const value = String(select?.value || '').trim();
            if (value === '') {
                return null;
            }
            selection[attribute.key] = value;
        }

        const selected = product.variants.find((variant) => {
            return attributes.every((attribute) => {
                const expected = normalizeText(selection[attribute.key]);
                const actual = normalizeText(variant.valuesByLabel[attribute.key] || '');
                return expected !== '' && expected === actual;
            });
        });

        return selected || null;
    };

    const refreshVariantModalState = () => {
        if (!variantSelectionState || !variantSelectionState.product) {
            return;
        }

        updateVariantOptionAvailability();

        const selectedVariant = getSelectedVariantByAttributes();
        const selectedQty = parseIntegerQty(variantQtyInput?.value || 1);
        const product = variantSelectionState.product;

        if (!selectedVariant) {
            if (variantSelectionState) {
                variantSelectionState.lastVariantId = null;
            }
            if (variantModalHelper) {
                variantModalHelper.textContent = 'Selecciona todos los atributos para habilitar esta variación.';
            }
            if (variantPriceDisplay) {
                variantPriceDisplay.value = formatMoney(product.price);
            }
            if (variantStockBadge) {
                variantStockBadge.textContent = 'Stock: --';
                variantStockBadge.className = 'badge text-bg-light border';
            }
            if (variantAddButton) {
                variantAddButton.disabled = true;
            }
            return;
        }

        const hasVariantStock = selectedVariant.stock !== null && Number.isFinite(Number(selectedVariant.stock));
        const availableStock = hasVariantStock
            ? Math.min(product.stock, Math.max(0, Math.floor(Number(selectedVariant.stock))))
            : product.stock;

        // Evita arrastrar cantidad alta de otra variación por accidente.
        if (variantSelectionState?.lastVariantId !== selectedVariant.id && variantQtyInput) {
            variantQtyInput.value = '1';
        }
        if (variantSelectionState) {
            variantSelectionState.lastVariantId = selectedVariant.id;
        }

        if (variantPriceDisplay) {
            variantPriceDisplay.value = formatMoney(selectedVariant.price > 0 ? selectedVariant.price : product.price);
        }

        if (variantStockBadge) {
            variantStockBadge.textContent = `Stock: ${availableStock}`;
            variantStockBadge.className = `badge border ${availableStock > 0 ? 'text-bg-success' : 'text-bg-danger'}`;
        }

        if (variantQtyInput) {
            variantQtyInput.max = String(Math.max(1, availableStock));
            if (selectedQty > availableStock && availableStock > 0) {
                variantQtyInput.value = String(availableStock);
            }
        }

        if (variantModalHelper) {
            variantModalHelper.textContent = availableStock > 0
                ? `Variación seleccionada: ${selectedVariant.name}`
                : 'Esta variación está sin stock.';
        }
        if (variantAddButton) {
            variantAddButton.disabled = availableStock <= 0;
        }
    };

    const openVariantModal = (product) => {
        if (!variantModalElement || !variantAttributesContainer || !variantAddButton || typeof bootstrap === 'undefined') {
            showMessage('warning', 'Variaciones', 'No fue posible abrir el selector de variaciones.');
            return;
        }

        const attributes = Array.isArray(product.variantAttributes) ? product.variantAttributes : [];
        const variants = Array.isArray(product.variants) ? product.variants : [];
        if (attributes.length === 0 || variants.length === 0) {
            showMessage('warning', 'Variaciones', 'Este producto no tiene variaciones configuradas correctamente.');
            return;
        }

        variantSelectionState = {
            product,
            lastVariantId: null,
        };
        variantModalProductName && (variantModalProductName.textContent = product.name);
        variantAttributesContainer.innerHTML = '';

        attributes.forEach((attribute) => {
            const wrapper = document.createElement('div');
            wrapper.className = attributes.length >= 3 ? 'col-md-4' : 'col-md-6';
            const label = document.createElement('label');
            label.className = 'form-label';
            label.textContent = String(attribute.label || 'Atributo');

            const select = document.createElement('select');
            select.className = 'form-select';
            select.dataset.attrKey = String(attribute.key || '');

            const emptyOption = document.createElement('option');
            emptyOption.value = '';
            emptyOption.textContent = 'Seleccionar...';
            select.appendChild(emptyOption);

            attribute.values.forEach((value) => {
                const option = document.createElement('option');
                option.value = String(value);
                option.textContent = String(value);
                select.appendChild(option);
            });

            wrapper.appendChild(label);
            wrapper.appendChild(select);
            variantAttributesContainer.appendChild(wrapper);
        });

        if (variantQtyInput) {
            variantQtyInput.value = '1';
        }
        variantAttributesContainer.querySelectorAll('select').forEach((select) => {
            select.addEventListener('change', () => {
                refreshVariantModalState();
            });
        });

        variantAddButton.onclick = () => {
            const selectedVariant = getSelectedVariantByAttributes();
            if (!selectedVariant) {
                showMessage('warning', 'Variación', 'Selecciona todos los atributos para continuar.');
                return;
            }

            const hasVariantStock = selectedVariant.stock !== null && Number.isFinite(Number(selectedVariant.stock));
            const availableStock = hasVariantStock
                ? Math.min(product.stock, Math.max(0, Math.floor(Number(selectedVariant.stock))))
                : product.stock;
            if (availableStock <= 0) {
                showMessage('warning', 'Sin stock', 'Esta variación está agotada.');
                return;
            }

            const qty = parseIntegerQty(variantQtyInput?.value || 1);
            addItemToCart(product, {
                variantId: selectedVariant.id,
                variantName: selectedVariant.name,
                price: selectedVariant.price > 0 ? selectedVariant.price : product.price,
                stock: availableStock,
                qty,
            });

            closeVariantModal();
        };

        variantModalInstance = bootstrap.Modal.getOrCreateInstance(variantModalElement);
        variantModalInstance.show();
        refreshVariantModalState();
    };

    const addProductToCart = (productId) => {
        if (!posEnabled) {
            return;
        }

        const id = String(productId || '').trim();
        if (id === '' || !productCatalog.has(id)) {
            return;
        }

        const product = productCatalog.get(id);
        if (product.stock <= 0) {
            showMessage('warning', 'Sin stock', 'Este producto no tiene stock disponible.');
            return;
        }

        if (product.hasVariants) {
            openVariantModal(product);
            return;
        }

        addItemToCart(product, {
            qty: 1,
            price: product.price,
            stock: product.stock,
        });
    };

    const clearCart = () => {
        cart.clear();
        renderCart();
    };

    const applyProductFilters = () => {
        const term = normalizeText(productSearchInput?.value || '');
        let visibleCount = 0;

        productCards.forEach((card) => {
            const matchesCategory = activeCategory === 'all' || String(card.dataset.category || '') === activeCategory;
            const searchIndex = normalizeText(card.dataset.search || '');
            const matchesSearch = term === '' || searchIndex.includes(term);
            const visible = matchesCategory && matchesSearch;

            card.classList.toggle('d-none', !visible);
            if (visible) {
                visibleCount++;
            }
        });

        noProductResults?.classList.toggle('d-none', visibleCount > 0);
    };

    const appendCustomerOption = (customer) => {
        if (!customerInput || !customer || !customer.id) {
            return;
        }

        const id = String(customer.id);
        const name = String(customer.nombre || '').trim();
        const documento = String(customer.documento || '').trim();
        const telefono = String(customer.telefono || '').trim();
        const email = String(customer.email || '').trim();
        const docSearchKey = documento.toLowerCase().replace(/[^a-z0-9]/g, '');

        const label = documento !== '' ? `${name} (${documento})` : name;

        if (customerInput.querySelector(`option[value="${escapeSelectorValue(id)}"]`)) {
            if (customerSelectInstance) {
                customerSelectInstance.setValue(id, true);
            } else {
                customerInput.value = id;
            }
            syncCustomerInfo();
            return;
        }

        if (customerSelectInstance) {
            customerSelectInstance.addOption({
                value: id,
                text: label,
            });
            customerSelectInstance.addItem(id, true);
        } else {
            const option = document.createElement('option');
            option.value = id;
            option.textContent = label;
            customerInput.appendChild(option);
            customerInput.value = id;
        }

        const optionElement = customerInput.querySelector(`option[value="${escapeSelectorValue(id)}"]`);
        if (optionElement) {
            optionElement.setAttribute('data-documento', docSearchKey);
            optionElement.setAttribute('data-documento-visible', documento);
            optionElement.setAttribute('data-nombre', name);
            optionElement.setAttribute('data-telefono', telefono);
            optionElement.setAttribute('data-email', email);
        }

        syncCustomerInfo();
    };

    categoryTabs?.addEventListener('click', (event) => {
        const button = event.target.closest('.vx-pos-category-btn');
        if (!button) {
            return;
        }

        activeCategory = String(button.dataset.category || 'all');
        categoryTabs.querySelectorAll('.vx-pos-category-btn').forEach((tab) => {
            tab.classList.toggle('is-active', tab === button);
        });

        applyProductFilters();
    });

    productGrid?.addEventListener('click', (event) => {
        const button = event.target.closest('.vx-pos-product-card');
        if (!button) {
            return;
        }

        addProductToCart(button.dataset.productId || '');
    });

    productSearchInput?.addEventListener('input', applyProductFilters);

    clearProductSearchButton?.addEventListener('click', () => {
        if (!productSearchInput) {
            return;
        }

        productSearchInput.value = '';
        applyProductFilters();
        productSearchInput.focus();
    });

    checkoutList.addEventListener('click', (event) => {
        const actionButton = event.target.closest('[data-action]');
        if (!actionButton) {
            return;
        }

        const itemRow = actionButton.closest('.vx-pos-checkout-item');
        if (!itemRow) {
            return;
        }

        const itemKey = String(itemRow.dataset.itemKey || '');
        if (!cart.has(itemKey)) {
            return;
        }

        const current = cart.get(itemKey);
        const action = String(actionButton.dataset.action || '');

        if (action === 'remove') {
            cart.delete(itemKey);
            renderCart();
            return;
        }

        if (action === 'minus') {
            updateItemQty(itemKey, Math.max(1, current.qty - 1), false);
            return;
        }

        if (action === 'plus') {
            updateItemQty(itemKey, current.qty + 1, true);
        }
    });

    checkoutList.addEventListener('change', (event) => {
        const qtyInput = event.target.closest('.vx-qty-input');
        if (qtyInput) {
            const row = qtyInput.closest('.vx-pos-checkout-item');
            if (!row) {
                return;
            }

            const itemKey = String(row.dataset.itemKey || '');
            if (!cart.has(itemKey)) {
                return;
            }

            const original = Number(qtyInput.value || 0);
            const integerQty = parseIntegerQty(original);
            if (!Number.isInteger(original)) {
                showMessage('warning', 'Cantidad inválida', 'La cantidad debe ser un número entero.');
            }
            updateItemQty(itemKey, integerQty, true);
            return;
        }

        const typeSelect = event.target.closest('.vx-line-discount-type');
        if (!typeSelect) {
            return;
        }

        const row = typeSelect.closest('.vx-pos-checkout-item');
        if (!row) {
            return;
        }

        const itemKey = String(row.dataset.itemKey || '');
        if (!cart.has(itemKey)) {
            return;
        }

        const item = cart.get(itemKey);
        item.lineDiscountType = typeSelect.value === 'porcentaje' ? 'porcentaje' : 'valor';
        cart.set(itemKey, item);
        renderCart();
    });

    checkoutList.addEventListener('input', (event) => {
        const discountInput = event.target.closest('.vx-line-discount-input');
        if (!discountInput) {
            return;
        }

        const row = discountInput.closest('.vx-pos-checkout-item');
        if (!row) {
            return;
        }

        const itemKey = String(row.dataset.itemKey || '');
        if (!cart.has(itemKey)) {
            return;
        }

        const item = cart.get(itemKey);
        item.lineDiscountValue = parseAmountInput(discountInput.value);
        cart.set(itemKey, item);

        const line = calcLine(item);
        const lineTotalNode = row.querySelector('.vx-pos-checkout-line-total');
        if (lineTotalNode) {
            lineTotalNode.textContent = formatMoney(line.lineTotal);
        }

        syncCheckoutSummary();
    });

    clearCartButton?.addEventListener('click', clearCart);
    saleTypeInput?.addEventListener('change', syncSaleTypeUI);
    customerInput?.addEventListener('change', syncCustomerInfo);
    paymentMethodInput?.addEventListener('change', () => {
        syncPaymentReferenceUI();
        syncCashUI();
    });
    cashAmountInput?.addEventListener('input', syncCashChange);
    variantQtyInput?.addEventListener('input', () => {
        const normalizedQty = parseIntegerQty(variantQtyInput.value || 1);
        if (String(normalizedQty) !== String(variantQtyInput.value || '').trim()) {
            variantQtyInput.value = String(normalizedQty);
        }
        refreshVariantModalState();
    });
    variantQtyInput?.addEventListener('change', () => {
        variantQtyInput.value = String(parseIntegerQty(variantQtyInput.value || 1));
        refreshVariantModalState();
    });
    variantModalElement?.addEventListener('hidden.bs.modal', () => {
        variantSelectionState = null;
        if (variantAttributesContainer) {
            variantAttributesContainer.innerHTML = '';
        }
        if (variantQtyInput) {
            variantQtyInput.value = '1';
        }
        if (variantPriceDisplay) {
            variantPriceDisplay.value = '$0.00';
        }
        if (variantStockBadge) {
            variantStockBadge.textContent = 'Stock: --';
            variantStockBadge.className = 'badge text-bg-light border';
        }
        if (variantAddButton) {
            variantAddButton.disabled = true;
        }
        if (variantModalHelper) {
            variantModalHelper.textContent = 'Selecciona los atributos para agregar al checkout.';
        }
    });
    variantModalElement?.addEventListener('shown.bs.modal', () => {
        const firstSelect = variantAttributesContainer?.querySelector('select');
        if (firstSelect) {
            firstSelect.focus();
        }
    });

    if (globalDiscountModeSelector) {
        globalDiscountModeSelector.addEventListener('change', () => {
            const mode = globalDiscountModeSelector.value === 'porcentaje' ? 'porcentaje' : 'valor';
            if (globalDiscountModeInput) {
                globalDiscountModeInput.value = mode;
            }
            syncGlobalDiscountFromDisplay(true);
            renderCart();
        });
    }

    if (globalDiscountDisplayInput) {
        globalDiscountDisplayInput.addEventListener('input', () => {
            syncGlobalDiscountFromDisplay(false);
            renderCart();
        });

        globalDiscountDisplayInput.addEventListener('blur', () => {
            syncGlobalDiscountFromDisplay(true);
            renderCart();
        });

        globalDiscountDisplayInput.addEventListener('focus', () => {
            const value = syncGlobalDiscountFromDisplay(false);
            globalDiscountDisplayInput.value = value <= 0 ? '' : String(value % 1 === 0 ? Math.trunc(value) : value);
        });
    }

    abonoInput?.addEventListener('input', () => {
        const totals = getCartTotals();
        const abono = parsePositiveNumber(abonoInput.value || 0);
        if (abono > totals.total) {
            abonoInput.value = totals.total.toFixed(2);
        }
    });

    form.addEventListener('submit', (event) => {
        if (!posEnabled) {
            event.preventDefault();
            showMessage('warning', 'POS bloqueado', 'El POS está bloqueado para este usuario.');
            return;
        }

        if (!paymentMethodInput || String(paymentMethodInput.value || '').trim() === '') {
            event.preventDefault();
            showMessage('warning', 'Método de pago', 'Selecciona un método de pago válido.');
            return;
        }

        if (
            paymentMethodInput
            && dataphonePaymentCodes.has(String(paymentMethodInput.value || '').toLowerCase())
            && paymentReferenceInput
            && String(paymentReferenceInput.value || '').trim() === ''
        ) {
            event.preventDefault();
            showMessage('warning', 'Referencia de pago', 'Debes ingresar la referencia de transacción del datáfono para registrar la venta.');
            paymentReferenceInput.focus();
            return;
        }

        if (cart.size === 0) {
            event.preventDefault();
            showMessage('warning', 'Carrito vacío', 'Debes agregar al menos un producto al checkout.');
            return;
        }

        if (saleTypeInput && saleTypeInput.value === 'credito' && (!customerInput || String(customerInput.value || '') === '')) {
            event.preventDefault();
            showMessage('warning', 'Cliente requerido', 'Para venta a crédito debes seleccionar un cliente.');
            return;
        }

        const totals = getCartTotals();
        if (abonoInput && saleTypeInput && saleTypeInput.value === 'credito') {
            const abono = parsePositiveNumber(abonoInput.value || 0);
            if (abono > totals.total) {
                event.preventDefault();
                showMessage('warning', 'Abono inválido', 'El abono inicial no puede superar el total de la venta.');
                abonoInput.value = totals.total.toFixed(2);
                return;
            }
        }

        // Validar pago en efectivo
        if (String(paymentMethodInput?.value || '').toLowerCase() === 'efectivo' && cashAmountInput) {
            const paid = parsePositiveNumber(cashAmountInput.value || 0);
            if (paid < totals.total) {
                event.preventDefault();
                showMessage('warning', 'Pago insuficiente', 'El monto recibido ($' + paid.toLocaleString() + ') es menor al total ($' + totals.total.toLocaleString() + ').');
                cashAmountInput.focus();
                return;
            }
        }

        syncGlobalDiscountFromDisplay(true);
        if (globalDiscountModeSelector && globalDiscountModeInput) {
            globalDiscountModeInput.value = globalDiscountModeSelector.value === 'porcentaje' ? 'porcentaje' : 'valor';
        }

        rebuildHiddenInputs();
    });

    customerForm?.addEventListener('submit', async (event) => {
        event.preventDefault();

        if (!posEnabled) {
            showMessage('warning', 'POS bloqueado', 'No puedes crear clientes mientras el POS esté bloqueado.');
            return;
        }

        const createUrl = String(customerForm.dataset.createUrl || '').trim();
        if (createUrl === '') {
            showMessage('error', 'Error', 'No se encontró la ruta para crear clientes.');
            return;
        }

        const submitButton = customerForm.querySelector('button[type="submit"]');
        if (submitButton) {
            submitButton.disabled = true;
        }

        try {
            const formData = new FormData(customerForm);
            const response = await fetch(createUrl, {
                method: 'POST',
                body: formData,
                headers: {
                    Accept: 'application/json',
                    'X-Requested-With': 'XMLHttpRequest',
                },
                credentials: 'same-origin',
            });

            const data = await response.json().catch(() => ({}));
            if (!response.ok || !data || data.ok !== true) {
                const message = String((data && data.message) || 'No fue posible crear el cliente.');
                showMessage('error', 'Error', message);
                return;
            }

            appendCustomerOption(data.customer || null);
            customerForm.reset();

            if (typeof bootstrap !== 'undefined' && customerModal) {
                const modal = bootstrap.Modal.getInstance(customerModal) || new bootstrap.Modal(customerModal);
                modal.hide();
            }

            showMessage('success', 'Cliente creado', String(data.message || 'Cliente creado correctamente.'));
        } catch (error) {
            showMessage('error', 'Error', 'No fue posible crear el cliente. Intenta nuevamente.');
        } finally {
            if (submitButton) {
                submitButton.disabled = false;
            }
        }
    });

    if (!posEnabled) {
        clearCartButton?.setAttribute('disabled', 'disabled');
        checkoutSubmit?.setAttribute('disabled', 'disabled');
    }

    buildProductCatalog();
    initCustomerSearch();
    syncGlobalDiscountFromDisplay(true);
    syncSaleTypeUI();
    syncPaymentReferenceUI();
    syncCashUI();
    syncCustomerInfo();
    applyProductFilters();
    renderCart();

    if (posEnabled) {
        productSearchInput?.focus();
    }
})();
