// Partial: _nav-tree.js.j2 — Nav tree rendering, tabs, header stats

// =====================================================================
// Header Stats
// =====================================================================

function updateHeaderStats() {
    // Compute level + main counts from tree data (unique IDs)
    // Test/result counts come from /api/status (not in tree data)
    var rows = editState.treeData;
    if (!rows || rows.length === 0) return;
    var seen = {};
    var counts = {prd: 0, ops: 0, dev: 0, main: 0};
    var repoCounts = {};  // { "CAL": 3, "TTN": 2 }
    for (var i = 0; i < rows.length; i++) {
        var r = rows[i];
        if (seen[r.id]) continue;
        seen[r.id] = true;
        if (r.level) {
            var lev = r.level.toLowerCase();
            if (counts[lev] !== undefined) counts[lev]++;
            if (!r.is_associated) counts.main++;
            // Track associated repo prefixes
            if (r.is_associated && r.repo_prefix && r.repo_prefix !== 'CORE') {
                repoCounts[r.repo_prefix] = (repoCounts[r.repo_prefix] || 0) + 1;
            }
        }
    }
    document.getElementById('stat-prd').textContent = 'PRD: ' + counts.prd;
    document.getElementById('stat-ops').textContent = 'OPS: ' + counts.ops;
    document.getElementById('stat-dev').textContent = 'DEV: ' + counts.dev;
    document.getElementById('stat-main').textContent = 'Core: ' + counts.main;

    // Fetch test/result counts from /api/status (informational badges)
    apiFetch('/api/status').then(function(data) {
        if (!data) return;
        var nc = data.node_counts || {};
        var testCount = nc.test || 0;
        var resultCount = nc.test_result || 0;
        var testBadge = document.getElementById('stat-tests');
        var resultBadge = document.getElementById('stat-results');
        if (testCount > 0) {
            testBadge.textContent = 'Tests: ' + testCount;
            testBadge.style.display = '';
        } else {
            testBadge.style.display = 'none';
        }
        if (resultCount > 0) {
            resultBadge.textContent = 'Results: ' + resultCount;
            resultBadge.style.display = '';
        } else {
            resultBadge.style.display = 'none';
        }

        var assocRepos = data.associated_repos || [];
        // Build name lookup from API: { "CAL": "callisto", ... }
        var nameMap = {};
        for (var j = 0; j < assocRepos.length; j++) {
            nameMap[assocRepos[j].code] = assocRepos[j].name;
        }
        var container = document.getElementById('repo-badges-container');
        var sep = document.getElementById('repo-sep');
        if (!container) return;
        container.innerHTML = '';
        var repoPrefixes = Object.keys(repoCounts).sort();
        editState.knownRepos = repoPrefixes;
        if (repoPrefixes.length === 0) {
            if (sep) sep.style.display = 'none';
            return;
        }
        if (sep) sep.style.display = '';
        for (var k = 0; k < repoPrefixes.length; k++) {
            var code = repoPrefixes[k];
            var fullName = nameMap[code];
            var displayName = fullName ? fullName.charAt(0).toUpperCase() + fullName.slice(1) : code;
            var count = repoCounts[code];
            var badge = document.createElement('span');
            badge.className = 'stat-badge repo';
            badge.id = 'stat-repo-' + code;
            badge.title = 'Click to hide ' + displayName + ' requirements';
            badge.textContent = displayName + ': ' + count;
            badge.setAttribute('data-repo', code);
            badge.onclick = (function(repoCode) {
                return function() { toggleRepoFilter(repoCode); };
            })(code);
            // Restore dimmed state if filter is active
            if (editState.activeFilters.hiddenRepos &&
                editState.activeFilters.hiddenRepos.indexOf(code) >= 0) {
                badge.classList.add('dimmed');
            }
            container.appendChild(badge);
        }
    });
}

