/**
 * AXIS Enterprise UI — core shell (sidebar, lazy vendors, confirms)
 * Heavy libraries load only when the page needs them.
 */
(function () {
    'use strict';

    const CDN = 'https://cdn.jsdelivr.net/npm';
    const DT = 'https://cdn.datatables.net/1.13.7';

    const loaded = new Set();
    let voucherDimensionPickerCounter = 0;
    let voucherPartyPickerCounter = 0;
    let voucherAccountPickerCounter = 0;
    let salaryComponentAccountPickerCounter = 0;

    const VOUCHER_LINE_PICKER_Z = 1200;

    function positionVoucherLinePickerMenu(toggle, menu, minWidth) {
        const rect = toggle.getBoundingClientRect();
        const gap = 4;
        const padding = 8;
        const menuWidth = menu.offsetWidth || minWidth || 320;
        const menuHeight = menu.offsetHeight || 300;

        let top = rect.bottom + gap;
        let left = rect.left;

        const card = toggle.closest('.voucher-journal-card') || toggle.closest('.card');
        const footer = card?.querySelector('.card-footer');
        const footerRect = footer?.getBoundingClientRect();
        const overlapsFooter = footerRect
            && top < footerRect.bottom - gap
            && (top + menuHeight) > footerRect.top;

        if (overlapsFooter || top + menuHeight > window.innerHeight - padding) {
            top = rect.top - menuHeight - gap;
        }
        if (left + menuWidth > window.innerWidth - padding) {
            left = window.innerWidth - menuWidth - padding;
        }
        if (left < padding) {
            left = padding;
        }
        if (top < padding) {
            top = padding;
        }

        menu.style.position = 'fixed';
        menu.style.top = `${top}px`;
        menu.style.left = `${left}px`;
        menu.style.zIndex = String(VOUCHER_LINE_PICKER_Z);
        menu.style.minWidth = `${Math.max(rect.width, minWidth || 240)}px`;
    }

    function closeVoucherLinePickerMenuInstance(menu, picker, toggleSelector, portalClass) {
        if (!menu || menu.classList.contains('d-none')) {
            return;
        }

        menu.classList.add('d-none');
        picker?.querySelector(toggleSelector)?.setAttribute('aria-expanded', 'false');
        menu.style.position = '';
        menu.style.top = '';
        menu.style.left = '';
        menu.style.zIndex = '';
        menu.style.minWidth = '';
        menu.classList.remove(portalClass);
        if (picker && menu.parentElement !== picker) {
            picker.appendChild(menu);
        }
    }

    function closeAllVoucherLinePickers() {
        document.querySelectorAll('.voucher-dimension-picker-menu:not(.d-none)').forEach((menu) => {
            const pickerId = menu.dataset.vdPickerId;
            const picker = document.querySelector(`.voucher-dimension-picker[data-vd-picker-id="${pickerId}"]`);
            closeVoucherLinePickerMenuInstance(menu, picker, '.voucher-dimension-picker-toggle', 'voucher-dimension-picker-menu--portal');
        });
        document.querySelectorAll('.voucher-party-picker-menu:not(.d-none)').forEach((menu) => {
            const pickerId = menu.dataset.vpPickerId;
            const picker = document.querySelector(`.voucher-party-picker[data-vp-picker-id="${pickerId}"]`);
            closeVoucherLinePickerMenuInstance(menu, picker, '.voucher-party-picker-toggle', 'voucher-party-picker-menu--portal');
        });
        document.querySelectorAll('.voucher-account-picker-menu:not(.d-none)').forEach((menu) => {
            const scPickerId = menu.dataset.scPickerId;
            if (scPickerId) {
                const picker = document.querySelector(`.sc-account-picker[data-sc-picker-id="${scPickerId}"]`);
                closeVoucherLinePickerMenuInstance(menu, picker, '.voucher-account-picker-toggle', 'voucher-account-picker-menu--portal');
                return;
            }

            const pickerId = menu.dataset.vaPickerId;
            const picker = document.querySelector(`.voucher-account-picker[data-va-picker-id="${pickerId}"]`);
            closeVoucherLinePickerMenuInstance(menu, picker, '.voucher-account-picker-toggle', 'voucher-account-picker-menu--portal');
        });
    }

    window.axisCloseAllVoucherLinePickers = closeAllVoucherLinePickers;

    function escapeHtml(value) {
        return String(value ?? '')
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
    }

    function readVoucherJsonScript(scriptId, fallback) {
        const el = document.getElementById(scriptId);
        if (!el?.textContent?.trim()) {
            return fallback;
        }

        try {
            return JSON.parse(el.textContent);
        } catch (error) {
            return fallback;
        }
    }

    function repositionAllVoucherLinePickerMenus() {
        document.querySelectorAll('.voucher-dimension-picker-menu--portal:not(.d-none)').forEach((menu) => {
            const pickerId = menu.dataset.vdPickerId;
            const picker = document.querySelector(`.voucher-dimension-picker[data-vd-picker-id="${pickerId}"]`);
            const toggle = picker?.querySelector('.voucher-dimension-picker-toggle');
            if (toggle) {
                positionVoucherLinePickerMenu(toggle, menu, 280);
            }
        });
        document.querySelectorAll('.voucher-party-picker-menu--portal:not(.d-none)').forEach((menu) => {
            const pickerId = menu.dataset.vpPickerId;
            const picker = document.querySelector(`.voucher-party-picker[data-vp-picker-id="${pickerId}"]`);
            const toggle = picker?.querySelector('.voucher-party-picker-toggle');
            if (toggle) {
                positionVoucherLinePickerMenu(toggle, menu, 560);
            }
        });
        document.querySelectorAll('.voucher-account-picker-menu--portal:not(.d-none)').forEach((menu) => {
            const scPickerId = menu.dataset.scPickerId;
            const picker = scPickerId
                ? document.querySelector(`.sc-account-picker[data-sc-picker-id="${scPickerId}"]`)
                : document.querySelector(`.voucher-account-picker[data-va-picker-id="${menu.dataset.vaPickerId}"]`);
            const toggle = picker?.querySelector('.voucher-account-picker-toggle');
            if (toggle) {
                positionVoucherLinePickerMenu(toggle, menu, 560);
            }
        });
    }

    function registerPickerFocusGuard() {
        if (document.documentElement.dataset.axisPickerFocusGuard === '1') {
            return;
        }

        document.documentElement.dataset.axisPickerFocusGuard = '1';
        document.addEventListener('focusin', (event) => {
            if (event.target.closest(
                '.voucher-account-picker-menu--portal, .voucher-party-picker-menu--portal, .voucher-dimension-picker-menu--portal, .coa-parent-picker-menu--portal',
            )) {
                event.stopImmediatePropagation();
            }
        }, true);
    }

    function registerVoucherPickerGlobalListeners() {
        registerPickerFocusGuard();

        if (document.documentElement.dataset.axisPickerClickListeners === '1') {
            return;
        }

        document.documentElement.dataset.axisPickerClickListeners = '1';

        document.addEventListener('click', (event) => {
            if (event.target.closest('.voucher-dimension-picker, .voucher-party-picker, .voucher-account-picker, .sc-account-picker, [data-coa-parent-picker]')
                || event.target.closest('.voucher-dimension-picker-menu--portal, .voucher-party-picker-menu--portal, .voucher-account-picker-menu--portal, .coa-parent-picker-menu--portal, .coa-parent-picker-menu')) {
                return;
            }
            closeAllVoucherLinePickers();
            if (typeof window.axisCloseAllCoaParentPickers === 'function') {
                window.axisCloseAllCoaParentPickers();
            }
        });

        window.addEventListener('scroll', repositionAllVoucherLinePickerMenus, true);
        window.addEventListener('resize', repositionAllVoucherLinePickerMenus);

        const form = document.getElementById('voucherForm');
        if (form) {
            form.dataset.voucherPickerGlobalListeners = '1';
        }
    }

    function loadScript(src) {
        if (loaded.has(src)) {
            return Promise.resolve();
        }
        return new Promise((resolve, reject) => {
            const el = document.createElement('script');
            el.src = src;
            el.defer = true;
            el.onload = () => { loaded.add(src); resolve(); };
            el.onerror = reject;
            document.body.appendChild(el);
        });
    }

    function loadStyle(href) {
        if (document.querySelector(`link[href="${href}"]`)) {
            return;
        }
        const el = document.createElement('link');
        el.rel = 'stylesheet';
        el.href = href;
        document.head.appendChild(el);
    }

    // ── Sidebar ───────────────────────────────────────────────────────────
    const sidebar = document.getElementById('sidebar');
    const backdrop = document.getElementById('sidebar-backdrop');
    const topbar = document.getElementById('topbar');
    const topnav = document.getElementById('topnav');
    const openWindowsBar = document.getElementById('open-windows');
    const openWindowsList = document.getElementById('openWindowsList');
    const main = document.getElementById('main');
    const toggle = document.getElementById('sidebarToggle');

    if (sidebar && toggle) {
        let collapsed = localStorage.getItem('sidebarCollapsed') === 'true';

        function closeMobile() {
            sidebar.classList.remove('mobile-open');
            backdrop?.classList.remove('show');
            document.body.style.overflow = '';
        }

        function applySidebar() {
            if (window.innerWidth <= 768) {
                sidebar.classList.remove('collapsed');
                topbar?.classList.remove('expanded');
                topnav?.classList.remove('expanded');
                main?.classList.remove('expanded');
                return;
            }
            closeMobile();
            const isCollapsed = collapsed;
            sidebar.classList.toggle('collapsed', isCollapsed);
            topbar?.classList.toggle('expanded', isCollapsed);
            topnav?.classList.toggle('expanded', isCollapsed);
            main?.classList.toggle('expanded', isCollapsed);
        }

        toggle.addEventListener('click', () => {
            if (window.innerWidth <= 768) {
                const open = sidebar.classList.toggle('mobile-open');
                backdrop?.classList.toggle('show', open);
                document.body.style.overflow = open ? 'hidden' : '';
            } else {
                collapsed = !collapsed;
                localStorage.setItem('sidebarCollapsed', collapsed);
                applySidebar();
            }
        });

        backdrop?.addEventListener('click', closeMobile);
        window.addEventListener('resize', applySidebar);
        applySidebar();
    }

    // ── Top navigation dropdowns (escape overflow clipping) ─────────────────
    function axisPopperFixed(defaultBsPopperConfig) {
        const config = { ...defaultBsPopperConfig, strategy: 'fixed' };
        config.modifiers = [...(config.modifiers || [])];
        config.modifiers.push({
            name: 'preventOverflow',
            options: { boundary: 'viewport', padding: 8 },
        });
        return config;
    }

    function preserveTopnavScroll(scroller) {
        if (!scroller) {
            return null;
        }
        const scrollLeft = scroller.scrollLeft;
        requestAnimationFrame(() => {
            scroller.scrollLeft = scrollLeft;
        });
        requestAnimationFrame(() => {
            requestAnimationFrame(() => {
                scroller.scrollLeft = scrollLeft;
            });
        });
        return scrollLeft;
    }

    function scrollTopnavToggleIntoView(toggle, scroller) {
        if (!toggle || !scroller) {
            return;
        }

        const scrollerRect = scroller.getBoundingClientRect();
        const toggleRect = toggle.getBoundingClientRect();
        const padding = 8;

        if (toggleRect.left < scrollerRect.left + padding) {
            scroller.scrollLeft -= scrollerRect.left + padding - toggleRect.left;
        } else if (toggleRect.right > scrollerRect.right - padding) {
            scroller.scrollLeft += toggleRect.right - (scrollerRect.right - padding);
        }
    }

    function initTopnavDropdowns() {
        if (!topnav) {
            return;
        }

        const scroller = topnav.querySelector('.topnav-scroll');

        topnav.querySelectorAll('.topnav-item > .topnav-link[data-bs-toggle="dropdown"]').forEach((toggle) => {
            bootstrap.Dropdown.getOrCreateInstance(toggle, {
                popperConfig: axisPopperFixed,
                autoClose: 'outside',
            });

            toggle.addEventListener('pointerdown', () => {
                if (scroller) {
                    scroller.dataset.axisScrollLeft = String(scroller.scrollLeft);
                }
            });

            toggle.addEventListener('show.bs.dropdown', () => {
                if (!scroller) {
                    return;
                }
                const saved = Number(scroller.dataset.axisScrollLeft ?? scroller.scrollLeft);
                scroller.scrollLeft = saved;
                scrollTopnavToggleIntoView(toggle, scroller);
                scroller.dataset.axisScrollLeft = String(scroller.scrollLeft);
            });

            toggle.addEventListener('shown.bs.dropdown', () => {
                if (!scroller) {
                    return;
                }
                const saved = Number(scroller.dataset.axisScrollLeft ?? scroller.scrollLeft);
                preserveTopnavScroll(scroller);
                scroller.scrollLeft = saved;
            });
        });
    }

    function initTopbarUserMenu() {
        const toggle = document.querySelector('.topbar-user-toggle[data-bs-toggle="dropdown"]');
        if (!toggle) {
            return;
        }

        bootstrap.Dropdown.getOrCreateInstance(toggle, {
            popperConfig: axisPopperFixed,
        });
    }

    function initTopnavInlineSubmenus() {
        if (!topnav) {
            return;
        }

        topnav.querySelectorAll('.topnav-inline-toggle').forEach((toggle) => {
            toggle.addEventListener('click', (event) => {
                event.stopPropagation();
            });
        });
    }

    function initShellMenus() {
        if (typeof bootstrap === 'undefined') {
            window.addEventListener('load', initShellMenus, { once: true });
            return;
        }
        initTopnavDropdowns();
        initTopnavInlineSubmenus();
        initTopbarUserMenu();
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initShellMenus);
    } else {
        initShellMenus();
    }

    // ── Open windows tab bar ────────────────────────────────────────────────
    function initOpenWindows() {
        if (!openWindowsBar || !openWindowsList) {
            return;
        }

        const userId = document.querySelector('meta[name="axis-user-id"]')?.content || '0';
        const companyId = document.querySelector('meta[name="axis-company-id"]')?.content || '0';
        const storageKey = `axis.openWindows.${userId}.${companyId}`;
        const suppressedKey = `axis.openWindows.suppressed.${userId}.${companyId}`;
        const lastPageKey = `axis.openWindows.lastPage.${userId}.${companyId}`;
        const maxTabs = 7;

        function loadSuppressed() {
            try {
                const raw = sessionStorage.getItem(suppressedKey);
                const parsed = raw ? JSON.parse(raw) : [];
                return new Set(Array.isArray(parsed) ? parsed : []);
            } catch {
                return new Set();
            }
        }

        function saveSuppressed(set) {
            sessionStorage.setItem(suppressedKey, JSON.stringify([...set]));
        }

        function suppressPath(id) {
            const suppressed = loadSuppressed();
            suppressed.add(id);
            saveSuppressed(suppressed);
        }

        function releaseSuppressed(id) {
            const suppressed = loadSuppressed();
            if (!suppressed.delete(id)) {
                return;
            }
            saveSuppressed(suppressed);
        }

        function currentId() {
            return window.location.pathname + window.location.search;
        }

        function currentTitle() {
            return document.querySelector('meta[name="axis-window-title"]')?.content?.trim()
                || document.title.split('—')[0]?.trim()
                || 'Page';
        }

        function loadWindows() {
            try {
                const raw = sessionStorage.getItem(storageKey);
                const parsed = raw ? JSON.parse(raw) : [];
                return Array.isArray(parsed) ? parsed : [];
            } catch {
                return [];
            }
        }

        function saveWindows(windows) {
            sessionStorage.setItem(storageKey, JSON.stringify(windows));
        }

        function registerCurrent() {
            const id = currentId();
            const title = currentTitle();
            const url = id;
            let windows = loadWindows();
            const suppressed = loadSuppressed();
            const lastPage = sessionStorage.getItem(lastPageKey);

            if (suppressed.has(id) && lastPage === id) {
                return windows;
            }

            if (suppressed.has(id)) {
                releaseSuppressed(id);
            }

            const index = windows.findIndex((item) => item.id === id);

            if (index >= 0) {
                const existing = windows.splice(index, 1)[0];
                existing.title = title;
                existing.url = url;
                windows.push(existing);
            } else {
                windows.push({ id, title, url });
            }

            if (windows.length > maxTabs) {
                windows = windows.slice(windows.length - maxTabs);
            }

            saveWindows(windows);
            sessionStorage.setItem(lastPageKey, id);
            return windows;
        }

        function render(windows) {
            const activeId = currentId();
            openWindowsList.innerHTML = '';

            windows.forEach((item) => {
                const tab = document.createElement('a');
                tab.className = 'open-window-tab' + (item.id === activeId ? ' active' : '');
                tab.href = item.url;
                tab.title = item.title;

                const label = document.createElement('span');
                label.className = 'open-window-label';
                label.textContent = item.title;

                const closeBtn = document.createElement('button');
                closeBtn.type = 'button';
                closeBtn.className = 'open-window-close';
                closeBtn.setAttribute('aria-label', `Close ${item.title}`);
                closeBtn.innerHTML = '&times;';
                closeBtn.addEventListener('click', (event) => {
                    event.preventDefault();
                    event.stopPropagation();
                    closeTab(item.id);
                });

                tab.appendChild(label);
                tab.appendChild(closeBtn);
                tab.addEventListener('click', (event) => {
                    if (event.target === closeBtn) {
                        return;
                    }
                });

                openWindowsList.appendChild(tab);
            });

            if (windows.length > 0) {
                openWindowsBar.hidden = false;
                const activeTab = openWindowsList.querySelector('.open-window-tab.active');
                activeTab?.scrollIntoView({ inline: 'nearest', block: 'nearest', behavior: 'smooth' });
            } else {
                openWindowsBar.hidden = true;
            }
        }

        function closeTab(id) {
            let windows = loadWindows();
            const index = windows.findIndex((item) => item.id === id);
            if (index < 0) {
                return;
            }

            const isActive = id === currentId();
            windows.splice(index, 1);
            saveWindows(windows);

            if (isActive) {
                suppressPath(id);
            }

            if (windows.length === 0) {
                render(windows);
                return;
            }

            if (isActive) {
                const next = windows[Math.min(index, windows.length - 1)];
                window.location.href = next.url;
                return;
            }

            render(windows);
        }

        const windows = registerCurrent();
        render(windows);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initOpenWindows);
    } else {
        initOpenWindows();
    }

    // ── Confirm dialogs (lazy SweetAlert2) ──────────────────────────────────
    async function initConfirms() {
        const triggers = document.querySelectorAll('[data-confirm]');
        if (!triggers.length) return;

        loadStyle(`${CDN}/sweetalert2@11/dist/sweetalert2.min.css`);
        await loadScript(`${CDN}/sweetalert2@11`);

        triggers.forEach((el) => {
            el.addEventListener('click', function (e) {
                e.preventDefault();
                const formSel = this.dataset.form;
                const form = formSel ? document.querySelector(formSel) : this.closest('form');

                Swal.fire({
                    title: this.dataset.confirmTitle || 'Confirm',
                    text: this.dataset.confirmText || 'Are you sure?',
                    icon: this.dataset.confirmIcon || 'warning',
                    showCancelButton: true,
                    confirmButtonColor: this.dataset.confirmColor || '#2563eb',
                    cancelButtonColor: '#64748b',
                    confirmButtonText: this.dataset.confirmBtn || 'Confirm',
                }).then((r) => { if (r.isConfirmed && form) form.submit(); });
            });
        });
    }

    // ── Form plugins (lazy jQuery + Select2 + Flatpickr) ────────────────────
    function initReportDatepickers() {
        document.querySelectorAll('.axis-report-datepicker').forEach((el) => {
            if (el._flatpickr) {
                return;
            }

            const picker = flatpickr(el, {
                dateFormat: 'Y-m-d',
                altInput: true,
                altFormat: 'd-m-Y',
                altInputClass: 'form-control',
                allowInput: true,
                disableMobile: true,
                monthSelectorType: 'dropdown',
                shorthandCurrentMonth: true,
                onReady(_selectedDates, _dateStr, instance) {
                    instance.calendarContainer.classList.add('axis-report-calendar');
                },
            });

            const field = el.closest('.axis-date-field');
            field?.querySelectorAll('[data-axis-date-open]').forEach((trigger) => {
                trigger.addEventListener('click', () => picker.open());
            });
        });
    }

    async function initFormPlugins() {
        const needsSelect2 = document.querySelector('.select2');
        const needsDate = document.querySelector('.datepicker');
        const needsReportDate = document.querySelector('.axis-report-datepicker');
        if (!needsSelect2 && !needsDate && !needsReportDate) return;

        if (!window.jQuery) {
            await loadScript('https://code.jquery.com/jquery-3.7.1.min.js');
        }

        if (needsSelect2) {
            loadStyle(`${CDN}/select2@4.1.0-rc.0/dist/css/select2.min.css`);
            loadStyle(`${CDN}/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css`);
            await loadScript(`${CDN}/select2@4.1.0-rc.0/dist/js/select2.min.js`);
            window.jQuery('.select2').select2({ theme: 'bootstrap-5', width: '100%' });
        }

        if (needsDate || needsReportDate) {
            loadStyle(`${CDN}/flatpickr/dist/flatpickr.min.css`);
            await loadScript(`${CDN}/flatpickr`);

            if (needsDate) {
                document.querySelectorAll('.datepicker').forEach((el) => {
                    flatpickr(el, { dateFormat: 'd/m/Y', allowInput: true });
                });
            }

            if (needsReportDate) {
                initReportDatepickers();
            }
        }

        if (window.jQuery) {
            window.jQuery.ajaxSetup({
                headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content },
            });
        }
    }

    // ── DataTables (lazy, opt-in via data-axis-datatable) ───────────────────
    async function initDataTables() {
        const tables = document.querySelectorAll('[data-axis-datatable]');
        if (!tables.length) return;

        loadStyle(`${DT}/css/dataTables.bootstrap5.min.css`);
        if (!window.jQuery) {
            await loadScript('https://code.jquery.com/jquery-3.7.1.min.js');
        }
        await loadScript(`${DT}/js/jquery.dataTables.min.js`);
        await loadScript(`${DT}/js/dataTables.bootstrap5.min.js`);

        tables.forEach((table) => {
            const opts = table.dataset.axisDatatable ? JSON.parse(table.dataset.axisDatatable) : {};
            window.jQuery(table).DataTable(Object.assign({
                pageLength: 25,
                deferRender: true,
                responsive: true,
            }, opts));
        });
    }

    // ── User profile modal (photo preview) ──────────────────────────────────
    function initUserProfileModal() {
        const modal = document.getElementById('userProfileModal');
        if (!modal) {
            return;
        }

        const preview = document.getElementById('profilePhotoPreview');
        const fileInput = document.getElementById('profileAvatarInput');
        const removeBtn = document.getElementById('profileRemovePhotoBtn');
        const removeField = document.getElementById('profileRemoveAvatar');
        const defaultPreview = preview?.getAttribute('src') || '';
        const hasCustomAvatar = () => modal.dataset.hasCustomAvatar === '1';

        const syncRemoveButton = () => {
            if (!removeBtn) {
                return;
            }
            const willRemove = removeField?.value === '1';
            const hasFile = !!fileInput?.files?.length;
            removeBtn.disabled = willRemove || (!hasCustomAvatar() && !hasFile);
        };

        fileInput?.addEventListener('change', () => {
            const file = fileInput.files?.[0];
            if (!file || !preview) {
                return;
            }
            preview.src = URL.createObjectURL(file);
            if (removeField) {
                removeField.value = '0';
            }
            syncRemoveButton();
        });

        removeBtn?.addEventListener('click', () => {
            if (fileInput) {
                fileInput.value = '';
            }
            if (preview) {
                preview.src = defaultPreview;
            }
            if (removeField) {
                removeField.value = '1';
            }
            modal.dataset.hasCustomAvatar = '0';
            syncRemoveButton();
        });

        modal.addEventListener('hidden.bs.modal', () => {
            if (fileInput) {
                fileInput.value = '';
            }
            if (removeField) {
                removeField.value = '0';
            }
            if (preview) {
                preview.src = defaultPreview;
            }
            syncRemoveButton();
        });

        syncRemoveButton();
    }

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

        let dimensionTrees = readVoucherJsonScript('voucherDimensionTreesData', {});

        const labelMap = {};
        const walkTree = (nodes, fn) => {
            (nodes || []).forEach((node) => {
                fn(node);
                if (node.children && node.children.length) {
                    walkTree(node.children, fn);
                }
            });
        };

        Object.values(dimensionTrees).forEach((tree) => walkTree(tree, (node) => {
            if (node.id) {
                labelMap[String(node.id)] = node.name;
            }
        }));

        const expandedByPicker = new WeakMap();

        const nodeMatches = (node, term) => {
            if (!term) {
                return true;
            }

            const haystack = `${node.name || ''} ${node.code || ''}`.toLowerCase();
            return haystack.indexOf(term) !== -1;
        };

        const subtreeMatches = (node, term) => {
            if (!term) {
                return true;
            }

            if (nodeMatches(node, term)) {
                return true;
            }

            return (node.children || []).some((child) => subtreeMatches(child, term));
        };

        const renderTree = (picker, treeEl, emptyEl, searchInput, slot) => {
            const tree = dimensionTrees[slot] || [];
            const expanded = expandedByPicker.get(picker) || new Set();
            const term = (searchInput?.value || '').trim().toLowerCase();
            const selectedId = picker.querySelector('.voucher-dimension-input')?.value || '';

            const renderNodes = (nodes, depth) => nodes.map((node) => {
                if (term && !subtreeMatches(node, term)) {
                    return '';
                }

                const id = String(node.id);
                const hasChildren = !!(node.children && node.children.length);
                const childHtml = hasChildren && expanded.has(id)
                    ? renderNodes(node.children, depth + 1)
                    : '';

                return `
                    <div class="voucher-dimension-picker-item" style="padding-left:${depth * 16}px">
                        <button type="button" class="voucher-dimension-picker-toggle-btn ${hasChildren ? '' : 'is-hidden'}" data-vd-expand="${id}" aria-label="Expand">
                            <i class="bi ${expanded.has(id) ? 'bi-chevron-down' : 'bi-chevron-right'}" style="font-size:11px"></i>
                        </button>
                        <button type="button"
                                class="voucher-dimension-picker-option ${selectedId === id ? 'is-selected' : ''}"
                                data-vd-select="${id}">
                            <span>${node.name || ''}</span>
                            ${node.code ? `<span class="voucher-dimension-picker-option-code">${node.code}</span>` : ''}
                        </button>
                    </div>
                    ${hasChildren ? `<div class="${expanded.has(id) ? '' : 'd-none'}" data-vd-children="${id}">${childHtml}</div>` : ''}
                `;
            }).join('');

            const html = renderNodes(tree, 0);
            treeEl.innerHTML = html;
            emptyEl?.classList.toggle('d-none', html.trim() !== '');
        };

        const syncPickerLabel = (picker) => {
            const input = picker.querySelector('.voucher-dimension-input');
            const label = picker.querySelector('.voucher-dimension-picker-label');
            if (!label) {
                return;
            }

            const value = input?.value || '';
            label.textContent = value ? (labelMap[value] || 'Selected') : '— Select —';
        };

        let pickerIdCounter = voucherDimensionPickerCounter;
        const portalClass = 'voucher-dimension-picker-menu--portal';

        const findPickerMenu = (picker) => {
            const pickerId = picker.dataset.vdPickerId;
            if (!pickerId) {
                return picker.querySelector('.voucher-dimension-picker-menu');
            }

            return document.querySelector(`.voucher-dimension-picker-menu[data-vd-picker-id="${pickerId}"]`)
                || picker.querySelector('.voucher-dimension-picker-menu');
        };

        const positionPickerMenu = (toggle, menu) => {
            positionVoucherLinePickerMenu(toggle, menu, 280);
        };

        const closePickerMenu = (picker) => {
            const menu = findPickerMenu(picker);
            if (!menu) {
                return;
            }

            menu.classList.add('d-none');
            picker.querySelector('.voucher-dimension-picker-toggle')?.setAttribute('aria-expanded', 'false');

            menu.style.position = '';
            menu.style.top = '';
            menu.style.left = '';
            menu.style.zIndex = '';
            menu.style.minWidth = '';
            menu.classList.remove(portalClass);

            if (menu.parentElement !== picker) {
                picker.appendChild(menu);
            }
        };

        const closeAllPickerMenus = () => {
            document.querySelectorAll('.voucher-dimension-picker').forEach((picker) => {
                const menu = findPickerMenu(picker);
                if (menu && !menu.classList.contains('d-none')) {
                    closePickerMenu(picker);
                }
            });
        };

        registerVoucherPickerGlobalListeners();

        const initPicker = (picker) => {
            if (picker.dataset.vdReady === '1') {
                syncPickerLabel(picker);
                return;
            }

            const slot = picker.dataset.slot;
            const toggle = picker.querySelector('.voucher-dimension-picker-toggle');
            const initialMenu = picker.querySelector('.voucher-dimension-picker-menu');
            const treeEl = picker.querySelector('.voucher-dimension-picker-tree');
            const searchInput = picker.querySelector('.voucher-dimension-picker-search-input');
            const emptyEl = picker.querySelector('.voucher-dimension-picker-empty');
            const clearBtn = picker.querySelector('.voucher-dimension-picker-clear');

            if (!toggle || !initialMenu || !treeEl) {
                return;
            }

            picker.dataset.vdPickerId = String(++pickerIdCounter);
            voucherDimensionPickerCounter = pickerIdCounter;
            initialMenu.dataset.vdPickerId = picker.dataset.vdPickerId;

            const expanded = new Set();
            walkTree(dimensionTrees[slot] || [], (node) => {
                if (node.children && node.children.length) {
                    expanded.add(String(node.id));
                }
            });
            expandedByPicker.set(picker, expanded);

            syncPickerLabel(picker);
            renderTree(picker, treeEl, emptyEl, searchInput, slot);

            const resolveMenu = () => findPickerMenu(picker) || initialMenu;

            toggle.addEventListener('click', (event) => {
                event.preventDefault();
                event.stopPropagation();
                const menu = resolveMenu();
                const isOpen = !menu.classList.contains('d-none');
                closeAllVoucherLinePickers();
                if (isOpen) {
                    return;
                }

                document.body.appendChild(menu);
                menu.classList.add(portalClass);
                menu.classList.remove('d-none');
                toggle.setAttribute('aria-expanded', 'true');
                positionPickerMenu(toggle, menu);
                searchInput?.focus();
            });

            treeEl.addEventListener('click', (event) => {
                const expandBtn = event.target.closest('[data-vd-expand]');
                if (expandBtn) {
                    event.preventDefault();
                    const nodeId = expandBtn.getAttribute('data-vd-expand');
                    if (expanded.has(nodeId)) {
                        expanded.delete(nodeId);
                    } else {
                        expanded.add(nodeId);
                    }
                    renderTree(picker, treeEl, emptyEl, searchInput, slot);
                    return;
                }

                const selectBtn = event.target.closest('[data-vd-select]');
                if (!selectBtn) {
                    return;
                }

                const input = picker.querySelector('.voucher-dimension-input');
                if (input) {
                    input.value = selectBtn.getAttribute('data-vd-select') || '';
                }
                syncPickerLabel(picker);
                closePickerMenu(picker);
                if (searchInput) {
                    searchInput.value = '';
                }
                renderTree(picker, treeEl, emptyEl, searchInput, slot);
            });

            searchInput?.addEventListener('input', () => {
                if (searchInput.value.trim()) {
                    walkTree(dimensionTrees[slot] || [], (node) => {
                        if (node.children && node.children.length) {
                            expanded.add(String(node.id));
                        }
                    });
                }
                renderTree(picker, treeEl, emptyEl, searchInput, slot);
            });

            clearBtn?.addEventListener('click', (event) => {
                event.preventDefault();
                const input = picker.querySelector('.voucher-dimension-input');
                if (input) {
                    input.value = '';
                }
                if (searchInput) {
                    searchInput.value = '';
                }
                syncPickerLabel(picker);
                renderTree(picker, treeEl, emptyEl, searchInput, slot);
                closePickerMenu(picker);
            });

            picker.dataset.vdReady = '1';
        };

        const root = scope || document;
        root.querySelectorAll('.voucher-dimension-picker').forEach(initPicker);
    }

    window.axisInitVoucherDimensionPickers = initVoucherDimensionPickers;

    function initVoucherTreeColumnPickers(scope, config) {
        if (!config.skipVoucherFormCheck && !document.getElementById('voucherForm')) {
            return null;
        }

        const treeScriptIds = {
            partyTree: 'voucherPartyTreeData',
            accountTree: 'voucherAccountTreeData',
        };

        const resolveTree = (picker) => {
            if (typeof config.getTreeForPicker === 'function') {
                return config.getTreeForPicker(picker) || [];
            }

            return readVoucherJsonScript(treeScriptIds[config.treeDataset] || '', []);
        };

        const walkTree = (nodes, fn) => {
            (nodes || []).forEach((node) => {
                fn(node);
                if (node.children && node.children.length) {
                    walkTree(node.children, fn);
                }
            });
        };

        const treesByPicker = new WeakMap();
        const labelMapsByPicker = new WeakMap();
        const expandedByPicker = new WeakMap();

        const rebuildPickerMaps = (picker) => {
            const tree = resolveTree(picker);
            treesByPicker.set(picker, tree);
            const labelMap = {};
            walkTree(tree, (node) => {
                if (node.selectable && node.value) {
                    labelMap[node.value] = config.formatLabel(node);
                }
            });
            labelMapsByPicker.set(picker, labelMap);
            return tree;
        };

        const resetPickerExpanded = (picker, tree) => {
            const expanded = new Set();
            walkTree(tree, (node) => {
                if (!node.selectable && node.children && node.children.length) {
                    expanded.add(String(node.id));
                }
            });
            expandedByPicker.set(picker, expanded);
            return expanded;
        };
        let pickerIdCounter = config.counterRef.value;
        const portalClass = `${config.cssPrefix}-menu--portal`;

        const findPickerMenu = (picker) => {
            const pickerId = picker.dataset[config.pickerIdAttr];
            if (!pickerId) {
                return picker.querySelector(`.${config.cssPrefix}-menu`);
            }

            return document.querySelector(`.${config.cssPrefix}-menu[data-${config.menuIdAttr}="${pickerId}"]`)
                || picker.querySelector(`.${config.cssPrefix}-menu`);
        };

        const positionPickerMenu = (toggle, menu) => {
            positionVoucherLinePickerMenu(toggle, menu, config.menuMinWidth || 420);
        };

        const closePickerMenu = (picker) => {
            const menu = findPickerMenu(picker);
            if (!menu) {
                return;
            }

            menu.classList.add('d-none');
            picker.querySelector(`.${config.cssPrefix}-toggle`)?.setAttribute('aria-expanded', 'false');

            menu.style.position = '';
            menu.style.top = '';
            menu.style.left = '';
            menu.style.zIndex = '';
            menu.style.minWidth = '';
            menu.classList.remove(portalClass);

            if (menu.parentElement !== picker) {
                picker.appendChild(menu);
            }
        };

        const closeAllPickerMenus = () => {
            document.querySelectorAll(`.${config.rootSelector.slice(1)}`).forEach((picker) => {
                const menu = findPickerMenu(picker);
                if (menu && !menu.classList.contains('d-none')) {
                    closePickerMenu(picker);
                }
            });
        };

        registerVoucherPickerGlobalListeners();

        const nodeMatches = (node, term) => {
            if (!term) {
                return true;
            }

            const haystack = `${node.name || ''} ${node.code || ''} ${node.type_label || ''}`.toLowerCase();
            return haystack.indexOf(term) !== -1;
        };

        const subtreeMatches = (node, term) => {
            if (!term) {
                return true;
            }

            if (nodeMatches(node, term)) {
                return true;
            }

            return (node.children || []).some((child) => subtreeMatches(child, term));
        };

        const renderTree = (picker, treeEl, emptyEl, searchInput) => {
            const expanded = expandedByPicker.get(picker) || new Set();
            const term = (searchInput?.value || '').trim().toLowerCase();
            const selectedValue = picker.querySelector(config.inputSelector)?.value || '';

            const renderNodes = (nodes, depth) => nodes.map((node) => {
                if (term && !subtreeMatches(node, term)) {
                    return '';
                }

                const id = String(node.id);
                const hasChildren = !!(node.children && node.children.length);

                if (!node.selectable) {
                    const groupChildren = hasChildren ? renderNodes(node.children, depth + 1) : '';
                    if (!groupChildren) {
                        return '';
                    }

                    return `
                        <div class="${config.cssPrefix}-item ${config.cssPrefix}-item-group" style="padding-left:${depth * 16}px">
                            <button type="button" class="${config.cssPrefix}-toggle-btn ${hasChildren ? '' : 'is-hidden'}" data-${config.expandAttr}="${id}" aria-label="Expand">
                                <i class="bi ${expanded.has(id) ? 'bi-chevron-down' : 'bi-chevron-right'}" style="font-size:11px"></i>
                            </button>
                            <div class="${config.cssPrefix}-group">${escapeHtml(node.name)}</div>
                        </div>
                        <div class="${expanded.has(id) ? '' : 'd-none'}" data-${config.childrenAttr}="${id}">${groupChildren}</div>
                    `;
                }

                const childHtml = hasChildren && expanded.has(id) ? renderNodes(node.children, depth + 1) : '';
                const isSelected = selectedValue === node.value;

                return `
                    <button type="button"
                            class="${config.cssPrefix}-item ${config.cssPrefix}-row ${isSelected ? 'is-selected' : ''}"
                            style="padding-left:${depth * 16}px"
                            data-${config.selectAttr}="${escapeHtml(node.value || '')}">
                        <span class="${config.cssPrefix}-toggle-btn ${hasChildren ? '' : 'is-hidden'}" data-${config.expandAttr}="${escapeHtml(id)}" tabindex="-1">
                            <i class="bi ${expanded.has(id) ? 'bi-chevron-down' : 'bi-chevron-right'}" style="font-size:11px"></i>
                        </span>
                        <span class="${config.cssPrefix}-code">${escapeHtml(node.code || '—')}</span>
                        <span class="${config.cssPrefix}-name">${escapeHtml(node.name)}</span>
                        <span class="${config.cssPrefix}-type">${escapeHtml(node.type_label)}</span>
                    </button>
                    ${hasChildren ? `<div class="${expanded.has(id) ? '' : 'd-none'}" data-${config.childrenAttr}="${id}">${childHtml}</div>` : ''}
                `;
            }).join('');

            const html = renderNodes(treesByPicker.get(picker) || [], 0);
            if (!treeEl) {
                return;
            }
            treeEl.innerHTML = html;
            emptyEl?.classList.toggle('d-none', html.trim() !== '');
        };

        const syncPickerLabel = (picker) => {
            const input = picker.querySelector(config.inputSelector);
            const label = picker.querySelector(`.${config.cssPrefix}-label`);
            if (!label) {
                return;
            }

            const value = input?.value || '';
            const labelMap = labelMapsByPicker.get(picker) || {};
            const emptyLabel = typeof config.getEmptyLabelForPicker === 'function'
                ? config.getEmptyLabelForPicker(picker)
                : config.emptyLabel;
            label.textContent = value ? (labelMap[value] || config.selectedFallback) : emptyLabel;
        };

        const notifyValueChange = (picker) => {
            if (typeof config.onValueChange !== 'function') {
                return;
            }

            const input = picker.querySelector(config.inputSelector);
            config.onValueChange(picker, input?.value || '');
        };

        const initPicker = (picker) => {
            const toggle = picker.querySelector(`.${config.cssPrefix}-toggle`);
            const initialMenu = picker.querySelector(`.${config.cssPrefix}-menu`);
            const treeEl = picker.querySelector(`.${config.cssPrefix}-tree`);
            const searchInput = picker.querySelector(`.${config.cssPrefix}-search-input`);
            const emptyEl = picker.querySelector(`.${config.cssPrefix}-empty`);
            const clearBtn = picker.querySelector(`.${config.cssPrefix}-clear`);

            if (!toggle || !initialMenu || !treeEl) {
                return;
            }

            if (picker.dataset[config.readyAttr] === '1') {
                const tree = rebuildPickerMaps(picker);
                resetPickerExpanded(picker, tree);
                syncPickerLabel(picker);
                renderTree(picker, treeEl, emptyEl, searchInput);
                return;
            }

            picker.dataset[config.pickerIdAttr] = String(++pickerIdCounter);
            config.counterRef.value = pickerIdCounter;
            initialMenu.setAttribute(`data-${config.menuIdAttr}`, picker.dataset[config.pickerIdAttr]);

            const tree = rebuildPickerMaps(picker);
            resetPickerExpanded(picker, tree);

            syncPickerLabel(picker);
            renderTree(picker, treeEl, emptyEl, searchInput);

            const resolveMenu = () => findPickerMenu(picker) || initialMenu;

            toggle.addEventListener('click', (event) => {
                event.preventDefault();
                event.stopPropagation();
                const menu = resolveMenu();
                const isOpen = !menu.classList.contains('d-none');
                closeAllVoucherLinePickers();
                if (isOpen) {
                    return;
                }

                document.body.appendChild(menu);
                menu.classList.add(portalClass);
                menu.classList.remove('d-none');
                toggle.setAttribute('aria-expanded', 'true');
                positionPickerMenu(toggle, menu);
                if (searchInput) {
                    searchInput.focus();
                    searchInput.select();
                }
            });

            searchInput?.addEventListener('mousedown', (event) => event.stopPropagation());
            searchInput?.addEventListener('pointerdown', (event) => event.stopPropagation());
            searchInput?.addEventListener('keydown', (event) => event.stopPropagation());

            treeEl.addEventListener('click', (event) => {
                const expandBtn = event.target.closest(`[data-${config.expandAttr}]`);
                if (expandBtn) {
                    event.preventDefault();
                    event.stopPropagation();
                    const nodeId = expandBtn.getAttribute(`data-${config.expandAttr}`);
                    const expanded = expandedByPicker.get(picker) || new Set();
                    if (expanded.has(nodeId)) {
                        expanded.delete(nodeId);
                    } else {
                        expanded.add(nodeId);
                    }
                    expandedByPicker.set(picker, expanded);
                    renderTree(picker, treeEl, emptyEl, searchInput);
                    return;
                }

                const selectBtn = event.target.closest(`[data-${config.selectAttr}]`);
                if (!selectBtn) {
                    return;
                }

                const input = picker.querySelector(config.inputSelector);
                if (input) {
                    input.value = selectBtn.getAttribute(`data-${config.selectAttr}`) || '';
                }
                syncPickerLabel(picker);
                notifyValueChange(picker);
                closePickerMenu(picker);
                if (searchInput) {
                    searchInput.value = '';
                }
                renderTree(picker, treeEl, emptyEl, searchInput);
            });

            searchInput?.addEventListener('input', () => {
                if (searchInput.value.trim()) {
                    const pickerTree = treesByPicker.get(picker) || [];
                    const expanded = expandedByPicker.get(picker) || new Set();
                    walkTree(pickerTree, (node) => {
                        if (node.children && node.children.length) {
                            expanded.add(String(node.id));
                        }
                    });
                    expandedByPicker.set(picker, expanded);
                }
                renderTree(picker, treeEl, emptyEl, searchInput);
            });

            clearBtn?.addEventListener('click', (event) => {
                event.preventDefault();
                const input = picker.querySelector(config.inputSelector);
                if (input) {
                    input.value = '';
                }
                if (searchInput) {
                    searchInput.value = '';
                }
                syncPickerLabel(picker);
                notifyValueChange(picker);
                renderTree(picker, treeEl, emptyEl, searchInput);
                closePickerMenu(picker);
            });

            picker.dataset[config.readyAttr] = '1';
        };

        const root = scope || document;
        root.querySelectorAll(config.rootSelector).forEach(initPicker);

        const refreshPicker = (picker, listKey, selectedValue) => {
            if (!picker) {
                return;
            }

            if (listKey) {
                picker.dataset.listKey = listKey;
            }

            const input = picker.querySelector(config.inputSelector);
            if (selectedValue !== undefined && input) {
                input.value = selectedValue || '';
            }

            const tree = rebuildPickerMaps(picker);
            resetPickerExpanded(picker, tree);

            const treeEl = picker.querySelector(`.${config.cssPrefix}-tree`);
            const searchInput = picker.querySelector(`.${config.cssPrefix}-search-input`);
            const emptyEl = picker.querySelector(`.${config.cssPrefix}-empty`);
            if (searchInput) {
                searchInput.value = '';
            }

            syncPickerLabel(picker);
            renderTree(picker, treeEl, emptyEl, searchInput);
        };

        return { refreshPicker };
    }

    function initVoucherPartyPickers(scope) {
        const counterRef = { value: voucherPartyPickerCounter };
        initVoucherTreeColumnPickers(scope, {
            treeDataset: 'partyTree',
            rootSelector: '.voucher-party-picker',
            cssPrefix: 'voucher-party-picker',
            inputSelector: '.voucher-party-input',
            pickerIdAttr: 'vpPickerId',
            menuIdAttr: 'vp-picker-id',
            readyAttr: 'vpReady',
            globalListenerKey: 'vpGlobalListeners',
            expandAttr: 'vp-expand',
            selectAttr: 'vp-select',
            childrenAttr: 'vp-children',
            emptyLabel: '— Select —',
            selectedFallback: 'Selected',
            menuMinWidth: 560,
            counterRef,
            formatLabel: (node) => `${node.name || ''}${node.type_label ? ` (${node.type_label})` : ''}`,
            onValueChange: (picker, value) => {
                if (picker.dataset.voucherPartyHeader !== '1') {
                    return;
                }

                const partyIdEl = document.getElementById('partyId');
                const partyTypeEl = document.getElementById('partyType');
                if (!value || value.indexOf(':') === -1) {
                    if (partyIdEl) {
                        partyIdEl.value = '';
                    }
                    if (partyTypeEl) {
                        partyTypeEl.value = '';
                    }
                    return;
                }

                const parts = value.split(':');
                const partyType = parts.shift() || '';
                const partyId = parts.join(':');
                if (partyIdEl) {
                    partyIdEl.value = partyId;
                }
                if (partyTypeEl) {
                    partyTypeEl.value = partyType;
                }
            },
        });
        voucherPartyPickerCounter = counterRef.value;
    }

    function initVoucherAccountPickers(scope) {
        const counterRef = { value: voucherAccountPickerCounter };
        initVoucherTreeColumnPickers(scope, {
            treeDataset: 'accountTree',
            rootSelector: '.voucher-account-picker',
            cssPrefix: 'voucher-account-picker',
            inputSelector: '.voucher-account-input',
            pickerIdAttr: 'vaPickerId',
            menuIdAttr: 'va-picker-id',
            readyAttr: 'vaReady',
            globalListenerKey: 'vaGlobalListeners',
            expandAttr: 'va-expand',
            selectAttr: 'va-select',
            childrenAttr: 'va-children',
            emptyLabel: '— Select Account —',
            selectedFallback: 'Selected account',
            menuMinWidth: 560,
            counterRef,
            formatLabel: (node) => {
                const code = node.code ? `[${node.code}] ` : '';
                const type = node.type_label ? ` (${node.type_label})` : '';
                return `${code}${node.name || ''}${type}`;
            },
            onValueChange: () => {
                document.dispatchEvent(new CustomEvent('axis:voucher-account-changed'));
            },
        });
        voucherAccountPickerCounter = counterRef.value;
    }

    let salaryComponentPickerApi = null;

    function loadSalaryComponentAccountTrees() {
        const fromScript = readVoucherJsonScript('salaryComponentAccountTrees', null);
        if (fromScript && typeof fromScript === 'object') {
            window.salaryComponentAccountTrees = fromScript;
        } else if (!window.salaryComponentAccountTrees) {
            window.salaryComponentAccountTrees = {};
        }

        return window.salaryComponentAccountTrees;
    }

    function initSalaryComponentAccountPickers(scope) {
        registerPickerFocusGuard();
        loadSalaryComponentAccountTrees();
        const counterRef = { value: salaryComponentAccountPickerCounter };
        const api = initVoucherTreeColumnPickers(scope, {
            skipVoucherFormCheck: true,
            getTreeForPicker: (picker) => window.salaryComponentAccountTrees[picker.dataset.listKey] || [],
            getEmptyLabelForPicker: (picker) => picker.dataset.placeholder || 'Select account...',
            rootSelector: '.sc-account-picker',
            cssPrefix: 'voucher-account-picker',
            inputSelector: '.sc-account-input',
            pickerIdAttr: 'scPickerId',
            menuIdAttr: 'sc-picker-id',
            readyAttr: 'scPickerReady',
            expandAttr: 'va-expand',
            selectAttr: 'va-select',
            childrenAttr: 'va-children',
            emptyLabel: 'Select account...',
            selectedFallback: 'Selected account',
            menuMinWidth: 560,
            counterRef,
            formatLabel: (node) => {
                const code = node.code ? `[${node.code}] ` : '';
                const type = node.type_label ? ` (${node.type_label})` : '';
                return `${code}${node.name || ''}${type}`;
            },
        });
        salaryComponentAccountPickerCounter = counterRef.value;
        if (api) {
            salaryComponentPickerApi = api;
        }

        (scope || document).querySelectorAll('.sc-account-picker-add').forEach((btn) => {
            if (btn.dataset.scAddBound === '1') {
                return;
            }
            btn.dataset.scAddBound = '1';
            btn.addEventListener('click', (event) => {
                event.preventDefault();
                event.stopPropagation();
                const picker = btn.closest('.sc-account-picker');
                if (picker && typeof window.axisOpenSalaryComponentCoaQuickAdd === 'function') {
                    window.axisOpenSalaryComponentCoaQuickAdd(picker);
                }
            });
        });
    }

    window.axisInitVoucherPartyPickers = initVoucherPartyPickers;
    window.axisInitVoucherAccountPickers = initVoucherAccountPickers;
    window.axisInitSalaryComponentAccountPickers = initSalaryComponentAccountPickers;
    window.axisRefreshSalaryComponentAccountPicker = (picker, listKey, selectedValue) => {
        if (salaryComponentPickerApi) {
            salaryComponentPickerApi.refreshPicker(picker, listKey, selectedValue);
        }
    };
    window.axisRefreshSalaryComponentAccountTrees = (trees, selectPicker, accountId) => {
        if (trees && typeof trees === 'object') {
            window.salaryComponentAccountTrees = trees;
        }
        document.querySelectorAll('.sc-account-picker').forEach((picker) => {
            if (!salaryComponentPickerApi) {
                return;
            }
            const input = picker.querySelector('.sc-account-input');
            const selectedValue = selectPicker === picker && accountId
                ? String(accountId)
                : (input?.value || '');
            salaryComponentPickerApi.refreshPicker(picker, picker.dataset.listKey, selectedValue);
        });
    };
    window.axisInitReportDatepickers = initReportDatepickers;

    function initProfitLossTree() {
        const table = document.querySelector('.pl-report-table');
        if (!table) {
            return;
        }

        const setDescendantsVisible = (parentId, show) => {
            table.querySelectorAll(`.pl-tree-row[data-parent="${parentId}"]`).forEach((row) => {
                row.style.display = show ? '' : 'none';
                if (!show) {
                    const toggle = row.querySelector('.pl-tree-toggle');
                    if (toggle) {
                        toggle.setAttribute('aria-expanded', 'false');
                        const icon = toggle.querySelector('i');
                        if (icon) {
                            icon.className = 'bi bi-chevron-right';
                        }
                    }
                    const childId = row.dataset.accountId;
                    if (childId) {
                        setDescendantsVisible(childId, false);
                    }
                }
            });
        };

        table.addEventListener('click', (event) => {
            const toggle = event.target.closest('.pl-tree-toggle');
            if (!toggle) {
                return;
            }

            event.preventDefault();
            const row = toggle.closest('tr');
            const accountId = row?.dataset.accountId;
            if (!accountId) {
                return;
            }

            const expanded = toggle.getAttribute('aria-expanded') === 'true';
            const nextExpanded = !expanded;
            toggle.setAttribute('aria-expanded', nextExpanded ? 'true' : 'false');
            const icon = toggle.querySelector('i');
            if (icon) {
                icon.className = nextExpanded ? 'bi bi-chevron-down' : 'bi bi-chevron-right';
            }
            setDescendantsVisible(accountId, nextExpanded);
        });

        document.getElementById('plCollapseAll')?.addEventListener('click', () => {
            table.querySelectorAll('.pl-tree-toggle').forEach((toggle) => {
                toggle.setAttribute('aria-expanded', 'false');
                const icon = toggle.querySelector('i');
                if (icon) {
                    icon.className = 'bi bi-chevron-right';
                }
            });
            table.querySelectorAll('.pl-tree-row[data-level]').forEach((row) => {
                const level = Number(row.dataset.level || '0');
                row.style.display = level === 0 ? '' : 'none';
            });
        });

        document.getElementById('plPrintReport')?.addEventListener('click', () => {
            table.querySelectorAll('.pl-tree-row').forEach((row) => {
                row.style.display = '';
            });
            window.print();
        });
    }

    document.addEventListener('DOMContentLoaded', () => {
        initConfirms();
        initFormPlugins();
        initDataTables();
        initUserProfileModal();
        initVoucherDimensionPickers();
        initVoucherPartyPickers();
        initVoucherAccountPickers();
        initProfitLossTree();
    });
})();
