/**
 * Hash SPA router for Context Cockpit.
 */

const ROUTE_ALIASES = {
  graph: 'callgraph',
  bugs: 'memory',
};

/** @type {string[]} */
const KNOWN_ROUTES = [
  'overview',
  'commander',
  'context',
  'live',
  'knowledge',
  'memory',
  'agents',
  'graph',
  'search',
  'compression',
  'routes',
  'health',
  'deps',
  'learning',
  'symbols',
  'callgraph',
];

const ROUTE_LABELS = {
  overview: 'Home',
  commander: 'Context Health',
  context: 'Context Manager',
  live: 'Live Activity',
  knowledge: 'Knowledge',
  deps: 'Dependencies',
  compression: 'Savings',
  agents: 'Agents',
  memory: 'Memory',
  search: 'Search',
  learning: 'Trends',
  symbols: 'Symbols',
  callgraph: 'Call Graph',
  graph: 'Call Graph',
  routes: 'Routes',
  health: 'Health',
};

// One-line, plain-language explanation shown as a hint banner under the top bar.
const ROUTE_DESCRIPTIONS = {
  overview: 'Your savings at a glance.',
  commander: 'Context-window pressure and what to trim.',
  context: 'Everything currently loaded into the model context.',
  live: 'What lean-ctx is doing right now.',
  knowledge: 'Facts lean-ctx has learned about your project.',
  deps: 'How your modules depend on each other.',
  compression: 'Which files and read modes saved the most tokens.',
  agents: 'Connected agents and their activity.',
  memory: 'Saved episodes, procedures and bug memory.',
  search: 'Search indexed files, symbols and content.',
  learning: 'How your savings and efficiency change over time.',
  symbols: 'Functions, classes and types in your code.',
  callgraph: 'Which functions call which.',
  graph: 'Which functions call which.',
  routes: 'API routes detected in your project.',
  health: 'System health and reliability.',
};

/** @type {Record<string, () => void | Promise<void>>} */
const viewLoaders = {};

function normalizeViewId(raw) {
  let id = String(raw || '')
    .replace(/^#/, '')
    .trim()
    .toLowerCase();
  if (!id) id = 'overview';
  if (ROUTE_ALIASES[id]) id = ROUTE_ALIASES[id];
  return id;
}

function getActiveViewId() {
  return normalizeViewId(window.location.hash || 'overview');
}

function setNavActive(viewId) {
  const nav = document.querySelector('cockpit-nav');
  if (nav && typeof nav.setActive === 'function') nav.setActive(viewId);
  document.querySelectorAll('[data-cockpit-nav]').forEach(function (el) {
    el.classList.toggle('active', el.getAttribute('data-view') === viewId);
  });
}

function showViewSection(viewId) {
  document.querySelectorAll('.view').forEach(function (el) {
    el.classList.remove('active');
  });
  const target = document.getElementById('view-' + viewId);
  if (target) target.classList.add('active');

  setNavActive(viewId);
}

async function runLoader(viewId) {
  const label = ROUTE_LABELS[viewId] || viewId;
  const desc = ROUTE_DESCRIPTIONS[viewId] || '';
  document.dispatchEvent(new CustomEvent('lctx:view', { detail: { viewId, label, desc } }));
  const fn = viewLoaders[viewId];
  if (typeof fn === 'function') {
    try {
      await fn();
    } catch (_) {}
  }
}

function applyRouteFromHash() {
  let viewId = getActiveViewId();
  if (!document.getElementById('view-' + viewId)) {
    viewId = 'overview';
    const url = new URL(window.location.href);
    url.hash = '#overview';
    history.replaceState(null, '', url.pathname + url.search + url.hash);
  }
  showViewSection(viewId);
  runLoader(viewId);
}

function onHashChange() {
  applyRouteFromHash();
}

/**
 * @param {string} viewId
 * @param {{ replace?: boolean }} [opts]
 */
function navigateTo(viewId, opts) {
  const canon = normalizeViewId(viewId);
  const hash = '#' + canon;
  if (opts && opts.replace) {
    const url = new URL(window.location.href);
    url.hash = hash;
    history.replaceState(null, '', url.pathname + url.search + hash);
    applyRouteFromHash();
    return;
  }
  if (window.location.hash !== hash) {
    window.location.hash = hash;
  } else {
    applyRouteFromHash();
  }
}

function registerLoader(viewId, fn) {
  viewLoaders[normalizeViewId(viewId)] = fn;
}

function makeViewLoader(elementId) {
  return async function () {
    var el = document.getElementById(elementId);
    if (el && typeof el.loadData === 'function') await el.loadData();
  };
}

function initRouter() {
  var viewElementMap = {
    overview: 'overviewView',
    commander: 'commanderView',
    context: 'contextView',
    live: 'liveView',
    knowledge: 'knowledgeView',
    deps: 'depsView',
    compression: 'compressionView',
    agents: 'agentsView',
    memory: 'memoryView',
    search: 'searchView',
    learning: 'learningView',
    symbols: 'symbolsView',
    callgraph: 'callgraphView',
    routes: 'routesView',
    health: 'healthView',
  };
  for (var viewId in viewElementMap) {
    if (Object.prototype.hasOwnProperty.call(viewElementMap, viewId)) {
      registerLoader(viewId, makeViewLoader(viewElementMap[viewId]));
    }
  }
  window.addEventListener('hashchange', onHashChange);
  if (!window.location.hash || window.location.hash === '#') {
    var url = new URL(window.location.href);
    url.hash = '#overview';
    history.replaceState(null, '', url.pathname + url.search + url.hash);
  }
  applyRouteFromHash();
}

window.LctxRouter = {
  init: initRouter,
  navigateTo,
  registerLoader,
  normalizeViewId,
  getActiveViewId,
  ROUTE_ALIASES,
  KNOWN_ROUTES,
  ROUTE_LABELS,
  ROUTE_DESCRIPTIONS,
};

export {
  initRouter,
  navigateTo,
  registerLoader,
  normalizeViewId,
  getActiveViewId,
  ROUTE_ALIASES,
  KNOWN_ROUTES,
  ROUTE_LABELS,
  ROUTE_DESCRIPTIONS,
};
