/* FORGE — active tenant resolver. Switches between Tritan (pump CDMO, deep),
   Aetherion (microsat, deep), and Mittelstand
   (mill, deep). LocalStorage-backed.

   Each deep tenant reads its data from a window-attached fixture global
   (e.g. window.MITTELSTAND_TENANT) loaded by a sibling fixtures-*.jsx file.
   When the global is not yet evaluated the resolver falls back to safe empty
   arrays / nulls so the UI does not crash during early render.
*/

const TENANT_KEY = "forge.tenant";

// ---------- safe getters --------------------------------------------------
// Read a window-attached fixture global, fall back to a default when absent.
function readGlobal(name, fallback) {
  if (typeof window === "undefined") return fallback;
  const v = window[name];
  return (typeof v === "undefined" || v === null) ? fallback : v;
}

// Resolve a fixture key off a window global (e.g. window.MITTELSTAND_TENANT.parts).
function pick(globalName, key, fallback) {
  const g = readGlobal(globalName, null);
  if (!g || typeof g !== "object") return fallback;
  const v = g[key];
  return (typeof v === "undefined" || v === null) ? fallback : v;
}

// ---------- Mittelstand (deep) -------------------------------------------
// Tier-1 automotive customer (MAHLE), MTL-220 Rev D 24-mill batch, ECO-MS-0017.
// Wired to window.MITTELSTAND_TENANT (loaded by fixtures-mittelstand.jsx).
function buildMittelstandTenant() {
  return {
    tenant: {
      id: "mittelstand",
      name: "Mittelstand-pilot Werkzeugbau",
      site: "Stuttgart, DE",
      erp: "SAP B1 + proALPHA",
      customer: "MAHLE Industriebeteiligungen GmbH",
    },
    program: pick("MITTELSTAND_TENANT", "program", {
      id: "PGM-MTL-220",
      code: "MTL-220",
      name: "MTL-220 · 5-axis bridge mill",
      customer: "MAHLE Industriebeteiligungen GmbH",
      phase: "Series production",
      revision: "D",
    }),
    kpis: pick("MITTELSTAND_TENANT", "kpis", [
      // €4.2M = 420,000,000 cents. Resolved via forgeI18n where loaded; the
      // literal is the fallback rendered before forgeI18n hits window.
      { k: "Open RFQs (€)",    v: (typeof window !== "undefined" && window.forgeI18n && window.forgeI18n.formatMoneyMinor) ? (window.forgeI18n.formatMoneyMinor("420000000", "EUR") || "€4.2M") : "€4.2M", d: "+1 (MAHLE batch-2)",    trend: "up"   },
      { k: "WOs scheduled",    v: "6",     d: "24 mills",               trend: "up"   },
      { k: "Open ECOs",        v: "3",     d: "1 critical (MS-0017)",   trend: "up"   },
      { k: "Line readiness",   v: "94%",   d: "−3 pt (granite cell)",   trend: "down" },
      { k: "Alerts (24h)",     v: "5",     d: "2 supplier · 3 quality", trend: "up"   },
      { k: "FAI pass rate",    v: "92%",   d: "+2 pt YTD",              trend: "up"   },
    ]),
    nav: pick("MITTELSTAND_TENANT", "nav", typeof NAV !== "undefined" ? NAV : []),
    parts:          pick("MITTELSTAND_TENANT", "parts",          typeof MITTELSTAND_BOM_FLAT !== "undefined" ? MITTELSTAND_BOM_FLAT : []),
    boms:           pick("MITTELSTAND_TENANT", "boms",           []),
    cost_cascade:   pick("MITTELSTAND_TENANT", "cost_cascade",   []),
    routing:        pick("MITTELSTAND_TENANT", "routing",        []),
    quality_gates:  pick("MITTELSTAND_TENANT", "quality_gates",  []),
    pfmea:          pick("MITTELSTAND_TENANT", "pfmea",          []),
    suppliers:      pick("MITTELSTAND_TENANT", "suppliers",      []),
    work_orders:    pick("MITTELSTAND_TENANT", "work_orders",    []),
    travelers:      pick("MITTELSTAND_TENANT", "travelers",      []),
    eco:            pick("MITTELSTAND_TENANT", "eco",            []),
    field_returns:  pick("MITTELSTAND_TENANT", "field_returns",  []),
    compliance:     pick("MITTELSTAND_TENANT", "compliance",     {}),
    aftermarket:    pick("MITTELSTAND_TENANT", "aftermarket",    []),
    ledger:         pick("MITTELSTAND_TENANT", "ledger",         []),
    people:         pick("MITTELSTAND_TENANT", "people",         []),
    documents:      pick("MITTELSTAND_TENANT", "documents",      []),
    lifecycle: pick("MITTELSTAND_TENANT", "lifecycle", [
      { phase: "Frame contract signed",       date: "2025-09", status: "passed"    },
      { phase: "Engineering Rev D + ECO-0017", date: "2025-11", status: "passed"    },
      { phase: "Long-lead release",           date: "2026-01", status: "passed"    },
      { phase: "Granite-cell rework",         date: "2026-03", status: "passed"    },
      { phase: "First article assembly",      date: "2026-06", status: "in-flight" },
      { phase: "FAI + PPAP Level 3",          date: "2026-08", status: "upcoming"  },
      { phase: "Batch-1 ship-acceptance",     date: "2026-12", status: "upcoming"  },
    ]),
    depth: "deep",
  };
}

