// Sidebar: search filtering, active page highlighting, category collapse persistence
(function () {
  var searchInput = document.getElementById('search-input');
  var sidebarNav = document.getElementById('sidebar-nav');
  // Populated synchronously from window.WATCHFLOWS_NAV after renderSidebar().
  // No network fetch — search works in file:// mode too.
  var searchIndex = [];

  // Determine base path from current page location
  function getBasePath() {
    var path = window.location.pathname;
    // Count depth from docs root
    var docsIdx = path.indexOf('/docs/');
    if (docsIdx === -1) {
      // We're at the root or served directly
      return '';
    }
    var rel = path.substring(docsIdx + 6); // after /docs/
    var depth = (rel.match(/\//g) || []).length;
    var prefix = '';
    for (var i = 0; i < depth; i++) prefix += '../';
    return prefix;
  }

  // Base collapse toggle. Folded in from the former per-page inline <script>.
  // The persistence wrapper below overrides this to also save state.
  window.toggleCategory = function (name) {
    var cat = document.querySelector('[data-category="' + name + '"]');
    if (!cat) return;
    var items = cat.querySelector('.category-items');
    var chevron = cat.querySelector('.category-chevron');
    if (items.style.display === 'none') {
      items.style.display = '';
      chevron.style.transform = '';
    } else {
      items.style.display = 'none';
      chevron.style.transform = 'rotate(-90deg)';
    }
  };

  // HTML-escape a label so raw '&', '<', '>', quotes render literally.
  function esc(s) {
    return String(s)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
  }

  // Render the sidebar DOM from window.WATCHFLOWS_NAV into #sidebar-nav.
  // No-op (leaves existing markup) if nav-data.js didn't load.
  function renderSidebar() {
    var nav = window.WATCHFLOWS_NAV;
    if (!nav || !sidebarNav) return;
    var bp = getBasePath();

    // 1) Getting Started — #sidebar-nav's first child div
    var html = '<div class="mb-4">' +
      '<div class="text-xs font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500 mb-2 px-2">Getting Started</div>';
    nav.gettingStarted.forEach(function (item) {
      html += '<a href="' + bp + item.href + '" class="sidebar-link block px-2 py-1.5 text-sm rounded-md text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">' + esc(item.label) + '</a>';
    });
    html += '</div>';

    // 2) Concepts — #sidebar-nav's second child div
    html += '<div class="mb-4">' +
      '<div class="text-xs font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500 mb-2 px-2">Concepts</div>';
    nav.concepts.forEach(function (item) {
      html += '<a href="' + bp + item.href + '" class="sidebar-link block px-2 py-1.5 text-sm rounded-md text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">' + esc(item.label) + '</a>';
    });
    html += '</div>';

    // 3) Node categories — <div id="node-categories">
    html += '<div id="node-categories">';
    nav.categories.forEach(function (cat) {
      html += '<div class="mb-3 sidebar-category" data-category="' + cat.id + '">' +
        '<button onclick="toggleCategory(\'' + cat.id + '\')" class="flex items-center justify-between w-full px-2 py-1.5 text-sm font-semibold rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">' +
        '<span class="flex items-center gap-2">' +
        '<span class="w-2 h-2 rounded-full ' + cat.dot + '"></span>' +
        esc(cat.label) +
        '<span class="text-xs text-gray-400 font-normal">' + cat.count + '</span>' +
        '</span>' +
        '<svg class="category-chevron w-4 h-4 text-gray-400 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>' +
        '</button>' +
        '<div class="category-items ml-4 mt-1 space-y-0.5">';
      cat.items.forEach(function (item) {
        html += '<a href="' + bp + item.href + '" class="sidebar-link block px-2 py-1 text-sm rounded-md text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">' + esc(item.label) + '</a>';
      });
      html += '</div></div>';
    });
    html += '</div>';

    sidebarNav.innerHTML = html;
  }

  // Build the sidebar DOM before any highlight/collapse/search code queries it.
  renderSidebar();

  // Build the in-memory search index from nav data (replaces the old fetched
  // search-index.json). Shape {name, description, category, url} is identical to
  // the old JSON so the existing filter below works unchanged.
  function buildSearchIndex() {
    var nav = window.WATCHFLOWS_NAV;
    if (!nav) return;
    nav.categories.forEach(function (cat) {
      cat.items.forEach(function (item) {
        if (item.href.endsWith('index.html')) return; // skip Overview entries
        searchIndex.push({
          name: item.label,
          description: item.desc || '',
          category: cat.id,
          url: item.href
        });
      });
    });
    (nav.gettingStarted || []).forEach(function (item) {
      if (item.href === 'index.html') return; // skip site Overview
      searchIndex.push({ name: item.label, description: item.desc || '', category: 'concepts', url: item.href });
    });
    (nav.concepts || []).forEach(function (item) {
      searchIndex.push({ name: item.label, description: item.desc || '', category: 'concepts', url: item.href });
    });
  }
  buildSearchIndex();

  // Global id -> {label, href, token} lookup built from ALL categories, keyed by
  // the basename of each node's href (without .html). Used by both card-grid and
  // related-nodes rendering to resolve cross-category related ids.
  function buildNodeLookup() {
    var lookup = {};
    var nav = window.WATCHFLOWS_NAV;
    if (!nav) return lookup;
    nav.categories.forEach(function (cat) {
      var token = cat.dot.replace('bg-', '');
      cat.items.forEach(function (item) {
        if (item.href.endsWith('index.html')) return; // not a node
        var id = item.href.split('/').pop().replace(/\.html$/, '');
        lookup[id] = { label: item.label, href: item.href, token: token, category: cat.id };
      });
    });
    return lookup;
  }

  // Render the per-node card grid into #node-card-grid (keyed by its
  // data-category). No-op when the container is absent.
  function renderCardGrid() {
    var container = document.getElementById('node-card-grid');
    if (!container) return;
    var nav = window.WATCHFLOWS_NAV;
    if (!nav) return;
    var catId = container.getAttribute('data-category');
    var cat = nav.categories.filter(function (c) { return c.id === catId; })[0];
    if (!cat) return;
    var token = cat.dot.replace('bg-', '');
    var prefix = 'nodes/' + catId + '/';
    var html = '';
    cat.items.forEach(function (item) {
      if (item.href.endsWith('index.html')) return; // skip Overview, not a card
      // Card href is the node's href made relative to the category index page:
      // strip the 'nodes/<cat>/' prefix to get the sibling filename.
      var cardHref = item.href.indexOf(prefix) === 0 ? item.href.substring(prefix.length) : item.href;
      html += '<a href="' + cardHref + '" class="group block p-5 rounded-xl border border-gray-200 dark:border-gray-800 hover:border-' + token + '/50 hover:shadow-lg hover:shadow-' + token + '/5 transition-all">' +
        '<div class="flex items-center gap-2 mb-2">' +
        '<span class="text-lg">' + esc(item.icon || '') + '</span>' +
        '<h3 class="font-semibold">' + esc(item.label) + '</h3>' +
        '</div>' +
        '<p class="text-sm text-gray-500 dark:text-gray-400">' + esc(item.desc || '') + '</p>' +
        '</a>';
    });
    container.innerHTML = html;
  }

  // Render the "Related Nodes" section into #related-nodes for the current node
  // page (detected by URL). Writes nothing when the node has no related ids.
  function renderRelated() {
    var container = document.getElementById('related-nodes');
    if (!container) return;
    var nav = window.WATCHFLOWS_NAV;
    if (!nav) return;

    // Identify the current node id from the URL: last path segment minus .html.
    var currentId = window.location.pathname.split('/').pop().replace(/\.html$/, '');

    var lookup = buildNodeLookup();
    var current = lookup[currentId];
    if (!current) { container.innerHTML = ''; return; }

    // Find the matched nav item to read its related ids.
    var related = null;
    nav.categories.forEach(function (cat) {
      cat.items.forEach(function (item) {
        if (item.href.endsWith('index.html')) return;
        var id = item.href.split('/').pop().replace(/\.html$/, '');
        if (id === currentId) related = item.related || [];
      });
    });

    if (!related || related.length < 1) { container.innerHTML = ''; return; }

    var token = current.token; // current node's category accent token
    var chips = '';
    related.forEach(function (rid) {
      var target = lookup[rid];
      if (!target) return; // defensive: skip unresolved ids
      // Resolve to docs-root-relative href, then prefix with '../../' (node
      // pages live at depth 2 under docs).
      var href = '../../' + target.href;
      chips += '<a href="' + href + '" class="text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-800 hover:border-' + token + '/50 transition-colors">' + esc(target.label) + '</a>';
    });

    if (!chips) { container.innerHTML = ''; return; }

    container.innerHTML = '<h2 class="text-xl font-semibold mb-4">Related Nodes</h2>' +
      '<div class="flex flex-wrap gap-2">' + chips + '</div>';
  }

  // Active page highlighting
  function highlightActive() {
    var currentPath = window.location.pathname;
    var links = document.querySelectorAll('.sidebar-link');
    links.forEach(function (link) {
      var href = link.getAttribute('href');
      if (!href) return;
      // Resolve relative href to compare
      var linkPath = new URL(href, window.location.href).pathname;
      if (linkPath === currentPath) {
        link.classList.remove('text-gray-600', 'dark:text-gray-400');
        link.classList.add('bg-blue-50', 'dark:bg-blue-900/20', 'text-blue-700', 'dark:text-blue-300', 'font-medium');
        // Ensure parent category is expanded
        var cat = link.closest('.sidebar-category');
        if (cat) {
          var items = cat.querySelector('.category-items');
          var chevron = cat.querySelector('.category-chevron');
          if (items) items.style.display = '';
          if (chevron) chevron.style.transform = '';
        }
      }
    });
  }

  // Search filtering
  if (searchInput) {
    searchInput.addEventListener('input', function () {
      var query = this.value.toLowerCase().trim();
      var categories = document.querySelectorAll('.sidebar-category');

      if (!query) {
        // Show everything
        categories.forEach(function (cat) {
          cat.style.display = '';
          var links = cat.querySelectorAll('.sidebar-link');
          links.forEach(function (l) { l.style.display = ''; });
          // Restore items visibility
          var items = cat.querySelector('.category-items');
          if (items) items.style.display = '';
        });
        // Show concepts section too
        var conceptLinks = sidebarNav.querySelectorAll(':scope > div:not(#node-categories)');
        conceptLinks.forEach(function (el) { el.style.display = ''; });
        removeNoResults();
        return;
      }

      // Filter nodes from search index
      var matches = searchIndex.filter(function (node) {
        return node.name.toLowerCase().includes(query) ||
               node.description.toLowerCase().includes(query);
      });
      var matchUrls = new Set(matches.map(function (m) { return m.url; }));
      var matchCategories = new Set(matches.map(function (m) { return m.category; }));

      // Also check concept pages
      var conceptSection = sidebarNav.querySelector(':scope > div:nth-child(2)');
      if (conceptSection) {
        var conceptLinks = conceptSection.querySelectorAll('.sidebar-link');
        var hasConceptMatch = false;
        conceptLinks.forEach(function (link) {
          var text = link.textContent.toLowerCase();
          if (text.includes(query)) {
            link.style.display = '';
            hasConceptMatch = true;
          } else {
            link.style.display = 'none';
          }
        });
        conceptSection.style.display = hasConceptMatch ? '' : 'none';
      }

      // Hide getting started if searching
      var gsSection = sidebarNav.querySelector(':scope > div:first-child');
      if (gsSection) gsSection.style.display = 'none';

      categories.forEach(function (cat) {
        var catName = cat.dataset.category;
        if (!matchCategories.has(catName)) {
          cat.style.display = 'none';
          return;
        }
        cat.style.display = '';
        var items = cat.querySelector('.category-items');
        if (items) items.style.display = '';
        var chevron = cat.querySelector('.category-chevron');
        if (chevron) chevron.style.transform = '';

        var links = items ? items.querySelectorAll('.sidebar-link') : [];
        links.forEach(function (link) {
          var href = link.getAttribute('href');
          // Always hide overview links during search
          if (href && href.endsWith('index.html')) {
            link.style.display = 'none';
            return;
          }
          // Check if this link matches any result
          var isMatch = false;
          matchUrls.forEach(function (url) {
            if (href && href.includes(url)) isMatch = true;
          });
          link.style.display = isMatch ? '' : 'none';
        });
      });

      // Show "no results" if nothing matches
      if (matches.length === 0) {
        showNoResults();
      } else {
        removeNoResults();
      }
    });
  }

  function showNoResults() {
    removeNoResults();
    var el = document.createElement('div');
    el.id = 'no-results';
    el.className = 'px-2 py-4 text-sm text-gray-400 dark:text-gray-500 text-center';
    el.textContent = 'No matches';
    var nodeCategories = document.getElementById('node-categories');
    if (nodeCategories) nodeCategories.appendChild(el);
  }

  function removeNoResults() {
    var el = document.getElementById('no-results');
    if (el) el.remove();
  }

  // Category collapse state persistence
  var COLLAPSE_KEY = 'watchflows-docs-collapsed';
  function getCollapsed() {
    try { return JSON.parse(localStorage.getItem(COLLAPSE_KEY)) || []; }
    catch (e) { return []; }
  }

  function restoreCollapsed() {
    var collapsed = getCollapsed();
    collapsed.forEach(function (name) {
      var cat = document.querySelector('[data-category="' + name + '"]');
      if (!cat) return;
      var items = cat.querySelector('.category-items');
      var chevron = cat.querySelector('.category-chevron');
      if (items) items.style.display = 'none';
      if (chevron) chevron.style.transform = 'rotate(-90deg)';
    });
  }

  // Override the global toggleCategory to persist state
  var origToggle = window.toggleCategory;
  window.toggleCategory = function (name) {
    origToggle(name);
    var collapsed = getCollapsed();
    var cat = document.querySelector('[data-category="' + name + '"]');
    var items = cat && cat.querySelector('.category-items');
    var isNowHidden = items && items.style.display === 'none';
    if (isNowHidden) {
      if (collapsed.indexOf(name) === -1) collapsed.push(name);
    } else {
      collapsed = collapsed.filter(function (c) { return c !== name; });
    }
    localStorage.setItem(COLLAPSE_KEY, JSON.stringify(collapsed));
  };

  // Init
  highlightActive();
  restoreCollapsed();
  renderCardGrid();
  renderRelated();
})();
