(function () {
    'use strict';

    const portalClass = 'coa-parent-picker-menu--portal';
    const COA_PICKER_Z = 1200;
    let pickerCounter = 0;
    const pickerState = new WeakMap();

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

    function formatAccountLabel(account, placeholder) {
        if (!account) {
            return placeholder || '— No Parent (Top Level) —';
        }

        const code = account.code ? `[${account.code}] ` : '';
        return `${code}${account.name}`;
    }

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

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

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

    function subtreeMatches(node, term) {
        if (!term) {
            return true;
        }

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

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

    function positionMenu(toggle, menu) {
        const rect = toggle.getBoundingClientRect();
        const gap = 4;
        const padding = 8;
        const menuWidth = menu.offsetWidth || Math.max(rect.width, 560);
        const menuHeight = menu.offsetHeight || 280;

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

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

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

    function getState(picker) {
        if (!pickerState.has(picker)) {
            pickerState.set(picker, {
                tree: [],
                accountsMap: {},
                typeFilter: '',
                excludeIds: new Set(),
                expanded: new Set(),
                search: '',
                selectedId: '',
                menu: null,
                toggle: null,
                treeEl: null,
                emptyEl: null,
                searchInput: null,
                clearBtn: null,
                addBtn: null,
            });
        }

        return pickerState.get(picker);
    }

    function findPickerMenu(picker) {
        const pickerId = picker.dataset.coaParentId;
        if (pickerId) {
            const portaled = document.querySelector(
                `.coa-parent-picker-menu[data-coa-parent-picker-id="${pickerId}"]`,
            );
            if (portaled) {
                return portaled;
            }
        }

        return getState(picker).menu || picker.querySelector('.coa-parent-picker-menu');
    }

    function renderTree(picker) {
        const state = getState(picker);
        const treeEl = state.treeEl;
        const emptyEl = state.emptyEl;
        if (!treeEl) {
            return;
        }

        const term = state.search.trim().toLowerCase();
        const selectedId = picker.querySelector('.coa-parent-picker-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 isSection = String(id).startsWith('section:') || node.selectable === false;
            const expanded = term !== '' || state.expanded.has(id);
            const selectable = !isSection
                && node.selectable !== false
                && !state.excludeIds.has(id)
                && (!state.typeFilter || node.type === state.typeFilter);
            const isSelected = !isSection && selectedId === String(node.id);

            if (isSection) {
                const sectionChildren = hasChildren && expanded
                    ? renderNodes(node.children, depth + 1)
                    : '';

                if (!sectionChildren) {
                    return '';
                }

                if (term === '') {
                    state.expanded.add(id);
                }

                return `
                    <div class="coa-parent-picker-row is-section" style="padding-left:${depth * 14}px">
                        <button type="button" class="coa-parent-picker-toggle-btn ${hasChildren ? '' : 'is-hidden'}" data-coa-parent-expand="${escapeHtml(id)}">
                            <i class="bi bi-chevron-${expanded ? 'down' : 'right'}" style="font-size:11px"></i>
                        </button>
                        <span></span>
                        <span class="coa-parent-picker-name">${escapeHtml(node.name)}</span>
                        <span class="coa-parent-picker-type">${escapeHtml(node.type_label || '')}</span>
                    </div>
                    ${sectionChildren}
                `;
            }

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

            return `
                <button type="button"
                        class="coa-parent-picker-row ${isSelected ? 'is-selected' : ''}"
                        style="padding-left:${depth * 14}px"
                        data-coa-parent-select="${escapeHtml(node.id)}"
                        ${selectable ? '' : 'disabled'}>
                    <span class="coa-parent-picker-toggle-btn ${hasChildren ? '' : 'is-hidden'}" data-coa-parent-expand="${escapeHtml(id)}" tabindex="-1">
                        <i class="bi bi-chevron-${expanded ? 'down' : 'right'}" style="font-size:11px"></i>
                    </span>
                    <span class="coa-parent-picker-code">${escapeHtml(node.code || '—')}</span>
                    <span class="coa-parent-picker-name">${escapeHtml(node.name)}</span>
                    <span class="coa-parent-picker-type">${escapeHtml(node.type_label || '')}</span>
                </button>
                ${childHtml}
            `;
        }).join('');

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

    function syncLabel(picker) {
        const state = getState(picker);
        const input = picker.querySelector('.coa-parent-picker-input');
        const label = picker.querySelector('.coa-parent-picker-label');
        const placeholder = picker.dataset.placeholder || '— No Parent (Top Level) —';
        if (!label) {
            return;
        }

        const account = state.accountsMap[String(input?.value || '')];
        label.textContent = formatAccountLabel(account, placeholder);
    }

    function setValue(picker, id) {
        const input = picker.querySelector('.coa-parent-picker-input');
        if (input) {
            input.value = id ? String(id) : '';
        }
        getState(picker).selectedId = id ? String(id) : '';
        picker.querySelector('.coa-parent-picker-toggle')?.classList.remove('is-invalid');
        syncLabel(picker);
        renderTree(picker);
    }

    function closeMenu(picker) {
        const state = getState(picker);
        const menu = findPickerMenu(picker);
        const toggle = state.toggle;
        if (!menu) {
            return;
        }

        menu.classList.add('d-none');
        menu.classList.remove(portalClass);
        menu.style.position = '';
        menu.style.left = '';
        menu.style.top = '';
        menu.style.width = '';
        menu.style.zIndex = '';
        toggle?.setAttribute('aria-expanded', 'false');

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

    function openMenu(picker) {
        const state = getState(picker);
        const menu = findPickerMenu(picker);
        const toggle = state.toggle;
        if (!menu || !toggle || toggle.disabled) {
            return;
        }

        document.body.appendChild(menu);
        menu.dataset.coaParentPickerId = picker.dataset.coaParentId || '';
        menu.classList.add(portalClass);
        menu.classList.remove('d-none');
        toggle.setAttribute('aria-expanded', 'true');
        positionMenu(toggle, menu);

        if (state.searchInput) {
            state.searchInput.focus();
            state.searchInput.select();
        }

        renderTree(picker);
    }

    function closeAllMenus() {
        document.querySelectorAll('[data-coa-parent-picker]').forEach((picker) => {
            const menu = findPickerMenu(picker);
            if (menu && !menu.classList.contains('d-none')) {
                closeMenu(picker);
            }
        });
    }

    function repositionOpenMenus() {
        document.querySelectorAll('.coa-parent-picker-menu--portal:not(.d-none)').forEach((menu) => {
            const pickerId = menu.dataset.coaParentPickerId;
            const picker = pickerId
                ? document.querySelector(`[data-coa-parent-picker][data-coa-parent-id="${pickerId}"]`)
                : null;
            const toggle = picker ? getState(picker).toggle : null;
            if (toggle) {
                positionMenu(toggle, menu);
            }
        });
    }

    function bindPickerElements(picker) {
        const state = getState(picker);
        if (!state.menu) {
            state.menu = picker.querySelector('.coa-parent-picker-menu');
            state.toggle = picker.querySelector('.coa-parent-picker-toggle');
            state.treeEl = state.menu?.querySelector('.coa-parent-picker-tree') || null;
            state.emptyEl = state.menu?.querySelector('.coa-parent-picker-empty') || null;
            state.searchInput = state.menu?.querySelector('.coa-parent-picker-search-input') || null;
            state.clearBtn = state.menu?.querySelector('.coa-parent-picker-clear') || null;
            state.addBtn = state.menu?.querySelector('.coa-parent-picker-add') || null;
        }

        if (state.menu && picker.dataset.coaParentId) {
            state.menu.dataset.coaParentPickerId = picker.dataset.coaParentId;
        }
    }

    function initPicker(picker, options) {
        bindPickerElements(picker);
        const state = getState(picker);

        if (picker.dataset.coaParentReady === '1') {
            if (options?.tree) {
                state.tree = options.tree;
            }
            if (options?.accountsMap) {
                state.accountsMap = options.accountsMap;
            }
            if (options?.typeFilter !== undefined) {
                state.typeFilter = options.typeFilter || '';
            }
            renderTree(picker);
            syncLabel(picker);
            return picker;
        }

        picker.dataset.coaParentReady = '1';
        picker.dataset.coaParentId = String(++pickerCounter);
        bindPickerElements(picker);

        state.tree = options?.tree || [];
        state.accountsMap = options?.accountsMap || {};
        state.typeFilter = options?.typeFilter || '';

        walkTree(state.tree, (node) => {
            if (node.selectable === false || String(node.id).startsWith('section:')) {
                state.expanded.add(String(node.id));
            }
        });

        const { menu, toggle, treeEl, searchInput, clearBtn, addBtn } = state;

        toggle?.addEventListener('click', (event) => {
            event.preventDefault();
            event.stopPropagation();
            const currentMenu = findPickerMenu(picker);
            const isOpen = currentMenu && !currentMenu.classList.contains('d-none');
            closeAllMenus();
            if (isOpen) {
                return;
            }
            openMenu(picker);
        });

        searchInput?.addEventListener('input', function () {
            state.search = this.value;
            if (state.search.trim()) {
                walkTree(state.tree, (node) => {
                    if (node.children && node.children.length) {
                        state.expanded.add(String(node.id));
                    }
                });
            }
            renderTree(picker);
        });

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

        menu?.addEventListener('mousedown', (event) => event.stopPropagation());
        menu?.addEventListener('click', (event) => event.stopPropagation());

        treeEl?.addEventListener('click', (event) => {
            const expandBtn = event.target.closest('[data-coa-parent-expand]');
            if (expandBtn) {
                event.preventDefault();
                event.stopPropagation();
                const nodeId = expandBtn.getAttribute('data-coa-parent-expand');
                if (state.expanded.has(nodeId)) {
                    state.expanded.delete(nodeId);
                } else {
                    state.expanded.add(nodeId);
                }
                renderTree(picker);
                return;
            }

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

            setValue(picker, selectBtn.getAttribute('data-coa-parent-select'));
            closeMenu(picker);
            if (searchInput) {
                searchInput.value = '';
                state.search = '';
            }
        });

        clearBtn?.addEventListener('click', (event) => {
            event.preventDefault();
            event.stopPropagation();
            setValue(picker, '');
            closeMenu(picker);
            if (searchInput) {
                searchInput.value = '';
                state.search = '';
            }
        });

        addBtn?.addEventListener('click', (event) => {
            event.preventDefault();
            event.stopPropagation();
            if (typeof options?.onAddNew === 'function') {
                options.onAddNew(picker);
            }
        });

        syncLabel(picker);
        renderTree(picker);
        return picker;
    }

    function registerGlobalListeners() {
        if (document.documentElement.dataset.coaParentPickerListeners === '1') {
            return;
        }

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

        document.addEventListener('mousedown', (event) => {
            if (event.target.closest('[data-coa-parent-picker], .coa-parent-picker-menu--portal, .coa-parent-picker-menu')) {
                return;
            }
            closeAllMenus();
        });

        document.addEventListener('keydown', (event) => {
            if (event.key !== 'Escape') {
                return;
            }
            closeAllMenus();
        });

        window.addEventListener('resize', repositionOpenMenus);
        window.addEventListener('scroll', repositionOpenMenus, true);
    }

    registerGlobalListeners();

    window.axisInitCoaParentPicker = function (picker, options) {
        if (!picker) {
            return null;
        }

        return initPicker(picker, options || {});
    };

    window.axisRefreshCoaParentPicker = function (picker, options) {
        if (!picker) {
            return;
        }

        initPicker(picker, options || {});
    };

    window.axisSetCoaParentPickerValue = function (picker, id) {
        if (!picker) {
            return;
        }

        setValue(picker, id || '');
    };

    window.axisCloseAllCoaParentPickers = closeAllMenus;

    window.axisOpenCoaParentPicker = function (picker) {
        if (!picker || picker.dataset.coaParentReady !== '1') {
            return;
        }

        closeAllMenus();
        openMenu(picker);
    };

    window.axisWireExclusiveBankCash = function (bankInput, cashInput) {
        if (!bankInput || !cashInput) {
            return;
        }

        const sync = (source, other) => {
            source.addEventListener('change', function () {
                if (this.checked) {
                    other.checked = false;
                }
            });
        };

        sync(bankInput, cashInput);
        sync(cashInput, bankInput);
    };
})();