// ---------- Aetherion (deep) ---------------------------------------------
// Microsat NPD, Aperture Earth $4.2M FFP for KESTREL-3 12U bus.
// Wired to window.AETHERION_TENANT (loaded by fixtures-aetherion.jsx).
// htu220 aliases to this tenant for backward compat.
function buildAetherionTenant() {
  return {
    tenant: {
      id: "aetherion",
      name: "Aetherion Microsat",
      site: "Sunnyvale, CA · ISO 14644-1 Class 7",
      erp: "Teamcenter (Siemens)",
      customer: "Aperture Earth Analytics",
    },
    program: pick("AETHERION_TENANT", "program", {
      id: "PGM-AET-K3",
      code: "KESTREL-3",
      name: "KESTREL-3 · 12U sun-sync LEO bus",
      customer: "Aperture Earth Analytics",
      phase: "ASSY · I&T",
      revision: "D",
    }),
    kpis: pick("AETHERION_TENANT", "kpis", [
      { k: "Mass margin",         v: "11%",    d: "1.54 kg / 14.00 kg cap", trend: "down" },
      { k: "Power margin",        v: "8 W",    d: "70 W BOL · 32 W pl",     trend: "flat" },
      { k: "Open NCRs",           v: "2",      d: "1 critical · hinge",     trend: "flat" },
      { k: "Days to launch",      v: "124",    d: "T-0 2026-09-10",         trend: "down" },
      { k: "Qual gate pass rate", v: "94%",    d: "118 / 126 tests",        trend: "up"   },
      { k: "Telemetry latency",   v: "112 ms", d: "uplink p95 last 24h",    trend: "flat" },
    ]),
    nav: pick("AETHERION_TENANT", "nav", typeof NAV !== "undefined" ? NAV : []),
    parts:          pick("AETHERION_TENANT", "parts",          []),
    boms:           pick("AETHERION_TENANT", "boms",           []),
    cost_cascade:   pick("AETHERION_TENANT", "cost_cascade",   []),
    routing:        pick("AETHERION_TENANT", "routing",        []),
    quality_gates:  pick("AETHERION_TENANT", "quality_gates",  []),
    pfmea:          pick("AETHERION_TENANT", "pfmea",          []),
    suppliers:      pick("AETHERION_TENANT", "suppliers",      []),
    work_orders:    pick("AETHERION_TENANT", "work_orders",    []),
    travelers:      pick("AETHERION_TENANT", "travelers",      []),
    eco:            pick("AETHERION_TENANT", "eco",            []),
    field_returns:  pick("AETHERION_TENANT", "field_returns",  []),
    compliance:     pick("AETHERION_TENANT", "compliance",     {}),
    aftermarket:    pick("AETHERION_TENANT", "aftermarket",    []),
    ledger:         pick("AETHERION_TENANT", "ledger",         []),
    people:         pick("AETHERION_TENANT", "people",         []),
    documents:      pick("AETHERION_TENANT", "documents",      []),
    lifecycle: pick("AETHERION_TENANT", "lifecycle", [
      { phase: "SRR",    date: "2025-03-04", status: "passed"    },
      { phase: "PDR",    date: "2025-06-18", status: "passed"    },
      { phase: "CDR",    date: "2025-10-22", status: "passed"    },
      { phase: "FAB",    date: "2026-01-30", status: "passed"    },
      { phase: "ASSY",   date: "in-flight",  status: "in-flight" },
      { phase: "I&T",    date: "in-flight",  status: "in-flight" },
      { phase: "TVAC",   date: "2026-05-28", status: "in-flight" },
      { phase: "ACC",    date: "2026-07-15", status: "upcoming"  },
      { phase: "LAUNCH", date: "2026-09-10", status: "upcoming"  },
    ]),
    depth: "deep",
  };
}

