'use strict';

window.addEventListener('DOMContentLoaded', () => {
    const body = document.body;
    const toggle = document.getElementById('vxSidebarToggle');
    const close = document.getElementById('vxSidebarClose');
    const backdrop = document.getElementById('vxSidebarBackdrop');
    const desktopMediaQuery = window.matchMedia('(min-width: 992px)');
    const sidebarCollapseStorageKey = 'vx_sidebar_collapsed';

    const isDesktop = () => desktopMediaQuery.matches;

    const setToggleAriaLabel = () => {
        if (!toggle) {
            return;
        }

        if (isDesktop()) {
            const collapsed = body.classList.contains('vx-sidebar-collapsed');
            toggle.setAttribute('aria-label', collapsed ? 'Expandir menu' : 'Contraer menu');
            return;
        }

        const open = body.classList.contains('vx-sidebar-open');
        toggle.setAttribute('aria-label', open ? 'Cerrar menu' : 'Abrir menu');
    };

    const setDesktopCollapsed = (collapsed, persist = true) => {
        body.classList.toggle('vx-sidebar-collapsed', collapsed);
        if (persist) {
            try {
                window.localStorage.setItem(sidebarCollapseStorageKey, collapsed ? '1' : '0');
            } catch (_) {
                // Si localStorage no está disponible, seguimos sin bloquear la UI.
            }
        }
        setToggleAriaLabel();
    };

    const loadDesktopSidebarPreference = () => {
        let collapsed = false;
        try {
            collapsed = window.localStorage.getItem(sidebarCollapseStorageKey) === '1';
        } catch (_) {
            collapsed = false;
        }
        setDesktopCollapsed(collapsed, false);
    };

    const closeSidebar = () => {
        body.classList.remove('vx-sidebar-open');
        setToggleAriaLabel();
    };
    const openSidebar = () => {
        body.classList.add('vx-sidebar-open');
        setToggleAriaLabel();
    };
    const mobileMoreToggle = document.getElementById('vxMobileMoreToggle');
    const mobileSheet = document.getElementById('vxMobileSheet');
    const mobileSheetBackdrop = document.getElementById('vxMobileSheetBackdrop');
    const mobileSheetClose = document.getElementById('vxMobileSheetClose');

    const closeMobileSheet = () => {
        body.classList.remove('vx-mobile-sheet-open');
        mobileMoreToggle?.setAttribute('aria-expanded', 'false');
        mobileSheet?.setAttribute('aria-hidden', 'true');
    };

    const openMobileSheet = () => {
        if (isDesktop()) {
            return;
        }

        closeSidebar();
        body.classList.add('vx-mobile-sheet-open');
        mobileMoreToggle?.setAttribute('aria-expanded', 'true');
        mobileSheet?.setAttribute('aria-hidden', 'false');
    };

    const toggleMobileSheet = () => {
        if (body.classList.contains('vx-mobile-sheet-open')) {
            closeMobileSheet();
            return;
        }

        openMobileSheet();
    };

    toggle?.addEventListener('click', () => {
        if (isDesktop()) {
            const nextCollapsed = !body.classList.contains('vx-sidebar-collapsed');
            setDesktopCollapsed(nextCollapsed);
            return;
        }

        closeMobileSheet();

        if (body.classList.contains('vx-sidebar-open')) {
            closeSidebar();
            return;
        }
        openSidebar();
    });

    close?.addEventListener('click', closeSidebar);
    backdrop?.addEventListener('click', closeSidebar);
    mobileMoreToggle?.addEventListener('click', (event) => {
        event.preventDefault();
        toggleMobileSheet();
    });
    mobileSheetClose?.addEventListener('click', closeMobileSheet);
    mobileSheetBackdrop?.addEventListener('click', closeMobileSheet);
    document.querySelectorAll('.vx-mobile-sheet .vx-mobile-sheet-item, .vx-mobile-sheet .vx-mobile-sheet-profile, .vx-mobile-sheet .vx-mobile-sheet-quick-link').forEach((link) => {
        link.addEventListener('click', () => {
            closeMobileSheet();
        });
    });

    const navGroups = Array.from(document.querySelectorAll('.vx-sidebar [data-vx-nav-group]'));
    const setNavGroupOpen = (group, open) => {
        const toggleBtn = group.querySelector('[data-vx-nav-toggle]');
        const panel = group.querySelector('[data-vx-nav-panel]');
        if (!(toggleBtn instanceof HTMLButtonElement) || !(panel instanceof HTMLElement)) {
            return;
        }

        toggleBtn.classList.toggle('is-open', open);
        toggleBtn.setAttribute('aria-expanded', open ? 'true' : 'false');
        panel.classList.toggle('is-open', open);
    };

    navGroups.forEach((group) => {
        const toggleBtn = group.querySelector('[data-vx-nav-toggle]');
        if (!(toggleBtn instanceof HTMLButtonElement)) {
            return;
        }

        toggleBtn.addEventListener('click', () => {
            if (isDesktop() && body.classList.contains('vx-sidebar-collapsed')) {
                return;
            }

            const isOpen = toggleBtn.getAttribute('aria-expanded') === 'true';
            const nextOpen = !isOpen;

            if (nextOpen) {
                navGroups.forEach((otherGroup) => {
                    if (otherGroup !== group) {
                        setNavGroupOpen(otherGroup, false);
                    }
                });
            }

            setNavGroupOpen(group, nextOpen);
        });
    });

    document.querySelectorAll('.vx-sidebar .vx-nav-link').forEach((link) => {
        link.addEventListener('click', () => {
            if (window.innerWidth < 992) {
                closeSidebar();
            }
        });
    });

    // Fallback para dropdowns cuando Bootstrap no queda inicializado
    // (por cache agresivo o carga parcial de assets).
    if (!window.bootstrap?.Dropdown) {
        const dropdownToggles = Array.from(document.querySelectorAll('[data-bs-toggle="dropdown"]'))
            .filter((toggle) => toggle instanceof HTMLElement);

        const setDropdownOpen = (toggle, open) => {
            if (!(toggle instanceof HTMLElement)) {
                return;
            }

            const wrapper = toggle.closest('.dropdown');
            if (!(wrapper instanceof HTMLElement)) {
                return;
            }

            const menu = wrapper.querySelector('.dropdown-menu');
            if (!(menu instanceof HTMLElement)) {
                return;
            }

            wrapper.classList.toggle('show', open);
            toggle.classList.toggle('show', open);
            menu.classList.toggle('show', open);
            toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
        };

        const closeAllDropdowns = () => {
            dropdownToggles.forEach((toggle) => setDropdownOpen(toggle, false));
        };

        dropdownToggles.forEach((toggle) => {
            toggle.addEventListener('click', (event) => {
                event.preventDefault();
                event.stopPropagation();

                const isOpen = toggle.getAttribute('aria-expanded') === 'true';
                if (!isOpen) {
                    closeAllDropdowns();
                }
                setDropdownOpen(toggle, !isOpen);
            });
        });

        document.addEventListener('click', (event) => {
            const target = event.target;
            if (!(target instanceof Element)) {
                closeAllDropdowns();
                return;
            }

            if (!target.closest('.dropdown')) {
                closeAllDropdowns();
            }
        });

        window.addEventListener('keydown', (event) => {
            if (event.key === 'Escape') {
                closeAllDropdowns();
            }
        });
    }

    window.addEventListener('keydown', (event) => {
        if (event.key === 'Escape') {
            closeSidebar();
            closeMobileSheet();
        }
    });

    window.addEventListener('resize', () => {
        if (isDesktop()) {
            closeSidebar();
            closeMobileSheet();
            loadDesktopSidebarPreference();
            return;
        }

        body.classList.remove('vx-sidebar-collapsed');
        closeSidebar();
        closeMobileSheet();
    });

    if (isDesktop()) {
        loadDesktopSidebarPreference();
    } else {
        body.classList.remove('vx-sidebar-collapsed');
        closeMobileSheet();
    }
    setToggleAriaLabel();

    // ── vxConfirm — modal de confirmación elegante ──────────────────────────
    const _vxConfirmBuild = () => {
        const existing = document.getElementById('vx-confirm-modal');
        if (existing) return existing;
        const el = document.createElement('div');
        el.id = 'vx-confirm-modal';
        el.className = 'modal fade';
        el.tabIndex = -1;
        el.setAttribute('data-bs-backdrop', 'true');
        el.setAttribute('aria-hidden', 'true');
        el.innerHTML = `
            <div class="modal-dialog modal-dialog-centered" style="max-width:400px">
                <div class="modal-content" style="border-radius:18px;border:none;box-shadow:0 28px 64px -16px rgba(15,23,42,.28);overflow:hidden">
                    <div class="modal-body px-5 pt-5 pb-3 text-center">
                        <div id="vx-cm-icon" style="width:58px;height:58px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:1.55rem;margin-bottom:16px"></div>
                        <h5 id="vx-cm-title" style="font-weight:700;font-size:1rem;margin-bottom:8px;color:#111827"></h5>
                        <p id="vx-cm-msg" style="color:#6b7280;font-size:.87rem;line-height:1.6;margin-bottom:0"></p>
                    </div>
                    <div class="d-flex gap-2 px-5 pb-5 pt-4">
                        <button id="vx-cm-cancel" class="btn btn-outline-secondary flex-fill fw-semibold"
                                style="border-radius:10px;padding:10px 0;font-size:.88rem">Cancelar</button>
                        <button id="vx-cm-accept" class="btn flex-fill fw-semibold"
                                style="border-radius:10px;padding:10px 0;font-size:.88rem;color:#fff"></button>
                    </div>
                </div>
            </div>`;
        document.body.appendChild(el);
        return el;
    };

    const vxConfirm = (message, opts = {}) => {
        return new Promise((resolve) => {
            const modal    = _vxConfirmBuild();
            const type     = opts.type   || 'warning';
            const title    = opts.title  || 'Confirmar acción';
            const acceptLbl = opts.accept || 'Sí, continuar';
            const cancelLbl = opts.cancel || 'Cancelar';

            const palette = {
                danger:  { bg: '#fee2e2', color: '#dc2626', btn: '#dc2626', icon: '🚫' },
                warning: { bg: '#fef3c7', color: '#d97706', btn: '#d97706', icon: '⚠️' },
                info:    { bg: '#dbeafe', color: '#2563eb', btn: '#2563eb', icon: 'ℹ️'  },
                success: { bg: '#d1fae5', color: '#059669', btn: '#059669', icon: '✅' },
            };
            const p = palette[type] || palette.warning;

            const iconEl   = modal.querySelector('#vx-cm-icon');
            const titleEl  = modal.querySelector('#vx-cm-title');
            const msgEl    = modal.querySelector('#vx-cm-msg');
            const acceptBtn = modal.querySelector('#vx-cm-accept');
            const cancelBtn = modal.querySelector('#vx-cm-cancel');

            iconEl.style.background  = p.bg;
            iconEl.style.color       = p.color;
            iconEl.textContent       = p.icon;
            titleEl.textContent      = title;
            msgEl.textContent        = message;
            acceptBtn.textContent    = acceptLbl;
            cancelBtn.textContent    = cancelLbl;
            acceptBtn.style.background  = p.btn;
            acceptBtn.style.borderColor = 'transparent';

            const bsModal = window.bootstrap.Modal.getOrCreateInstance(modal);

            const cleanup = () => {
                acceptBtn.removeEventListener('click', onAccept);
                cancelBtn.removeEventListener('click', onCancel);
                modal.removeEventListener('hidden.bs.modal', onHidden);
            };
            const onAccept = () => { cleanup(); bsModal.hide(); resolve(true); };
            const onCancel = () => { cleanup(); bsModal.hide(); resolve(false); };
            const onHidden = () => { cleanup(); resolve(false); };

            acceptBtn.addEventListener('click', onAccept);
            cancelBtn.addEventListener('click', onCancel);
            modal.addEventListener('hidden.bs.modal', onHidden);

            bsModal.show();
        });
    };
    window.vxConfirm = vxConfirm;
    // ────────────────────────────────────────────────────────────────────────

    const extractLegacyConfirmMessage = (code) => {
        if (typeof code !== 'string') return '';
        const match = code.match(/confirm\((['"])(.*?)\1\)/i);
        return match ? String(match[2] || '').trim() : '';
    };

    // Strip onsubmit confirm() → data-vx-confirm
    document.querySelectorAll('form[onsubmit*="confirm("]').forEach((form) => {
        const message = extractLegacyConfirmMessage(form.getAttribute('onsubmit') || '');
        if (message === '') return;
        form.setAttribute('data-vx-confirm', message);
        form.removeAttribute('onsubmit');
    });

    // Strip button/link onclick confirm() → data-vx-confirm on parent form
    document.querySelectorAll('button[onclick*="confirm("], a[onclick*="confirm("]').forEach((btn) => {
        const message = extractLegacyConfirmMessage(btn.getAttribute('onclick') || '');
        if (message === '') return;
        const form = btn.closest('form');
        if (form) form.setAttribute('data-vx-confirm', message);
        btn.removeAttribute('onclick');
    });

    document.addEventListener('submit', (event) => {
        const form = event.target;
        if (!(form instanceof HTMLFormElement)) return;

        const message = (form.getAttribute('data-vx-confirm') || '').trim();
        if (message === '') return;

        if (form.dataset.vxConfirmed === '1') {
            form.dataset.vxConfirmed = '0';
            return;
        }

        event.preventDefault();

        const type   = (form.dataset.vxConfirmType  || 'warning').trim();
        const title  = (form.dataset.vxConfirmTitle || 'Confirmar acción').trim();
        const accept = (form.dataset.vxConfirmAccept || 'Sí, continuar').trim();

        vxConfirm(message, { type, title, accept }).then((accepted) => {
            if (!accepted) {
                window.sileo?.info({
                    title: 'Acción cancelada',
                    description: 'No se realizaron cambios.',
                    position: 'top-center',
                });
                return;
            }
            form.dataset.vxConfirmed = '1';
            form.submit();
        });
    }, true);

    const cashPendingBadge = document.getElementById('vxCajaPendingBadge');
    const pendingUrl = cashPendingBadge?.dataset?.pendingUrl ?? '';
    let lastPendingCount = Number.parseInt(cashPendingBadge?.textContent ?? '0', 10);
    if (!Number.isFinite(lastPendingCount) || lastPendingCount < 0) {
        lastPendingCount = 0;
    }
    let hasPolledOnce = false;
    let audioContext = null;

    const applyPendingCount = (count) => {
        if (!cashPendingBadge) {
            return;
        }

        const value = Number.isFinite(count) ? Math.max(0, count) : 0;
        if (value <= 0) {
            cashPendingBadge.classList.add('d-none');
            cashPendingBadge.textContent = '0';
            return;
        }

        cashPendingBadge.classList.remove('d-none');
        cashPendingBadge.textContent = value > 99 ? '99+' : String(value);
    };

    const ensureToastContainer = () => {
        let container = document.getElementById('vxToastContainer');
        if (container) {
            return container;
        }

        container = document.createElement('div');
        container.id = 'vxToastContainer';
        container.className = 'toast-container position-fixed top-0 end-0 p-3';
        container.style.zIndex = '1090';
        document.body.appendChild(container);
        return container;
    };

    const showPendingToast = (newCount, totalCount) => {
        const container = ensureToastContainer();
        const toast = document.createElement('div');
        toast.className = 'toast text-bg-dark border-0';
        toast.setAttribute('role', 'alert');
        toast.setAttribute('aria-live', 'assertive');
        toast.setAttribute('aria-atomic', 'true');
        toast.innerHTML = `
            <div class="d-flex">
                <div class="toast-body">
                    <strong>Nuevo traspaso pendiente</strong><br>
                    Llegaron ${newCount} nuevo(s). Total pendiente: ${totalCount}.
                </div>
                <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Cerrar"></button>
            </div>
        `;
        container.appendChild(toast);

        if (window.bootstrap?.Toast) {
            const toastInstance = new window.bootstrap.Toast(toast, { delay: 5000 });
            toast.addEventListener('hidden.bs.toast', () => toast.remove());
            toastInstance.show();
            return;
        }

        toast.classList.add('show');
        window.setTimeout(() => toast.remove(), 5000);
    };

    const playPendingSound = async () => {
        const AudioContextClass = window.AudioContext || window.webkitAudioContext;
        if (!AudioContextClass) {
            return;
        }

        try {
            if (!audioContext) {
                audioContext = new AudioContextClass();
            }

            if (audioContext.state === 'suspended') {
                await audioContext.resume();
            }

            if (audioContext.state !== 'running') {
                return;
            }

            const now = audioContext.currentTime;
            const playTone = (frequency, startAt, duration, gainLevel) => {
                const osc = audioContext.createOscillator();
                const gain = audioContext.createGain();
                osc.type = 'sine';
                osc.frequency.setValueAtTime(frequency, startAt);
                gain.gain.setValueAtTime(0.0001, startAt);
                gain.gain.exponentialRampToValueAtTime(gainLevel, startAt + 0.01);
                gain.gain.exponentialRampToValueAtTime(0.0001, startAt + duration);
                osc.connect(gain);
                gain.connect(audioContext.destination);
                osc.start(startAt);
                osc.stop(startAt + duration);
            };

            playTone(880, now, 0.09, 0.04);
            playTone(1174, now + 0.1, 0.12, 0.04);
        } catch (_) {
            // Evita romper la experiencia si el navegador bloquea audio automático.
        }
    };

    const unlockAudio = async () => {
        const AudioContextClass = window.AudioContext || window.webkitAudioContext;
        if (!AudioContextClass) {
            return;
        }

        try {
            if (!audioContext) {
                audioContext = new AudioContextClass();
            }

            if (audioContext.state === 'suspended') {
                await audioContext.resume();
            }
        } catch (_) {
            // Si no se puede activar audio, seguimos sin bloquear la UI.
        }
    };

    window.addEventListener('pointerdown', unlockAudio, { once: true });
    window.addEventListener('keydown', unlockAudio, { once: true });

    const refreshPendingCount = async () => {
        if (!pendingUrl) {
            return;
        }

        try {
            const response = await fetch(pendingUrl, {
                method: 'GET',
                credentials: 'same-origin',
                cache: 'no-store',
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                },
            });

            if (!response.ok) {
                return;
            }

            const payload = await response.json();
            const count = Number(payload?.count ?? 0);
            const normalizedCount = Number.isFinite(count) && count > 0 ? Math.floor(count) : 0;
            const previousCount = lastPendingCount;

            applyPendingCount(normalizedCount);

            if (hasPolledOnce && normalizedCount > previousCount) {
                const newItems = normalizedCount - previousCount;
                showPendingToast(newItems, normalizedCount);
                playPendingSound();
            }

            lastPendingCount = normalizedCount;
            hasPolledOnce = true;
        } catch (_) {
            // Evita romper la experiencia si falla el polling.
        }
    };

    if (cashPendingBadge && pendingUrl) {
        refreshPendingCount();
        window.setInterval(refreshPendingCount, 12000);
    }

    const stockNotificationToggle = document.getElementById('vxNotificationToggle');
    const stockNotificationBadge = document.getElementById('vxNotificationBadge');
    const stockNotificationList = document.getElementById('vxNotificationList');
    const stockNotificationCountLabel = document.getElementById('vxNotificationCountLabel');
    const stockNotificationMarkReadButton = document.getElementById('vxNotificationMarkRead');
    const stockNotificationEndpoint = stockNotificationToggle?.dataset?.notificationsUrl ?? '';
    const stockNotificationInventoryUrl = stockNotificationToggle?.dataset?.inventoryUrl ?? '';
    const stockNotificationSupportUrl = stockNotificationToggle?.dataset?.supportUrl ?? '';
    const stockNotificationMarkReadUrl = stockNotificationToggle?.dataset?.markReadUrl ?? '';
    const stockNotificationScope = String(stockNotificationToggle?.dataset?.notificationScope ?? 'tenant').toLowerCase();
    const stockNotificationStorageKey = 'vx_stock_minimum_alert_fingerprint';
    const ticketNotificationStorageKey = stockNotificationScope === 'superadmin'
        ? 'vx_superadmin_ticket_alert_fingerprint'
        : 'vx_ticket_alert_fingerprint';
    let stockOnlyNotificationsCount = 0;
    let ticketOnlyNotificationsCount = 0;
    let stockNotificationsHasPolled = false;

    const escapeHtml = (value) => String(value ?? '').replace(/[&<>"']/g, (char) => {
        const map = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            '\'': '&#39;',
        };
        return map[char] || char;
    });

    const normalizePositiveInt = (value) => {
        const parsed = Number.parseInt(String(value ?? '0'), 10);
        if (!Number.isFinite(parsed) || parsed < 0) {
            return 0;
        }

        return Math.floor(parsed);
    };

    const badgeText = (count) => (count > 99 ? '99+' : String(count));

    const getCsrfToken = () => {
        const tokenInput = document.querySelector('input[name="_token"]');
        if (!tokenInput) {
            return '';
        }
        return String(tokenInput.value || '').trim();
    };

    const renderStockNotificationItems = (items) => {
        if (!stockNotificationList) {
            return;
        }

        if (!Array.isArray(items) || items.length === 0) {
            stockNotificationList.innerHTML = '<li id="vxNotificationEmpty" class="vx-notify-empty">No hay notificaciones pendientes.</li>';
            return;
        }

        stockNotificationList.innerHTML = items.map((item) => {
            const notificationType = String(item?.notification_type || 'stock').toLowerCase();
            const title = escapeHtml(item?.title || 'Alerta de stock');
            const message = escapeHtml(item?.message || 'Stock mínimo alcanzado.');
            let severity = String(item?.severity || 'warning').toLowerCase() === 'critical' ? 'critical' : 'warning';
            let iconClass = severity === 'critical' ? 'bx bxs-error-circle' : 'bx bxs-bell-ring';

            if (notificationType === 'ticket') {
                severity = 'ticket';
                iconClass = 'bx bxs-message-dots';
            }

            return `
                <li class="vx-notify-item is-${severity}">
                    <span class="vx-notify-item-icon">
                        <i class="${iconClass}"></i>
                    </span>
                    <div class="vx-notify-item-body">
                        <strong>${title}</strong>
                        <small>${message}</small>
                    </div>
                </li>
            `;
        }).join('');
    };

    const applyStockNotifications = (payload) => {
        const items = Array.isArray(payload?.items) ? payload.items : [];
        const derivedStockCount = items.filter((item) => String(item?.notification_type || 'stock').toLowerCase() === 'stock').length;
        const derivedTicketCount = items.filter((item) => String(item?.notification_type || '').toLowerCase() === 'ticket').length;
        const countFromPayload = normalizePositiveInt(payload?.count ?? items.length);
        const countStock = normalizePositiveInt(payload?.count_stock ?? derivedStockCount);
        const countTickets = normalizePositiveInt(payload?.count_tickets ?? derivedTicketCount);
        const normalizedCount = Math.max(countFromPayload, countStock + countTickets, items.length);

        if (stockNotificationBadge) {
            if (normalizedCount <= 0) {
                stockNotificationBadge.textContent = '0';
                stockNotificationBadge.classList.add('d-none');
            } else {
                stockNotificationBadge.textContent = badgeText(normalizedCount);
                stockNotificationBadge.classList.remove('d-none');
            }
        }

        if (stockNotificationCountLabel) {
            stockNotificationCountLabel.textContent = `${normalizedCount} notificación(es)`;
        }

        if (stockNotificationMarkReadButton && stockNotificationMarkReadButton.dataset.processing !== '1') {
            stockNotificationMarkReadButton.disabled = normalizedCount <= 0;
        }

        renderStockNotificationItems(items);

        return {
            count: normalizedCount,
            countStock,
            countTickets,
            items,
        };
    };

    const stockFingerprint = (items) => {
        if (!Array.isArray(items) || items.length === 0) {
            return '';
        }

        return items
            .map((item) => `${item?.id || 'item'}:${item?.stock_actual ?? 0}:${item?.stock_minimo ?? 0}`)
            .join('|');
    };

    const ticketFingerprint = (items) => {
        if (!Array.isArray(items) || items.length === 0) {
            return '';
        }

        return items
            .map((item) => String(item?.ticket_id ?? item?.id ?? 'ticket'))
            .join('|');
    };

    const dispatchSileoToast = (type, title, description, extra = {}) => {
        if (!window.sileo || typeof window.sileo[type] !== 'function') {
            return false;
        }

        window.sileo[type]({
            title,
            description,
            position: 'top-center',
            ...extra,
        });

        return true;
    };

    const showActionNotification = ({title, description, buttonTitle, onClick}) => {
        return dispatchSileoToast('action', title, description, {
            duration: 9000,
            button: buttonTitle && typeof onClick === 'function'
                ? {title: buttonTitle, onClick}
                : undefined,
        });
    };

    const maybeShowStockPopup = (items) => {
        const stockItems = Array.isArray(items)
            ? items.filter((item) => String(item?.notification_type || 'stock').toLowerCase() === 'stock')
            : [];

        if (stockItems.length === 0) {
            return;
        }

        const fingerprint = stockFingerprint(stockItems);
        if (fingerprint === '') {
            return;
        }

        let alreadyShownFingerprint = '';
        try {
            alreadyShownFingerprint = window.sessionStorage.getItem(stockNotificationStorageKey) || '';
        } catch (_) {
            alreadyShownFingerprint = '';
        }

        if (alreadyShownFingerprint === fingerprint) {
            return;
        }

        try {
            window.sessionStorage.setItem(stockNotificationStorageKey, fingerprint);
        } catch (_) {
            // Si el navegador bloquea storage, seguimos mostrando el popup una vez por carga.
        }

        const preview = stockItems
            .slice(0, 3)
            .map((item) => `${item?.title || 'Producto'} (${item?.message || ''})`)
            .join(' · ');
        const moreCount = Math.max(0, stockItems.length - 3);
        const extra = moreCount > 0 ? ` +${moreCount} alerta(s) más.` : '';
        const description = `Tienes productos en o por debajo del stock mínimo.${preview ? ` ${preview}.` : ''}${extra}`;

        const actionShown = showActionNotification({
            title: 'Alerta de stock mínimo',
            description,
            buttonTitle: 'Revisar inventario',
            onClick: () => {
                if (stockNotificationInventoryUrl) {
                    window.location.href = stockNotificationInventoryUrl;
                }
            },
        });

        if (!actionShown) {
            const accepted = window.confirm(`${description} ¿Deseas revisar inventario ahora?`);
            if (accepted && stockNotificationInventoryUrl) {
                window.location.href = stockNotificationInventoryUrl;
            }
        }
    };

    const maybeShowTicketPopup = (items) => {
        if (stockNotificationScope !== 'superadmin') {
            return;
        }

        const ticketItems = Array.isArray(items)
            ? items.filter((item) => String(item?.notification_type || '').toLowerCase() === 'ticket')
            : [];

        if (ticketItems.length === 0) {
            return;
        }

        const fingerprint = ticketFingerprint(ticketItems);
        if (fingerprint === '') {
            return;
        }

        let alreadyShownFingerprint = '';
        try {
            alreadyShownFingerprint = window.sessionStorage.getItem(ticketNotificationStorageKey) || '';
        } catch (_) {
            alreadyShownFingerprint = '';
        }

        if (alreadyShownFingerprint === fingerprint) {
            return;
        }

        try {
            window.sessionStorage.setItem(ticketNotificationStorageKey, fingerprint);
        } catch (_) {
            // Si sessionStorage no está disponible, no bloqueamos el popup.
        }

        const preview = ticketItems
            .slice(0, 3)
            .map((item) => `${item?.title || 'Ticket'} (${item?.message || ''})`)
            .join(' · ');
        const moreCount = Math.max(0, ticketItems.length - 3);
        const extra = moreCount > 0 ? ` +${moreCount} ticket(s) más.` : '';
        const description = `Tienes tickets activos que requieren revisión.${preview ? ` ${preview}.` : ''}${extra}`;

        const actionShown = showActionNotification({
            title: 'Nuevo ticket de soporte',
            description,
            buttonTitle: 'Ir a soporte',
            onClick: () => {
                if (stockNotificationSupportUrl) {
                    window.location.href = stockNotificationSupportUrl;
                }
            },
        });

        if (!actionShown) {
            const accepted = window.confirm(`${description} ¿Deseas ir a soporte ahora?`);
            if (accepted && stockNotificationSupportUrl) {
                window.location.href = stockNotificationSupportUrl;
            }
        }
    };

    const showStockToast = (newCount, totalCount) => {
        dispatchSileoToast('warning', `Stock bajo: +${newCount}`, `Alertas de stock activas: ${totalCount}`);
    };

    const showTicketToast = (newCount, totalCount) => {
        dispatchSileoToast('info', `Tickets: +${newCount}`, `Tickets activos: ${totalCount}`);
    };

    const showNotificationActionToast = (icon, title, text) => {
        const palette = {
            success: 'success',
            error: 'error',
            warning: 'warning',
            info: 'info',
        };
        const type = palette[String(icon || '').toLowerCase()] || 'info';
        const shown = dispatchSileoToast(type, title, text);
        if (!shown && text) {
            window.alert(text);
        }
    };

    if (stockNotificationToggle) {
        const initialPayload = window.__veltrixStockNotifications || {};
        const appliedInitial = applyStockNotifications(initialPayload);
        stockOnlyNotificationsCount = appliedInitial.countStock;
        ticketOnlyNotificationsCount = appliedInitial.countTickets;

        if (appliedInitial.countStock > 0) {
            maybeShowStockPopup(appliedInitial.items);
        }
        if (appliedInitial.countTickets > 0) {
            maybeShowTicketPopup(appliedInitial.items);
        }

        if (stockNotificationMarkReadButton && stockNotificationMarkReadUrl) {
            stockNotificationMarkReadButton.addEventListener('click', async (event) => {
                event.preventDefault();

                if (stockNotificationMarkReadButton.disabled) {
                    return;
                }

                const csrfToken = getCsrfToken();
                if (!csrfToken) {
                    showNotificationActionToast('error', 'No se pudo marcar', 'No se encontró token CSRF.');
                    return;
                }

                stockNotificationMarkReadButton.dataset.processing = '1';
                stockNotificationMarkReadButton.disabled = true;

                try {
                    const response = await fetch(stockNotificationMarkReadUrl, {
                        method: 'POST',
                        credentials: 'same-origin',
                        headers: {
                            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                            'X-Requested-With': 'XMLHttpRequest',
                        },
                        body: new URLSearchParams({
                            _token: csrfToken,
                            scope: stockNotificationScope,
                        }).toString(),
                    });

                    const payload = await response.json().catch(() => ({}));
                    if (!response.ok || payload?.ok !== true) {
                        const message = String(payload?.message || 'No se pudieron actualizar las notificaciones.');
                        showNotificationActionToast('error', 'No se pudo marcar', message);
                        return;
                    }

                    const applied = applyStockNotifications(payload);
                    stockOnlyNotificationsCount = applied.countStock;
                    ticketOnlyNotificationsCount = applied.countTickets;
                    stockNotificationsHasPolled = true;

                    try {
                        window.sessionStorage.removeItem(stockNotificationStorageKey);
                        window.sessionStorage.removeItem(ticketNotificationStorageKey);
                    } catch (_) {
                        // Si sessionStorage no está disponible, continuamos.
                    }

                    const markedCount = normalizePositiveInt(payload?.marked ?? 0);
                    if (markedCount > 0) {
                        showNotificationActionToast('success', 'Listo', `${markedCount} notificación(es) marcadas como leídas.`);
                    } else {
                        showNotificationActionToast('info', 'Sin cambios', 'No había notificaciones pendientes.');
                    }
                } catch (_) {
                    showNotificationActionToast('error', 'No se pudo marcar', 'Error de conexión. Intenta nuevamente.');
                } finally {
                    delete stockNotificationMarkReadButton.dataset.processing;
                    stockNotificationMarkReadButton.disabled = (stockOnlyNotificationsCount + ticketOnlyNotificationsCount) <= 0;
                }
            });
        }

        const refreshStockNotifications = async () => {
            if (!stockNotificationEndpoint) {
                return;
            }

            try {
                const response = await fetch(stockNotificationEndpoint, {
                    method: 'GET',
                    credentials: 'same-origin',
                    cache: 'no-store',
                    headers: {
                        'X-Requested-With': 'XMLHttpRequest',
                    },
                });

                if (!response.ok) {
                    return;
                }

                const payload = await response.json();
                const previousStockCount = stockOnlyNotificationsCount;
                const previousTicketCount = ticketOnlyNotificationsCount;
                const applied = applyStockNotifications(payload);
                stockOnlyNotificationsCount = applied.countStock;
                ticketOnlyNotificationsCount = applied.countTickets;

                if (stockNotificationsHasPolled && applied.countStock > previousStockCount) {
                    showStockToast(applied.countStock - previousStockCount, applied.countStock);
                    maybeShowStockPopup(applied.items);
                }

                if (stockNotificationsHasPolled && applied.countTickets > previousTicketCount) {
                    showTicketToast(applied.countTickets - previousTicketCount, applied.countTickets);
                    maybeShowTicketPopup(applied.items);
                }

                stockNotificationsHasPolled = true;
            } catch (_) {
                // Evita bloquear la UI si falla la consulta de notificaciones.
            }
        };

        refreshStockNotifications();
        window.setInterval(refreshStockNotifications, 18000);
    }

    const initTooltips = () => {
        if (!window.bootstrap?.Tooltip) {
            return;
        }

        document.querySelectorAll('[data-vx-tooltip]').forEach((element) => {
            if (!(element instanceof HTMLElement)) {
                return;
            }

            if (element.dataset.vxTooltipInit === '1') {
                return;
            }

            const message = String(element.getAttribute('data-vx-tooltip') || '').trim();
            if (message === '') {
                return;
            }

            element.setAttribute('title', message);
            new window.bootstrap.Tooltip(element, {
                title: message,
                trigger: 'hover focus',
                container: 'body',
            });
            element.dataset.vxTooltipInit = '1';
        });
    };

    initTooltips();
});
