(function () {
    const root = document.querySelector('.ship-market-page');

    if (!root) {
        return;
    }

    const endpointsNode = document.getElementById('ship-market-cart-endpoints');
    const initialCartNode = document.getElementById('ship-market-cart-initial');
    const stockLimitsNode = document.getElementById('ship-market-stock-limits');
    const activeSolicitudNode = document.getElementById('ship-market-active-solicitud');
    const endpoints = JSON.parse(endpointsNode?.textContent || '{}');
    const stockLimits = JSON.parse(stockLimitsNode?.textContent || '{}');
    const activeSolicitud = JSON.parse(activeSolicitudNode?.textContent || 'null');
    const csrfToken = root.dataset.csrfToken || '';
    const alerts = root.querySelector('.ship-market-alerts');
    const themeToggle = root.querySelector('[data-theme-toggle]');
    const themeToggleLabel = root.querySelector('[data-theme-toggle-label]');
    const cartItemsContainer = document.querySelector('[data-cart-items]');
    const cartListScroll = document.querySelector('[data-cart-list-scroll]');
    const cartEmpty = document.querySelector('[data-cart-empty]');
    const clearButton = document.querySelector('[data-clear-cart]');
    const generateRequestButton = document.querySelector('[data-generate-request]');
    const confirmReplaceSolicitudButton = document.querySelector('[data-confirm-replace-solicitud]');
    const replaceSolicitudModalElement = document.getElementById('shipMarketReplaceSolicitudModal');
    const replaceSolicitudModal = replaceSolicitudModalElement ? bootstrap.Modal.getOrCreateInstance(replaceSolicitudModalElement) : null;
    const template = document.getElementById('ship-market-cart-item-template');
    const numberFormatter = new Intl.NumberFormat('es-PE');
    const quantitySyncDelay = 250;
    const minimumCartQuantity = 1;
    const themeStorageKey = 'ship-market-theme';

    let cartState = JSON.parse(initialCartNode?.textContent || '{"items":[],"summary":{"lineas":0,"unidades":0}}');
    let confirmedCartState = JSON.parse(JSON.stringify(cartState));
    let requestInFlight = false;
    let quantitySyncTimer = null;
    let hasPendingQuantitySync = false;

    const updateThemeToggle = (theme) => {
        const isDark = theme === 'dark';

        root.dataset.theme = isDark ? 'dark' : 'light';

        if (themeToggle) {
            themeToggle.setAttribute('aria-pressed', isDark ? 'true' : 'false');
            themeToggle.setAttribute('aria-label', isDark ? 'Activar modo claro' : 'Activar modo oscuro');
        }

        if (themeToggleLabel) {
            themeToggleLabel.textContent = isDark ? 'Modo claro' : 'Modo oscuro';
        }
    };

    const storedTheme = window.localStorage.getItem(themeStorageKey);
    updateThemeToggle(storedTheme === 'dark' ? 'dark' : 'light');

    const currentQuantityForCode = (code) => {
        const item = (Array.isArray(cartState.items) ? cartState.items : []).find((entry) => entry.codigo === code);

        return Number(item?.cantidad || 0);
    };

    const currentLimitForCode = (code) => Number(stockLimits?.[code]?.stock_disponible || 0);

    const flashProductAddedNotice = (code) => {
        const card = root.querySelector('[data-product-card][data-code="' + CSS.escape(code) + '"]');

        if (!card) {
            return;
        }

        card.classList.add('ship-market-card--added');

        const existingTimer = Number(card.dataset.noticeTimer || 0);

        if (existingTimer) {
            window.clearTimeout(existingTimer);
        }

        const timerId = window.setTimeout(() => {
            card.classList.remove('ship-market-card--added');
            delete card.dataset.noticeTimer;
        }, 1400);

        card.dataset.noticeTimer = String(timerId);
    };

    const cloneCartState = (state) => JSON.parse(JSON.stringify(state));

    const recalculateSummary = () => {
        const items = Array.isArray(cartState.items) ? cartState.items : [];

        cartState.summary = {
            lineas: items.length,
            unidades: items.reduce((total, item) => total + Number(item.cantidad || 0), 0),
        };
    };

    const buildQuantitiesPayload = () => {
        const quantities = {};

        (Array.isArray(cartState.items) ? cartState.items : []).forEach((item) => {
            const quantity = Number(item.cantidad || 0);

            if (quantity > 0) {
                quantities[item.codigo] = quantity;
            }
        });

        return quantities;
    };

    const quantitiesPayloadMatch = (left, right) => {
        const leftEntries = Object.entries(left || {}).sort(([leftCode], [rightCode]) => leftCode.localeCompare(rightCode));
        const rightEntries = Object.entries(right || {}).sort(([leftCode], [rightCode]) => leftCode.localeCompare(rightCode));

        if (leftEntries.length !== rightEntries.length) {
            return false;
        }

        return leftEntries.every(([leftCode, leftQuantity], index) => {
            const [rightCode, rightQuantity] = rightEntries[index] || [];

            return leftCode === rightCode && Number(leftQuantity) === Number(rightQuantity);
        });
    };

    const findCartItem = (code) => (Array.isArray(cartState.items) ? cartState.items : []).find((entry) => entry.codigo === code);

    const removeCartItemLocally = (code) => {
        cartState.items = (Array.isArray(cartState.items) ? cartState.items : []).filter((item) => item.codigo !== code);
        recalculateSummary();
    };

    const upsertCartItemLocally = (code, quantity) => {
        const nextQuantity = Math.max(0, quantity);
        const existingItem = findCartItem(code);
        const limit = currentLimitForCode(code);
        const description = stockLimits?.[code]?.descripcion || existingItem?.descripcion || code;

        if (nextQuantity <= 0) {
            removeCartItemLocally(code);
            return;
        }

        if (existingItem) {
            existingItem.cantidad = nextQuantity;
            existingItem.stock_disponible = limit;
        } else {
            cartState.items = [
                ...(Array.isArray(cartState.items) ? cartState.items : []),
                {
                    codigo: code,
                    descripcion: description,
                    cantidad: nextQuantity,
                    stock_disponible: limit,
                },
            ];
        }

        recalculateSummary();
    };

    const syncAddButtons = () => {
        root.querySelectorAll('[data-add-to-cart]').forEach((button) => {
            const code = button.dataset.code || '';
            const limit = currentLimitForCode(code);
            const quantity = currentQuantityForCode(code);
            const inCart = quantity > 0;
            const atLimit = limit > 0 && quantity >= limit;

            if (inCart) {
                button.disabled = true;
                button.textContent = 'Ver en el carrito';
                return;
            }

            button.disabled = atLimit;
            button.textContent = atLimit ? 'Limite alcanzado' : 'Agregar al carrito';
        });
    };

    const showAlert = (message, variant) => {
        if (!alerts) {
            return;
        }

        alerts.innerHTML = '<div class="alert alert-' + variant + '">' + message + '</div>';
    };

    const setSummaryValues = () => {
        document.querySelectorAll('[data-cart-lines]').forEach((node) => {
            node.textContent = numberFormatter.format(cartState.summary?.lineas || 0);
        });

        document.querySelectorAll('[data-cart-units]').forEach((node) => {
            node.textContent = numberFormatter.format(cartState.summary?.unidades || 0);
        });

        document.querySelectorAll('[data-cart-count]').forEach((node) => {
            node.textContent = numberFormatter.format(cartState.summary?.lineas || 0);
        });

        if (clearButton) {
            clearButton.disabled = (cartState.summary?.lineas || 0) === 0 || requestInFlight;
        }

        if (generateRequestButton) {
            generateRequestButton.disabled = (cartState.summary?.lineas || 0) === 0 || requestInFlight;
        }

        syncAddButtons();
    };
    const request = async (url, options) => {
        const response = await fetch(url, {
            ...options,
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                'X-CSRF-TOKEN': csrfToken,
                ...(options?.headers || {}),
            },
        });

        const payload = await response.json().catch(() => ({}));

        if (!response.ok) {
            throw new Error(payload.message || payload.error || 'No se pudo actualizar el carrito.');
        }

        return payload;
    };

    const syncCart = async (url, options, successMessage) => {
        if (requestInFlight) {
            return;
        }

        requestInFlight = true;
        setSummaryValues();

        try {
            const payload = await request(url, options);
            cartState = payload.cart || { items: [], summary: { lineas: 0, unidades: 0 } };
            confirmedCartState = cloneCartState(cartState);
            renderCart();
            showAlert(payload.message || successMessage, 'success');
        } catch (error) {
            showAlert(error.message, 'warning');
        } finally {
            requestInFlight = false;
            setSummaryValues();
        }
    };

    const addItem = async (code) => {
        const beforeQuantity = currentQuantityForCode(code);

        await syncCart(endpoints.add, {
            method: 'POST',
            body: JSON.stringify({ codigo: code, cantidad: 1 }),
        }, 'Bien agregado al carrito.');

        if (currentQuantityForCode(code) > beforeQuantity) {
            flashProductAddedNotice(code);
        }
    };

    const flushPendingQuantityChanges = async () => {
        if (!hasPendingQuantitySync || requestInFlight) {
            return;
        }

        hasPendingQuantitySync = false;
        requestInFlight = true;
        const requestedQuantities = buildQuantitiesPayload();

        try {
            const payload = await request(endpoints.update, {
                method: 'PATCH',
                body: JSON.stringify({ cantidades: requestedQuantities }),
            });

            const serverCart = payload.cart || { items: [], summary: { lineas: 0, unidades: 0 } };
            const currentQuantities = buildQuantitiesPayload();
            const requestIsCurrent = quantitiesPayloadMatch(currentQuantities, requestedQuantities);

            confirmedCartState = cloneCartState(serverCart);

            if (requestIsCurrent) {
                cartState = cloneCartState(serverCart);
                renderCart();
            } else {
                hasPendingQuantitySync = true;
            }
        } catch (error) {
            const currentQuantities = buildQuantitiesPayload();
            const requestIsCurrent = quantitiesPayloadMatch(currentQuantities, requestedQuantities);

            if (requestIsCurrent) {
                cartState = cloneCartState(confirmedCartState);
                renderCart();
                showAlert(error.message, 'warning');
            } else {
                hasPendingQuantitySync = true;
            }
        } finally {
            requestInFlight = false;
            setSummaryValues();

            if (hasPendingQuantitySync) {
                scheduleQuantitySync();
            }
        }
    };

    function scheduleQuantitySync() {
        hasPendingQuantitySync = true;

        if (quantitySyncTimer !== null) {
            window.clearTimeout(quantitySyncTimer);
        }

        quantitySyncTimer = window.setTimeout(() => {
            quantitySyncTimer = null;
            flushPendingQuantityChanges();
        }, quantitySyncDelay);
    }

    const cancelPendingQuantitySync = () => {
        hasPendingQuantitySync = false;

        if (quantitySyncTimer !== null) {
            window.clearTimeout(quantitySyncTimer);
            quantitySyncTimer = null;
        }
    };

    const changeQuantityLocally = (code, quantity) => {
        upsertCartItemLocally(code, quantity);
        renderCart();
        scheduleQuantitySync();
    };

    const removeItem = (code) => {
        cancelPendingQuantitySync();

        return syncCart(endpoints.removeBase.replace('__CODE__', encodeURIComponent(code)), {
        method: 'DELETE',
        }, 'Bien removido del carrito.');
    };

    const clearCart = () => {
        cancelPendingQuantitySync();

        return syncCart(endpoints.clear, {
        method: 'DELETE',
        }, 'Carrito vaciado.');
    };

    const generateSolicitud = async () => {
        if (requestInFlight) {
            return;
        }

        if (hasPendingQuantitySync) {
            await flushPendingQuantityChanges();
        }

        if ((cartState.summary?.lineas || 0) === 0) {
            showAlert('No hay bienes en el carrito para generar la solicitud.', 'warning');
            return;
        }

        requestInFlight = true;
        setSummaryValues();

        try {
            const payload = await request(endpoints.generate, {
                method: 'POST',
                body: JSON.stringify({}),
            });

            cartState = payload.cart || { items: [], summary: { lineas: 0, unidades: 0 } };
            confirmedCartState = cloneCartState(cartState);
            renderCart();
            showAlert(payload.message || 'Solicitud generada correctamente.', 'success');
        } catch (error) {
            showAlert(error.message, 'warning');
        } finally {
            requestInFlight = false;
            setSummaryValues();
        }
    };

    const promptSolicitudReplacement = async () => {
        if (!activeSolicitud) {
            await generateSolicitud();
            return;
        }

        replaceSolicitudModal?.show();
    };

    const renderCart = () => {
        setSummaryValues();

        if (!cartItemsContainer || !template) {
            return;
        }

        cartItemsContainer.innerHTML = '';

        const items = Array.isArray(cartState.items) ? cartState.items : [];

        if (items.length === 0) {
            cartListScroll?.classList.add('d-none');
            cartEmpty?.classList.remove('d-none');
            return;
        }

        cartListScroll?.classList.remove('d-none');
        cartEmpty?.classList.add('d-none');

        items.forEach((item) => {
            const fragment = template.content.cloneNode(true);

            fragment.querySelector('[data-cart-item-name]').textContent = item.descripcion;
            fragment.querySelector('[data-cart-item-quantity]').textContent = numberFormatter.format(item.cantidad || 0);

            fragment.querySelector('[data-remove-item]').addEventListener('click', () => {
                removeItem(item.codigo);
            });

            fragment.querySelector('[data-decrease-item]').addEventListener('click', () => {
                const currentQuantity = Number(item.cantidad || 0);

                if (currentQuantity <= minimumCartQuantity) {
                    return;
                }

                changeQuantityLocally(item.codigo, currentQuantity - 1);
            });

            fragment.querySelector('[data-increase-item]').addEventListener('click', () => {
                const max = Number(item.stock_disponible || currentLimitForCode(item.codigo) || 0);
                const nextValue = Math.min(max, (item.cantidad || 0) + 1);

                if (nextValue !== item.cantidad) {
                    changeQuantityLocally(item.codigo, nextValue);
                } else {
                    showAlert('La cantidad solicitada supera el stock disponible.', 'warning');
                }
            });

            const decreaseButton = fragment.querySelector('[data-decrease-item]');
            const increaseButton = fragment.querySelector('[data-increase-item]');
            decreaseButton.disabled = Number(item.cantidad || 0) <= minimumCartQuantity;
            increaseButton.disabled = Number(item.cantidad || 0) >= Number(item.stock_disponible || currentLimitForCode(item.codigo) || 0);

            cartItemsContainer.appendChild(fragment);
        });
    };

    root.querySelectorAll('[data-add-to-cart]').forEach((button) => {
        button.addEventListener('click', () => {
            const code = button.dataset.code || '';
            const limit = currentLimitForCode(code);
            const quantity = currentQuantityForCode(code);

            if (quantity > 0) {
                syncAddButtons();
                return;
            }

            if (limit > 0 && quantity >= limit) {
                showAlert('La cantidad solicitada supera el stock disponible.', 'warning');
                syncAddButtons();
                return;
            }

            addItem(code);
        });
    });

    themeToggle?.addEventListener('click', () => {
        const nextTheme = root.dataset.theme === 'dark' ? 'light' : 'dark';

        window.localStorage.setItem(themeStorageKey, nextTheme);
        updateThemeToggle(nextTheme);
    });

    generateRequestButton?.addEventListener('click', promptSolicitudReplacement);

    confirmReplaceSolicitudButton?.addEventListener('click', async () => {
        replaceSolicitudModal?.hide();
        await generateSolicitud();
    });

    clearButton?.addEventListener('click', clearCart);

    renderCart();
})();