// ---------- (Aurora removed) ----------------------------------------------
// The Aurora / biochar tenant was a plant-OPERATOR scope mismatch for Forge.
// Migrated to /Users/sankalp/Projects/operator/seed/biochar/ on 2026-05-09.
// See /Users/sankalp/Projects/_forge/SCAFFOLDING-STRATEGY.md.

// ---------- resolver ------------------------------------------------------
function getActiveTenant() {
  const id = (typeof localStorage !== "undefined" && localStorage.getItem(TENANT_KEY)) || "tritan";
  // Prefer window.PUMP_TENANT over the script-scoped const PUMP_TENANT from
  // fixtures-pump.jsx. After api.js#useTenantState refetches state from the
  // server it writes the fresh tenant object onto window.PUMP_TENANT, while
  // the original fixture const remains bound to the seed data. Reading the
  // const here would surface stale ECO/traveler status after mutations.
  const winPump = (typeof window !== "undefined") ? window.PUMP_TENANT : null;
  const pump = winPump || (typeof PUMP_TENANT !== "undefined" ? PUMP_TENANT : null);
  if (id === "tritan"      && pump)                                    return pump;
  if (id === "aetherion")                                              return buildAetherionTenant();
  if (id === "htu220")                                                  return buildAetherionTenant(); // alias for backward compat
  if (id === "space")                                                   return buildAetherionTenant(); // alias: dir name ≠ tenant id
  if (id === "mittelstand")                                            return buildMittelstandTenant();
  // aurora id is no longer resolved — falls through to default tenant below.
  // fallback — if PUMP_TENANT not yet loaded, fall back to aetherion
  return pump || buildAetherionTenant();
}

function setActiveTenant(id) {
  if (typeof localStorage !== "undefined") localStorage.setItem(TENANT_KEY, id);
  // The patched Storage.prototype.setItem below auto-fires
  // "forge:tenant-change" whenever forge.tenant actually changes. We still
  // dispatch it explicitly here as belt-and-suspenders in case the patch
  // hasn't been installed yet (rare: a screen calling setActiveTenant before
  // active-tenant.jsx has been evaluated end-to-end).
  if (typeof window !== "undefined") {
    window.dispatchEvent(new CustomEvent("forge:tenant-change", { detail: { id } }));
  }
}