async function refreshDirtyCount() {
    const data = await apiFetch('/api/dirty');
    if (!data) return;
    editState.mutationCount = data.mutation_count || 0;
    const badge = document.getElementById('unsaved-badge');
    const btnSave = document.getElementById('btn-save');
    const btnRevert = document.getElementById('btn-revert');
    const btnUndo = document.getElementById('btn-undo');
    if (editState.mutationCount > 0) {
        badge.textContent = editState.mutationCount;
        badge.classList.remove('hidden');
        btnSave.disabled = false;
        btnRevert.disabled = false;
        btnUndo.disabled = false;
    } else {
        badge.classList.add('hidden');
        btnSave.disabled = true;
        btnRevert.disabled = true;
        btnUndo.disabled = true;
    }
}

// =====================================================================
// Nav Tree
// =====================================================================

async function loadTreeData() {
    const data = await apiFetch('/api/tree-data');
    if (!data) return;
    editState.treeData = data;
    updateHeaderStats();
    renderNavTree();
}

function renderNavTree() {
    const container = document.getElementById('nav-tree-container');
    const activeTab = editState.activeNavTab;
    const rows = editState.treeData;

    if (!rows || rows.length === 0) {
        container.innerHTML = '<div style="padding:20px;color:#adb5bd;text-align:center;font-size:0.85rem;">No items found</div>';
        return;
    }

    // Filter by tab — req tab shows requirements only
    let filteredRows;
    if (activeTab === 'req') {
        filteredRows = rows.filter(function(r) {
            return r.level && r.level !== '';
        });
    } else {
        filteredRows = rows;
    }

    if (activeTab === 'journey') {
        var journeys = rows.filter(function(r) { return r.kind === 'journey'; });
        if (journeys.length === 0) {
            container.innerHTML = '<div style="padding:20px;color:#adb5bd;text-align:center;font-size:0.85rem;">No journey data available.</div>';
            return;
        }
        var jhtml = '';
        for (var ji = 0; ji < journeys.length; ji++) {
            var j = journeys[ji];
            var jSelected = editState.openCards.has(j.id) ? ' selected' : '';
            jhtml += '<div class="nav-tree-row nav-tree-journey' + jSelected + '" ' +
                'data-id="' + j.id + '" data-kind="journey" ' +
                'onclick="openCard(\'' + j.id + '\')">' +
                '<span class="nav-tree-kind-icon">&#x1F9ED;</span>' +
                '<span class="nav-tree-id" style="color:#6c757d;">' + escapeHtml(j.id) + '</span>' +
                '<span class="nav-tree-title">' + escapeHtml(j.title) + '</span>' +
                '</div>';
        }
        container.innerHTML = jhtml;
        return;
    }

    if (activeTab !== 'req' && activeTab !== 'journey') {
        container.innerHTML = '<div style="padding:20px;color:#adb5bd;text-align:center;font-size:0.85rem;">Select a tab to view content.</div>';
        return;
    }

    // Apply edit-mode filters
    const totalBeforeFilter = filteredRows.length;
    const af = editState.activeFilters;
    var hiddenRepos = af.hiddenRepos || [];
    const hasActiveFilter = af.levelPrd || af.levelOps || af.levelDev ||
        af.uncommitted || af.changed || af.main || af.leaf ||
        af.deprecated || af.roadmap ||
        hiddenRepos.length > 0 ||
        editState.filterStatus !== '' || editState.filterCoverage !== '';

    // Track which rows are direct filter matches (vs ancestor context)
    var matchSet = null;
    var directMatchCount = 0;

    if (hasActiveFilter) {
        // Build parent-index map: for each row index, find its parent row index
        // (nearest preceding row whose id matches this row's parent_id).
        // This handles DAG flattening where the same ID appears multiple times.
        var parentIdx = new Array(filteredRows.length);
        for (var i = 0; i < filteredRows.length; i++) {
            parentIdx[i] = -1;
            if (filteredRows[i].parent_id) {
                for (var j = i - 1; j >= 0; j--) {
                    if (filteredRows[j].id === filteredRows[i].parent_id) {
                        parentIdx[i] = j;
                        break;
                    }
                }
            }
        }
        // First pass: mark row indices that directly match the filter
        var matchIndices = new Set();
        for (var i = 0; i < filteredRows.length; i++) {
            var r = filteredRows[i];
            // Level filters (when active, HIDE that level)
            if (af.levelPrd && r.level === 'PRD') continue;
            if (af.levelOps && r.level === 'OPS') continue;
            if (af.levelDev && r.level === 'DEV') continue;
            // Associated repo filters (hide specific repos)
            if (hiddenRepos.length > 0 && r.is_associated &&
                r.repo_prefix && hiddenRepos.indexOf(r.repo_prefix) >= 0) continue;
            // Git filters (when active, SHOW only matching)
            if (af.uncommitted && !r.is_uncommitted) continue;
            if (af.changed && !r.is_changed) continue;
            // Core filter (hide core/non-associated items)
            if (af.main && !r.is_associated) continue;
            // Leaf only
            if (af.leaf && !r.is_leaf) continue;
            // Hide Deprecated (when active, hide items with Deprecated status)
            if (af.deprecated && r.status && r.status.toLowerCase() === 'deprecated') continue;
            // Hide Roadmap (when active, hide items with Roadmap/Planned status)
            if (af.roadmap && r.status && (r.status.toLowerCase() === 'roadmap' || r.status.toLowerCase() === 'planned')) continue;
            // Status dropdown
            if (editState.filterStatus && r.status !== editState.filterStatus) continue;
            // Coverage dropdown
            if (editState.filterCoverage && r.coverage !== editState.filterCoverage) continue;
            matchIndices.add(i);
        }
        directMatchCount = matchIndices.size;
        // Second pass: include ancestors of matching rows to preserve tree structure
        var allVisible = new Set(matchIndices);
        for (var i = 0; i < filteredRows.length; i++) {
            if (matchIndices.has(i)) {
                var pi = parentIdx[i];
                while (pi >= 0) {
                    if (allVisible.has(pi)) break;  // already included
                    allVisible.add(pi);
                    pi = parentIdx[pi];
                }
            }
        }
        // Build a set of original indices for matched rows (for dimming context-only rows)
        matchSet = new Set();
        var finalIdx = 0;
        for (var i = 0; i < filteredRows.length; i++) {
            if (allVisible.has(i)) {
                if (matchIndices.has(i)) matchSet.add(finalIdx);
                finalIdx++;
            }
        }
        filteredRows = filteredRows.filter(function(r, idx) { return allVisible.has(idx); });
    }

    // Update counter
    var counterEl = document.getElementById('edit-counter');
    if (counterEl) {
        if (hasActiveFilter) {
            counterEl.textContent = directMatchCount + ' / ' + totalBeforeFilter;
        } else {
            counterEl.textContent = '';
        }
    }

    if (hasActiveFilter && directMatchCount === 0) {
        container.innerHTML = '<div style="padding:20px;color:#adb5bd;text-align:center;font-size:0.85rem;">No matching requirements</div>';
        return;
    }

    let html = '';
    filteredRows.forEach(function(row, arrIdx) {
        // Determine if collapsed
        const isCollapsed = editState.collapsedTreeNodes.has(row.id);
        // Check if parent is collapsed (skip rendering)
        if (row.depth > 0 && isAncestorCollapsed(row, filteredRows)) {
            return; // don't render
        }

        const indents = [];
        for (let i = 0; i < row.depth; i++) {
            indents.push('<span class="nav-tree-indent"></span>');
        }

        const toggleClass = row.has_children
            ? (isCollapsed ? 'nav-tree-toggle' : 'nav-tree-toggle')
            : 'nav-tree-toggle leaf';
        const toggleIcon = row.has_children
            ? (isCollapsed ? '&#9654;' : '&#9660;')
            : '';

        const selectedClass = editState.openCards.has(row.id) ? ' selected' : '';
        // Dim context-only rows when filters are active
        const dimClass = (matchSet && !matchSet.has(arrIdx)) ? ' filter-dim' : '';

        // ── REQUIREMENT row rendering ──
        const levelClass = row.level ? row.level.toLowerCase() : '';
        const shortId = row.id.replace('REQ-', '');

        // Coverage icon
        var covIcon = '';
        if (row.coverage === 'full') {
            covIcon = '<span class="coverage-icon full" title="Full coverage">&#x25CF;</span>';
        } else if (row.coverage === 'partial') {
            covIcon = '<span class="coverage-icon partial" title="Partial coverage">&#x25D0;</span>';
        } else {
            covIcon = '<span class="coverage-icon none" title="No coverage">&#x25CB;</span>';
        }

        // Status badge (with optional validation color + tooltip for Active status)
        var statusBadge = '';
        if (row.status) {
            var statusLower = row.status.toLowerCase();
            var valClass = row.validation_color ? ' val-' + row.validation_color : '';
            var tipAttr = row.validation_tip ? ' data-tip="' + escapeHtml(row.validation_tip) + '"' : '';
            statusBadge = '<span class="status-badge ' + statusLower + valClass + '"' + tipAttr + ' style="font-size:0.65rem;padding:1px 4px;margin-left:auto;">' + row.status;
            if (row.is_changed) statusBadge += '<span class="change-indicator">&#x25C6;</span>';
            statusBadge += '</span>';
        }

        html += '<div class="nav-tree-row' + selectedClass + dimClass + '" ' +
            'data-id="' + row.id + '" ' +
            'data-parent="' + (row.parent_id || '') + '" ' +
            'data-depth="' + row.depth + '" ' +
            'data-kind="requirement" ' +
            'onclick="openCard(\'' + row.id + '\')">' +
            indents.join('') +
            '<button class="' + toggleClass + '" onclick="event.stopPropagation(); toggleTreeNode(\'' + row.id + '\')">' +
            toggleIcon + '</button>' +
            covIcon +
            (levelClass ? '<span class="nav-tree-level ' + levelClass + '">' + row.level + '</span>' : '') +
            '<span class="nav-tree-id">' + shortId + '</span>' +
            '<span class="nav-tree-title">' + escapeHtml(row.title || '') + '</span>' +
            statusBadge +
            '</div>';
    });

    container.innerHTML = html;
}

