// Persistent left navigation rail. Renders the wiki folder/file tree, expanded
// to the current page's ancestor chain, and lets the user navigate by clicking
// folders (links) or open files locally via the companion (a.tree-file, wired
// in companion.js). Shares the .tree-* CSS and the ?tree endpoint with
// tree-picker.js but does not reuse its row builder — that one is modal-select
// behavior, this one is navigation behavior. Hidden in edit mode (the server
// omits the container).

(function () {
    // This script owns the .tree-scroll child of the aside, not the aside itself.
    var container = document.querySelector('aside.tree-sidebar .tree-scroll');
    if (!container) return;

    function joinPath(parent, name) {
        if (parent === '/' || parent === '') return '/' + name;
        return parent.replace(/\/+$/, '') + '/' + name;
    }

    function encodeSegments(p) {
        return p.replace(/^\/+/, '').split('/').map(encodeURIComponent).join('/');
    }

    function folderHref(p) {
        if (p === '/' || p === '') return '/';
        return '/' + encodeSegments(p) + '/';
    }

    function fileHref(p) {
        return '/' + encodeSegments(p);
    }

    function fetchFolder(path, expandTo) {
        var url = folderHref(path) + '?tree=1';
        if (expandTo) url += '&expandTo=' + encodeURIComponent(expandTo);
        return fetch(url, { credentials: 'same-origin' }).then(function (r) {
            if (!r.ok) throw new Error('HTTP ' + r.status);
            return r.json();
        });
    }

    // Current page as a canonical, DECODED wiki path ("/" for root, no trailing
    // slash otherwise). pathname is percent-encoded; the tree's entry names (and
    // thus fullPath) are decoded, so we must decode here too or paths containing
    // spaces / non-ASCII never match a row and the chain never expands.
    var activePath = (function () {
        var p = window.location.pathname.replace(/\/+$/, '');
        if (p === '') return '/';
        try { return decodeURIComponent(p); } catch (e) { return p; }
    })();
    var activeRow = null;

    function disabledRow(text) {
        var row = document.createElement('div');
        row.className = 'tree-row is-disabled';
        row.textContent = text;
        return row;
    }

    // renderInto fills containerEl with rows for `entries` (children of
    // parentPath). Folders carrying a `children` array (the pre-expanded
    // ancestor chain from ?expandTo) are opened immediately and recurse.
    function renderInto(containerEl, parentPath, entries) {
        if (!entries || entries.length === 0) {
            containerEl.appendChild(disabledRow('(empty)'));
            return;
        }
        entries.forEach(function (entry) {
            var built = buildRow(parentPath, entry);
            containerEl.appendChild(built.row);
            if (built.preExpand) built.open();
        });
    }

    function buildRow(parentPath, entry) {
        var fullPath = joinPath(parentPath, entry.name);
        var isFolder = entry.kind === 'folder';

        var row = document.createElement('div');
        row.className = 'tree-row';

        var chevron = document.createElement('span');
        chevron.className = 'tree-chevron';
        if (isFolder) chevron.textContent = '▸'; // ▸
        else chevron.classList.add('is-leaf');
        row.appendChild(chevron);


        var link = document.createElement('a');
        link.className = 'tree-name ' + (isFolder ? 'tree-folder' : 'tree-file');
        link.textContent = entry.name;
        link.href = isFolder ? folderHref(fullPath) : fileHref(fullPath);
        row.appendChild(link);

        if (isFolder && fullPath === activePath) {
            row.classList.add('is-active');
            activeRow = row;
        }

        var preChildren = (isFolder && entry.children) ? entry.children : null;
        var childrenEl = null;
        var loaded = false;
        var isOpen = false;

        function ensureChildrenEl() {
            if (!childrenEl) {
                childrenEl = document.createElement('div');
                childrenEl.className = 'tree-children';
            }
            return childrenEl;
        }

        function loadChildren() {
            var el = ensureChildrenEl();
            el.textContent = '';
            el.appendChild(disabledRow('…'));
            fetchFolder(fullPath).then(function (resp) {
                el.textContent = '';
                renderInto(el, fullPath, resp.entries);
                loaded = true;
            }).catch(function () {
                el.textContent = '';
                var err = document.createElement('div');
                err.className = 'tree-row';
                err.textContent = '(failed — tap to retry)';
                err.addEventListener('click', function (e) {
                    e.stopPropagation();
                    loadChildren();
                });
                el.appendChild(err);
            });
        }

        function open() {
            if (!isFolder || isOpen) return;
            var el = ensureChildrenEl();
            row.parentNode.insertBefore(el, row.nextSibling);
            chevron.textContent = '▾'; // ▾
            isOpen = true;
            if (!loaded) {
                if (preChildren) {
                    renderInto(el, fullPath, preChildren);
                    loaded = true;
                } else {
                    loadChildren();
                }
            }
        }

        function close() {
            if (!isFolder || !isOpen) return;
            if (childrenEl && childrenEl.parentNode) {
                childrenEl.parentNode.removeChild(childrenEl);
            }
            chevron.textContent = '▸';
            isOpen = false;
        }

        // Clicking the name link navigates (folder) or opens the file; clicking
        // anywhere else on the row toggles expansion for folders.
        row.addEventListener('click', function (e) {
            if (e.target.closest('a.tree-name')) return;
            if (!isFolder) return;
            if (isOpen) close(); else open();
        });

        return { row: row, open: open, preExpand: !!preChildren };
    }

    function render() {
        container.textContent = '';
        var listing = document.createElement('div');
        container.appendChild(listing);
        listing.appendChild(disabledRow('…'));

        fetchFolder('/', activePath === '/' ? '' : activePath).then(function (resp) {
            listing.textContent = '';
            renderInto(listing, '/', resp.entries);
            if (activeRow) {
                try { activeRow.scrollIntoView({ block: 'nearest' }); } catch (e) {}
            }
        }).catch(function () {
            listing.textContent = '';
            var err = document.createElement('div');
            err.className = 'tree-row';
            err.textContent = '(failed — tap to retry)';
            err.addEventListener('click', function () { render(); });
            listing.appendChild(err);
        });
    }

    // Mobile: the tree FAB sits at the bottom of the stacked FAB group and
    // opens the tree's scroll container in the full-viewport Overlay
    // (overlay.js). The container always exists when not editing, so — per the
    // layout spec — the FAB always renders; the overlay auto-closes when a
    // folder/file link inside it navigates. Hidden on desktop by .fab CSS.
    function setupFab() {
        var fab = document.createElement('button');
        fab.type = 'button';
        fab.className = 'btn btn-fab fab fab-tree';
        fab.title = 'Folder tree';
        fab.setAttribute('aria-label', 'Folder tree');
        fab.innerHTML = '<svg viewBox="0 0 16 16" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="miter"><path d="M1 6h14v8H1zm0 0V4h5l1 2"/></svg>';
        fab.addEventListener('click', function () {
            if (typeof openOverlay === 'function') openOverlay(container);
        });
        document.body.appendChild(fab);
    }

    render();
    setupFab();
})();