function getActiveTenantId() {
  const raw = (typeof localStorage !== "undefined" && localStorage.getItem(TENANT_KEY)) || "tritan";
  // canonicalize htu220/space → aetherion at read-time so callers see the new id;
  // setActiveTenant("htu220") still works for backward compat
  return (raw === "htu220" || raw === "space") ? "aetherion" : raw;
}

function listTenants() {
  return [
    { id: "tritan",      name: "Tritan Pumps Pvt Ltd",          tagline: "Submersible pump CDMO · India",            depth: "deep" },
    { id: "aetherion",   name: "Aetherion Microsat",            tagline: "12U sun-sync LEO bus · KESTREL-3",         depth: "deep" },
    { id: "mittelstand", name: "Mittelstand-pilot Werkzeugbau", tagline: "5-axis bridge mill · MTL-220 Rev D",       depth: "deep" },
  ];
}

// Hook for screens to subscribe to tenant changes
function useActiveTenant() {
  const [, setBump] = React.useState(0);
  React.useEffect(() => {
    const onChange = () => setBump(function(b) { return b + 1; });
    window.addEventListener("forge:tenant-change", onChange);
    return function() { window.removeEventListener("forge:tenant-change", onChange); };
  }, []);
  return getActiveTenant();
}

if (typeof window !== "undefined") {
  window.getActiveTenant   = getActiveTenant;
  window.getActiveTenantId = getActiveTenantId;
  window.setActiveTenant   = setActiveTenant;
  window.listTenants       = listTenants;
  window.useActiveTenant   = useActiveTenant;
}

// ---------- tenant-sync watchdog (Wave 7A) --------------------------------
// Bug: when localStorage.forge.tenant changes WITHOUT going through
// setActiveTenant() — e.g. a dev console eval, a test script, another script
// path that calls localStorage.setItem directly — the React tree never gets
// the "forge:tenant-change" event and shows the stale tenant until a full
// page reload.
//
// Two-layer defense:
//
//   1. window "storage" event — fires when ANOTHER tab/window mutates the
//      same localStorage key (browsers don't fire it on the originating tab).
//      Useful for cross-tab tenant sync.
//
//   2. Storage.prototype.setItem monkey-patch — wraps the native setter so
//      ANY in-tab write to "forge.tenant" (from anywhere) re-emits the
//      "forge:tenant-change" CustomEvent that the rest of the app already
//      listens for (app-shell, useActiveTenant, useTenantState, etc.).
//
// The patch is installed once, guarded by window.__forgeTenantPatched, so
// repeated evaluations (HMR / Babel re-eval) don't double-wrap and recurse.
// Storage.prototype is shared between localStorage and sessionStorage, so we
// gate on the key name — sessionStorage writes pass through untouched.
if (typeof window !== "undefined") {
  window.addEventListener("storage", function (e) {
    // e.key === null when the whole store is cleared via localStorage.clear().
    if (e.key === TENANT_KEY || e.key === null) {
      try {
        window.dispatchEvent(
          new CustomEvent("forge:tenant-change", { detail: { id: e.newValue } })
        );
      } catch (err) { /* ignore */ }
    }
  });

  if (window.localStorage && typeof Storage !== "undefined" && !window.__forgeTenantPatched) {
    window.__forgeTenantPatched = true;
    var __origSetItem = Storage.prototype.setItem;
    Storage.prototype.setItem = function (key, value) {
      // Capture the previous value BEFORE the write so we can detect actual
      // changes (and avoid spurious refetches when the same value is re-set).
      var oldValue = null;
      try { oldValue = this.getItem(key); } catch (err) { /* ignore */ }
      __origSetItem.call(this, key, value);
      // Only fire for the localStorage tenant key — sessionStorage and other
      // keys (e.g. forge.locale) pass through silently.
      if (this === window.localStorage && key === TENANT_KEY && oldValue !== value) {
        try {
          window.dispatchEvent(
            new CustomEvent("forge:tenant-change", { detail: { id: value } })
          );
        } catch (err) { /* ignore */ }
      }
    };
  }
}