function isAncestorCollapsed(row, allRows) {
    if (!row.parent_id) return false;
    // Walk up the parent chain
    let parentId = row.parent_id;
    while (parentId) {
        if (editState.collapsedTreeNodes.has(parentId)) return true;
        // Find parent row
        const parentRow = allRows.find(function(r) { return r.id === parentId; });
        if (!parentRow) break;
        parentId = parentRow.parent_id;
    }
    return false;
}

function toggleTreeNode(nodeId) {
    if (editState.collapsedTreeNodes.has(nodeId)) {
        editState.collapsedTreeNodes.delete(nodeId);
    } else {
        editState.collapsedTreeNodes.add(nodeId);
    }
    renderNavTree();
    saveState();
}

function switchNavTab(kind) {
    editState.activeNavTab = kind;
    document.querySelectorAll('.nav-tab').forEach(function(tab) {
        tab.classList.toggle('active', tab.dataset.kind === kind);
    });
    renderNavTree();
    saveState();
}

// =====================================================================
// Edit-Mode Filters
// =====================================================================

function toggleEditLevelFilter(key) {
    editState.activeFilters[key] = !editState.activeFilters[key];
    // Toggle dimmed state on header stat badge
    var badgeMap = { levelPrd: 'stat-prd', levelOps: 'stat-ops', levelDev: 'stat-dev' };
    var badge = document.getElementById(badgeMap[key]);
    if (badge) badge.classList.toggle('dimmed', editState.activeFilters[key]);
    applyEditFilters();
}

