// gf-splitter.js — resizable list/detail divider for ListDetailLayout.
//
// Blazor Server can't round-trip every pointermove over the SignalR circuit
// without lag, so the drag is handled entirely client-side: the handler
// updates the `--ld-list-width` CSS custom property on the .ld container live
// and only touches localStorage on pointerup. Binding is delegated to the
// container (pointerdown → closest('.ld-divider')) so it survives the divider
// element being added/removed as the detail pane toggles — wire once, no
// re-init churn, no double-binding.
//
// IMPORTANT contract with the component: the .ld container's inline `style`
// must contain ONLY `--ld-list-width: <default>` (a value that never changes
// across renders), and `grid-template-columns` must live in CSS keyed off the
// .ld/.ld--single/.ld--resizable classes. That way Blazor never re-sets the
// `style` attribute (its rendered value is constant), so the override this
// module writes via setProperty survives every re-render and detail toggle.
window.gfSplitter = {
    // Wire a container once. key = localStorage slot (per view); listMin/listMax
    // clamp the list pane; detailMin keeps the detail pane from being crushed.
    init: function (container, key, listMin, listMax, detailMin) {
        if (!container) return;
        if (container.dataset.gfSplitterWired === '1') {
            // Already wired — just re-apply the saved width (cheap, idempotent).
            window.gfSplitter._applySaved(container, key, listMin, listMax, detailMin);
            return;
        }
        container.dataset.gfSplitterWired = '1';
        // Stash the component's default width (the only inline --ld-list-width
        // value at wire time) so reset() can restore it without deleting the
        // var — deleting it would leave grid-template-columns' var() with only
        // its CSS fallback, not the per-instance default.
        const def = (container.style.getPropertyValue('--ld-list-width') || '').trim();
        if (def) container.dataset.gfDefaultWidth = def;

        window.gfSplitter._applySaved(container, key, listMin, listMax, detailMin);

        let startX = 0, startW = 0, dragging = false, handleEl = null;

        const hardMaxFor = () => {
            // Don't let the list crush the detail pane below detailMin; but if
            // the container isn't measurable yet (0 width during early layout)
            // fall back to the configured listMax rather than pinning to listMin.
            const cw = container.clientWidth;
            return cw > 0 ? Math.min(listMax, cw - detailMin) : listMax;
        };

        const onMove = (e) => {
            if (!dragging) return;
            const w = Math.max(listMin, Math.min(hardMaxFor(), startW + (e.clientX - startX)));
            container.style.setProperty('--ld-list-width', w + 'px');
            e.preventDefault();
        };

        const end = (e) => {
            if (!dragging) return;
            dragging = false;
            document.body.style.userSelect = '';
            document.body.style.cursor = '';
            window.removeEventListener('pointermove', onMove);
            window.removeEventListener('pointerup', end);
            window.removeEventListener('pointercancel', end);
            if (handleEl && e && e.pointerId != null) {
                try { handleEl.releasePointerCapture(e.pointerId); } catch (_) { /* not captured */ }
            }
            handleEl = null;
            const cur = container.style.getPropertyValue('--ld-list-width');
            if (cur) { try { localStorage.setItem(key, cur.trim()); } catch (_) { /* unavailable */ } }
        };

        container.addEventListener('dblclick', (e) => {
            const handle = e.target.closest && e.target.closest('.ld-divider');
            if (!handle || !container.contains(handle)) return;
            window.gfSplitter.reset(container, key);
            e.preventDefault();
        });

        container.addEventListener('pointerdown', (e) => {
            const handle = e.target.closest && e.target.closest('.ld-divider');
            if (!handle || !container.contains(handle)) return;
            const list = container.querySelector('.ld-list');
            startW = list ? list.getBoundingClientRect().width : (listMin + listMax) / 2;
            startW = Math.max(listMin, Math.min(listMax, startW));
            startX = e.clientX;
            dragging = true;
            handleEl = handle;
            // Pointer capture keeps moves flowing even if the cursor outruns the
            // 7px handle; pointercancel/up both run the same cleanup so a
            // cancelled gesture can't strand a global drag.
            try { handle.setPointerCapture(e.pointerId); } catch (_) { /* fall back to window listeners */ }
            document.body.style.userSelect = 'none';
            document.body.style.cursor = 'col-resize';
            window.addEventListener('pointermove', onMove);
            window.addEventListener('pointerup', end);
            window.addEventListener('pointercancel', end);
            e.preventDefault();
        });
    },

    _applySaved: function (container, key, listMin, listMax, detailMin) {
        let saved = null;
        try { saved = localStorage.getItem(key); } catch (_) { saved = null; }
        if (!saved) return;
        const n = parseInt(saved, 10);
        if (!Number.isFinite(n)) return;
        // Re-clamp on restore: a width saved on a wide window must not crush the
        // detail pane on a narrower one. clientWidth 0 (not yet laid out) ⇒ skip
        // the container cap and use listMax.
        const cw = container.clientWidth;
        const hardMax = cw > 0 ? Math.min(listMax, cw - detailMin) : listMax;
        const w = Math.max(listMin, Math.min(hardMax, n));
        container.style.setProperty('--ld-list-width', w + 'px');
    },

    // Double-click the divider → restore the component's default width.
    reset: function (container, key) {
        if (!container) return;
        const def = container.dataset.gfDefaultWidth;
        if (def) container.style.setProperty('--ld-list-width', def);
        else container.style.removeProperty('--ld-list-width'); // falls back to CSS default
        try { localStorage.removeItem(key); } catch (_) { /* unavailable */ }
    }
};
