/* FORGE — hash router & App composition. Owns the screen registry.
   URL format: #/forge/dashboard, #/build/eco, #/auditor/ledger, etc. */

const { useState: uSR, useEffect: uER, useMemo: uMR } = React;

function parseHash() {
  const raw = window.location.hash.replace(/^#/, "") || "/forge/landing";
  const h = raw.split("?")[0].split("#")[0] || "/forge/landing";
  const parts = h.split("/").filter(Boolean);
  const mode = parts[0] || "forge";
  const path = "/" + parts.join("/");
  return { mode: mode, path: path };
}

function useHashRoute() {
  const [route, setRoute] = uSR(parseHash());
  uER(function() {
    const onHash = function() { setRoute(parseHash()); };
    window.addEventListener("hashchange", onHash);
    return function() { window.removeEventListener("hashchange", onHash); };
  }, []);
  return route;
}

function navigate(path) {
  window.location.hash = path;
}

// Helper — pick a sensible default selected part number for the active tenant.
// For Tritan (pump CDMO), use a meaningful pump part. For HTU-220 stub, keep the legacy turbine ref.
function defaultSelectedPn() {
  if (typeof getActiveTenant !== "function") return "HTU-220.10.02";
  const t = getActiveTenant();
  if (t && t.tenant && t.tenant.id === "tritan") {
    if (t.parts && t.parts.length > 10 && t.parts[10] && t.parts[10].num) return t.parts[10].num;
    if (t.boms && t.boms[0] && t.boms[0].lines && t.boms[0].lines[0]) return t.boms[0].lines[0].part_num || "M-27418.10.02";
    return "M-27418.10.02";
  }
  return "HTU-220.10.02";
}

// Helper — render a component if it exists in global scope, else NotFound
function renderIfExists(name, props) {
  const Cmp = (typeof window !== "undefined") ? window[name] : undefined;
  if (typeof Cmp === "function") {
    return React.createElement(Cmp, props || {});
  }
  // try direct ref via eval-ish: function declarations attach to globalThis in browser
  const direct = (typeof globalThis !== "undefined") ? globalThis[name] : undefined;
  if (typeof direct === "function") {
    return React.createElement(direct, props || {});
  }
  const NF = (typeof window !== "undefined" && typeof window.NotFound === "function") ? window.NotFound : null;
  return NF ? React.createElement(NF, { path: name }) : React.createElement("div", null, "missing: " + name);
}

// Parametric-path matcher. Returns a params object if `actualPath` matches
// `routePath`, else null. `routePath` segments starting with ":" are bound
// to the actualPath segment at the same position. Exact paths return {}.
//
// Examples:
//   matchPath("/build/eco/new", "/build/eco/new")    → {}
//   matchPath("/build/eco/:id", "/build/eco/ECO-51") → { id: "ECO-51" }
//   matchPath("/build/eco/:id", "/build/eco")        → null  (segment count)
//   matchPath("/build/eco",     "/build/eco/new")    → null  (segment count)
function matchPath(routePath, actualPath) {
  if (routePath === actualPath) return {};
  const rSegs = String(routePath).split("/").filter(Boolean);
  const aSegs = String(actualPath).split("/").filter(Boolean);
  if (rSegs.length !== aSegs.length) return null;
  const params = {};
  for (let i = 0; i < rSegs.length; i++) {
    if (rSegs[i].startsWith(":")) {
      params[rSegs[i].slice(1)] = decodeURIComponent(aSegs[i]);
    } else if (rSegs[i] !== aSegs[i]) {
      return null;
    }
  }
  return params;
}

// Built-in routes — wire to ACTUAL component names found in existing files.
// Component names verified via grep against client/*.jsx.
const BUILTIN_ROUTES = [
  // Forge mode
  { path: "/forge/landing",     mode: "forge",    title: "Landing",       renderer: function() {
      return renderIfExists("ScreenLanding", {
        onTryForge:  function() { navigate("/forge/onboarding"); },
        onBookDemo:  function() {},
        onTour:      function() { navigate("/forge/dashboard"); },
        onReadFCP:   function() {},
      });
    } },
  { path: "/forge/onboarding",  mode: "forge",    title: "Onboarding",    renderer: function() {
      return renderIfExists("ScreenOnboarding", {
        setToast:    function() {},
        onComplete:  function() { navigate("/forge/dashboard"); },
      });
    } },
  { path: "/forge/customer-onboarding",  mode: "forge",    title: "Customer Onboarding",    renderer: function() {
      return renderIfExists("ScreenOnboarding", {
        setToast:    function() {},
        onComplete:  function() { navigate("/forge/dashboard"); },
      });
    } },
  { path: "/forge/dashboard",   mode: "forge",    title: "Dashboard",     renderer: function() { return renderIfExists("ScreenDashboard"); } },
  { path: "/forge/viewer",      mode: "forge",    title: "Viewer",        renderer: function() { return renderIfExists("ScreenViewer", { selectedPn: defaultSelectedPn(), setSelectedPn: function() {} }); } },
  { path: "/forge/ebom",        mode: "forge",    title: "E-BOM",         renderer: function() { return renderIfExists("ScreenEBOM", { selectedPn: defaultSelectedPn(), setSelectedPn: function() {} }); } },
  { path: "/forge/ebomtombom",  mode: "forge",    title: "E-BOM → M-BOM", renderer: function() { return renderIfExists("ScreenETM", { mode: "dag" }); } },
  { path: "/forge/sim-setup",   mode: "forge",    title: "Sim · Setup",   renderer: function() { return renderIfExists("ScreenSimSetup"); } },
  { path: "/forge/sim-results", mode: "forge",    title: "Sim · Results", renderer: function() { return renderIfExists("ScreenSimResults"); } },
  { path: "/forge/plc",         mode: "forge",    title: "Product Lifecycle", renderer: function() { return renderIfExists("ScreenProductLifecycle"); } },
  // PR-15: FSM lifecycle visualizer — renders the active tenant's ECO state
  // machine via Mermaid (lazy-loaded). Source of truth: server/state-machines/visualize.js.
  { path: "/forge/lifecycle",   mode: "forge",    title: "Lifecycle FSM",   renderer: function() { return renderIfExists("ScreenLifecycleViz"); } },

  // Build mode
  { path: "/build/mbom",        mode: "build",    title: "M-BOM · Routing", renderer: function() { return renderIfExists("ScreenMBOM"); } },
  { path: "/build/eco",         mode: "build",    title: "Change Orders",   renderer: function() { return renderIfExists("ScreenECO"); } },
  // Deep-link to a specific ECO. Re-uses ScreenECO with a selectedId prop;
  // the existing list-pane stays so users can hop between ECOs from the
  // list. Static /build/eco/new (registered by pump/eco-compose.jsx) still
  // wins via the exact-match-first rule in App() below.
  { path: "/build/eco/:id",     mode: "build",    title: "Change Order",    renderer: function(params) {
      return renderIfExists("ScreenECO", { selectedId: params && params.id });
    } },
  { path: "/build/approvals",   mode: "build",    title: "Approvals",       renderer: function() { return renderIfExists("ScreenApprovals"); } },
  { path: "/build/erp",         mode: "build",    title: "ERP Release",     renderer: function() { return renderIfExists("ScreenERP", { mode: "queue" }); } },
  { path: "/build/workflows",   mode: "build",    title: "Workflow Hub",    renderer: function() { return renderIfExists("ScreenWorkflows", { setToast: function() {} }); } },
  { path: "/build/connectors",  mode: "build",    title: "Connectors",      renderer: function() { return renderIfExists("ScreenConnectors", { setToast: function() {} }); } },

  // Plan mode
  { path: "/plan/gantt",        mode: "plan",     title: "Schedule",        renderer: function() { return renderIfExists("ScreenGantt"); } },
  { path: "/plan/analytics",    mode: "plan",     title: "Analytics",       renderer: function() { return renderIfExists("ScreenAnalytics"); } },

  // Line mode
  { path: "/line/queue",        mode: "line",     title: "Line",            renderer: function() { return renderIfExists("ScreenLine"); } },
  // /line/analytics shares the ScreenAnalytics renderer with /plan/analytics
  // — the nav id "analytics" in the per-tenant Line group tail-matches both
  // paths; without this entry the sidebar onPick falls through to /plan/...
  { path: "/line/analytics",    mode: "line",     title: "Analytics",       renderer: function() { return renderIfExists("ScreenAnalytics"); } },
  { path: "/line/connectors",   mode: "line",     title: "Connectors",      renderer: function() { return renderIfExists("ScreenConnectors", { setToast: function() {} }); } },

  // Traveler mode
  { path: "/traveler/console",  mode: "traveler", title: "Traveler",        renderer: function() { return renderIfExists("ScreenTraveler"); } },

  // Auditor mode
  { path: "/auditor/ledger",    mode: "auditor",  title: "Audit Ledger",    renderer: function() { return renderIfExists("ScreenAuditor"); } },

  // Organization (kept under forge mode for now)
  { path: "/forge/people",      mode: "forge",    title: "People & HR",     renderer: function() { return renderIfExists("ScreenPeople"); } },
  { path: "/forge/docs",        mode: "forge",    title: "Documents",       renderer: function() { return renderIfExists("ScreenDocuments"); } },
  { path: "/forge/maintenance", mode: "forge",    title: "Maintenance",     renderer: function() { return renderIfExists("ScreenMaintenance"); } },
  { path: "/forge/integrations",mode: "forge",    title: "Integrations",    renderer: function() { return renderIfExists("ScreenIntegrations"); } },
  { path: "/forge/analytics",   mode: "forge",    title: "Analytics",       renderer: function() { return renderIfExists("ScreenAnalytics"); } },
  { path: "/forge/connectors",  mode: "forge",    title: "Connectors",      renderer: function() { return renderIfExists("ScreenConnectors", { setToast: function() {} }); } },
];

function App() {
  const route = useHashRoute();
  const tenant = useActiveTenant();

  const allRoutes = uMR(function() {
    const tid = tenant && tenant.tenant && tenant.tenant.id;
    const win = (typeof window !== "undefined") ? window : {};
    // Pump deep demo is tritan-only. Other tenants get their own deep routes.
    const pump = tid === "tritan" && Array.isArray(win.PUMP_ROUTES)
      ? win.PUMP_ROUTES
      : (tid === "tritan" && typeof PUMP_ROUTES !== "undefined" ? PUMP_ROUTES : []);
    const mittelstand = tid === "mittelstand" && Array.isArray(win.MITTELSTAND_ROUTES)
      ? win.MITTELSTAND_ROUTES
      : [];
    // Aetherion is the canonical id; htu220 is a back-compat alias.
    const aetherion = (tid === "aetherion" || tid === "htu220")
      && (Array.isArray(win.AETHERION_ROUTES) || Array.isArray(win.SPACE_ROUTES))
      ? (win.AETHERION_ROUTES || win.SPACE_ROUTES)
      : [];
    // Aurora removed — no longer a Forge tenant (parked as EPCC plant-operator ICP).
    // Tenant routes first: deep demos override generic built-ins on path collision.
    // Order: per-tenant deep routes -> pump (only for tritan) -> built-ins.
    return mittelstand.concat(aetherion, pump, BUILTIN_ROUTES);
  }, [route.path, tenant && tenant.tenant && tenant.tenant.id]);

  // Match routes — exact first (cheap), then parametric. Static routes (no
  // ":" in the path) win over parametric ones at the same prefix so that
  // /build/eco/new keeps matching the compose form even when /build/eco/:id
  // is also registered.
  let matched = null;
  let matchedParams = null;
  for (let i = 0; i < allRoutes.length; i++) {
    const r = allRoutes[i];
    if (r.path === route.path) { matched = r; matchedParams = {}; break; }
  }
  if (!matched) {
    for (let i = 0; i < allRoutes.length; i++) {
      const r = allRoutes[i];
      if (String(r.path).indexOf(":") < 0) continue;
      const params = matchPath(r.path, route.path);
      if (params) { matched = r; matchedParams = params; break; }
    }
  }

  // hide loading splash now that App has mounted
  uER(function() {
    const splash = document.getElementById("forge-splash");
    if (splash) splash.style.display = "none";
  }, []);

  const ShellCmp = (typeof AppShell === "function") ? AppShell : null;
  const NF = (typeof NotFound === "function") ? NotFound : function() { return React.createElement("div", null, "404"); };

  // Pass params to the renderer. Existing renderers take no args and just
  // ignore the extra parameter — backwards compatible.
  const content = matched ? matched.renderer(matchedParams) : React.createElement(NF, { path: route.path });
  const isChromelessRoute = route.path === "/forge/landing" || route.path === "/forge/onboarding";

  if (isChromelessRoute || !ShellCmp) {
    // Landing and onboarding own their page chrome; keep the app shell out.
    return content;
  }

  // Render shell + cross-cutting overlays (⌘K palette, notifications, reset button)
  // as Fragment siblings so the overlays float above all routed content.
  const CCMount = (typeof CrossCuttingMount === "function") ? CrossCuttingMount : null;
  return React.createElement(React.Fragment, null,
    React.createElement(
      ShellCmp,
      { mode: route.mode, screenId: route.path },
      content
    ),
    CCMount ? React.createElement(CCMount) : null
  );
}

if (typeof window !== "undefined") {
  window.App             = App;
  window.navigate        = navigate;
  window.parseHash       = parseHash;
  window.useHashRoute    = useHashRoute;
  window.matchPath       = matchPath;
  window.BUILTIN_ROUTES  = BUILTIN_ROUTES;
}