function toggleEditFilter(key) {
    editState.activeFilters[key] = !editState.activeFilters[key];
    // Update button state for git filters
    var btnMap = { uncommitted: 'edit-btn-uncommitted', changed: 'edit-btn-changed' };
    if (btnMap[key]) {
        var btn = document.getElementById(btnMap[key]);
        if (btn) btn.classList.toggle('active', editState.activeFilters[key]);
    }
    // Update stat badge state for core filter (dimmed = hiding associated)
    if (key === 'main') {
        var mainBadge = document.getElementById('stat-main');
        if (mainBadge) mainBadge.classList.toggle('dimmed', editState.activeFilters.main);
    }
    // Update checkbox state for toggles
    var checkMap = {
        leaf: 'edit-toggle-leaf',
        deprecated: 'edit-toggle-deprecated',
        roadmap: 'edit-toggle-roadmap',
    };
    if (checkMap[key]) {
        var cb = document.getElementById(checkMap[key]);
        if (cb) cb.checked = editState.activeFilters[key];
    }
    applyEditFilters();
}

function toggleRepoFilter(repoCode) {
    if (!editState.activeFilters.hiddenRepos) {
        editState.activeFilters.hiddenRepos = [];
    }
    var idx = editState.activeFilters.hiddenRepos.indexOf(repoCode);
    if (idx >= 0) {
        editState.activeFilters.hiddenRepos.splice(idx, 1);
    } else {
        editState.activeFilters.hiddenRepos.push(repoCode);
    }
    // Update badge dimmed state
    var badge = document.getElementById('stat-repo-' + repoCode);
    if (badge) badge.classList.toggle('dimmed', idx < 0);
    applyEditFilters();
}

function applyEditFilters() {
    // Sync dropdown values to state
    var statusSel = document.getElementById('edit-filter-status');
    var covSel = document.getElementById('edit-filter-coverage');
    if (statusSel) editState.filterStatus = statusSel.value;
    if (covSel) editState.filterCoverage = covSel.value;
    renderNavTree();
    saveState();
}

function clearEditFilters() {
    // Reset all filter state
    editState.activeFilters = {
        levelPrd: false, levelOps: false, levelDev: false,
        uncommitted: false, changed: false, main: false, leaf: false,
        deprecated: false, roadmap: false,
        hiddenRepos: []
    };
    editState.filterStatus = '';
    editState.filterCoverage = '';
    // Reset header stat badge states
    document.querySelectorAll('.stat-badge').forEach(function(b) {
        b.classList.remove('dimmed');
        b.classList.remove('active');
    });
    // Reset toolbar buttons
    document.querySelectorAll('#edit-toolbar .btn-group .btn').forEach(function(b) { b.classList.remove('active'); });
    var statusSel = document.getElementById('edit-filter-status');
    var covSel = document.getElementById('edit-filter-coverage');
    if (statusSel) statusSel.value = '';
    if (covSel) covSel.value = '';
    var leafCb = document.getElementById('edit-toggle-leaf');
    if (leafCb) leafCb.checked = false;
    var deprecatedCb = document.getElementById('edit-toggle-deprecated');
    if (deprecatedCb) deprecatedCb.checked = false;
    var roadmapCb = document.getElementById('edit-toggle-roadmap');
    if (roadmapCb) roadmapCb.checked = false;
    renderNavTree();
    saveState();
}

// =====================================================================
// Collapse / Expand All
// =====================================================================

function collapseAllTreeNodes() {
    var rows = editState.treeData;
    if (!rows) return;
    for (var i = 0; i < rows.length; i++) {
        if (rows[i].has_children) {
            editState.collapsedTreeNodes.add(rows[i].id);
        }
    }
    renderNavTree();
    saveState();
}

function expandAllTreeNodes() {
    editState.collapsedTreeNodes.clear();
    renderNavTree();
    saveState();
}
