// FORGE — FSM lifecycle visualizer (PR-15).
//
// Renders the active tenant's ECO state-machine as a Mermaid diagram, with
// a fallback raw-text view. Wired into router.jsx under `/forge/lifecycle`.
//
// Babel-standalone IIFE pattern. No module imports. Attaches:
//   window.ScreenLifecycleViz
//
// Mermaid is lazy-loaded from unpkg the first time the screen renders. We
// guard against duplicate script injection by stashing a global promise on
// `window.__forgeMermaidLoader`.
(function () {
  const { useState, useEffect, useMemo, useRef } = React;

  const MERMAID_SRC = "https://unpkg.com/mermaid@10/dist/mermaid.min.js";

  function loadMermaid() {
    if (typeof window === "undefined") return Promise.resolve(null);
    if (window.mermaid) return Promise.resolve(window.mermaid);
    if (window.__forgeMermaidLoader) return window.__forgeMermaidLoader;
    window.__forgeMermaidLoader = new Promise(function (resolve, reject) {
      const tag = document.createElement("script");
      tag.src = MERMAID_SRC;
      tag.async = true;
      tag.onload = function () {
        try {
          if (window.mermaid && typeof window.mermaid.initialize === "function") {
            window.mermaid.initialize({
              startOnLoad: false,
              theme: "neutral",
              securityLevel: "loose",
              fontFamily: "Inter, system-ui, sans-serif",
            });
          }
          resolve(window.mermaid);
        } catch (e) {
          reject(e);
        }
      };
      tag.onerror = function () { reject(new Error("mermaid failed to load")); };
      document.head.appendChild(tag);
    });
    return window.__forgeMermaidLoader;
  }

  // Resolve the active tenant id with safe defaults.
  function activeTenantId() {
    try {
      if (typeof window.getActiveTenantId === "function") {
        return window.getActiveTenantId();
      }
      if (typeof window.getActiveTenant === "function") {
        const t = window.getActiveTenant();
        return (t && t.tenant && t.tenant.id) || "tritan";
      }
    } catch (_) {
      // fall through
    }
    return "tritan";
  }

  // Subscribe to the active-tenant pub/sub so the visualizer follows the
  // topbar's tenant switcher. Falls back to local state when the hook is not
  // yet attached to window (test harnesses, very early boot).
  function useActiveTenantId() {
    const [id, setId] = useState(activeTenantId());
    useEffect(function () {
      function onChange() { setId(activeTenantId()); }
      window.addEventListener("forge:tenant-change", onChange);
      return function () { window.removeEventListener("forge:tenant-change", onChange); };
    }, []);
    return [id, setId];
  }

  // Pull the diagram JSON from the server endpoint we wired in PR-15.
  function fetchDiagram(tenantId, machine) {
    const url = "/api/" + encodeURIComponent(tenantId) +
      "/state-machine/diagram?machine=" + encodeURIComponent(machine || "eco");
    return fetch(url, { credentials: "include" }).then(function (r) {
      if (!r.ok) {
        return r.json().then(function (j) {
          throw new Error(j.error || "diagram fetch failed: " + r.status);
        });
      }
      return r.json();
    });
  }

  // Wave 4C: pull the dict shape (no `?machine=` param) to enumerate every
  // machine available for a tenant. Includes traveler when station_graph
  // is configured. Order is intentional: eco first, then phase (Aetherion),
  // then traveler — display order in the tab strip below.
  function fetchAllDiagrams(tenantId) {
    const url = "/api/" + encodeURIComponent(tenantId) + "/state-machine/diagram";
    return fetch(url, { credentials: "include" }).then(function (r) {
      if (!r.ok) {
        return r.json().then(function (j) {
          throw new Error(j.error || "diagrams index fetch failed: " + r.status);
        });
      }
      return r.json();
    });
  }

  // Stable display order for the tab strip. Unknown machines fall back to
  // alphabetical at the end. Keeps the UI sensible if a new machine is added.
  function orderMachines(names) {
    const ORDER = ["eco", "phase", "traveler"];
    const known = ORDER.filter(function (m) { return names.indexOf(m) >= 0; });
    const extras = names.filter(function (m) { return ORDER.indexOf(m) < 0; }).sort();
    return known.concat(extras);
  }

  // Pretty label for a machine tab button.
  function machineLabel(name) {
    if (name === "eco") return "ECO";
    if (name === "phase") return "Phase";
    if (name === "traveler") return "Traveler";
    return name;
  }

  function ScreenLifecycleViz(props) {
    // Tenant id follows the active-tenant pub/sub. The in-screen tenant
    // buttons (below) explicitly call setActiveTenant so a click here also
    // updates the global, which keeps the topbar switcher and FSM viz in
    // sync.
    const [tenantId, setTenantId] = useActiveTenantId();
    // Wave 4C: machine is now selectable. Default to 'eco', re-validated
    // against the available list whenever the tenant changes.
    const [machine, setMachine] = useState("eco");
    const [availableMachines, setAvailableMachines] = useState(["eco"]);
    const [diagram, setDiagram] = useState(null);
    const [error, setError] = useState(null);
    const [mermaidReady, setMermaidReady] = useState(!!(typeof window !== "undefined" && window.mermaid));
    const [rendered, setRendered] = useState(""); // SVG string
    const mountRef = useRef(null);

    // ── Discover available machines per tenant ──────────────────────
    // Wave 4C: fetch the diagram-index dict so the tab strip knows what to
    // render. Aetherion gets eco+phase+traveler, Tritan/Mittelstand get
    // eco+traveler. If the current machine isn't available on the new
    // tenant, snap back to eco.
    useEffect(function () {
      let cancelled = false;
      fetchAllDiagrams(tenantId)
        .then(function (dict) {
          if (cancelled) return;
          const names = orderMachines(Object.keys(dict || {}));
          setAvailableMachines(names.length ? names : ["eco"]);
          if (names.indexOf(machine) < 0) {
            setMachine(names[0] || "eco");
          }
        })
        .catch(function () {
          // Soft-fail: assume at least eco. The per-machine fetch below
          // will surface the real error.
          if (!cancelled) setAvailableMachines(["eco"]);
        });
      return function () { cancelled = true; };
      // Only re-fetch on tenant change; machine selection doesn't change
      // the available list.
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [tenantId]);

    // ── Fetch diagram on tenant or machine change ───────────────────
    useEffect(function () {
      let cancelled = false;
      setError(null);
      setDiagram(null);
      fetchDiagram(tenantId, machine)
        .then(function (d) { if (!cancelled) setDiagram(d); })
        .catch(function (e) { if (!cancelled) setError(e.message || String(e)); });
      return function () { cancelled = true; };
    }, [tenantId, machine]);

    // ── Lazy-load Mermaid ───────────────────────────────────────────
    useEffect(function () {
      let cancelled = false;
      loadMermaid()
        .then(function () { if (!cancelled) setMermaidReady(true); })
        .catch(function (e) {
          if (!cancelled) setError("mermaid load: " + (e.message || e));
        });
      return function () { cancelled = true; };
    }, []);

    // ── Render Mermaid → SVG when both pieces are ready ─────────────
    useEffect(function () {
      if (!mermaidReady || !diagram || !diagram.mermaid) return;
      let cancelled = false;
      try {
        const id = "forge-fsm-" + tenantId + "-" + machine + "-" + Date.now();
        // Mermaid 10 render: returns Promise<{svg}>.
        const p = window.mermaid.render(id, diagram.mermaid);
        Promise.resolve(p).then(function (out) {
          if (cancelled) return;
          const svg = out && (out.svg || out) || "";
          setRendered(svg);
        }).catch(function (e) {
          if (!cancelled) setError("render: " + (e.message || e));
        });
      } catch (e) {
        if (!cancelled) setError("render: " + (e.message || e));
      }
      return function () { cancelled = true; };
    }, [mermaidReady, diagram, tenantId, machine]);

    // ── Inject the rendered SVG ─────────────────────────────────────
    useEffect(function () {
      if (mountRef.current && rendered) {
        mountRef.current.innerHTML = rendered;
      }
    }, [rendered]);

    // ── Styling consts (mirror /forge/dashboard look) ──────────────
    const ink = "var(--ink, #111)";
    const ink3 = "var(--ink-3, #888)";
    const line = "var(--line-soft, #e8e8e8)";
    const mono = "var(--font-mono, ui-monospace, 'SF Mono', monospace)";

    const TENANT_OPTS = useMemo(function () {
      return [
        { id: "tritan",      label: "TRITAN · PUMP CDMO" },
        { id: "aetherion",   label: "AETHERION · MICROSAT" },
        { id: "mittelstand", label: "MITTELSTAND · MACHINE BUILDER" },
      ];
    }, []);

    // Header title reflects the active machine. "ECO" → "ECO state machine",
    // "phase" → "Phase ladder", "traveler" → "Traveler graph". Keeps the
    // page heading honest about what's actually rendered.
    const headerTitle =
      machine === "traveler"
        ? "Traveler graph — " + tenantId
        : machine === "phase"
        ? "Phase ladder — " + tenantId
        : "ECO state machine — " + tenantId;

    return React.createElement(
      "div",
      { style: { padding: "24px 28px", fontFamily: "Inter, system-ui, sans-serif", color: ink } },

      // Header row
      React.createElement(
        "div",
        { style: { display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 12, borderBottom: "1px solid " + line, paddingBottom: 12 } },
        React.createElement("div", null,
          React.createElement("div", { style: { fontSize: 11, letterSpacing: "0.06em", textTransform: "uppercase", color: ink3, fontFamily: mono } }, "Forge / Lifecycle"),
          React.createElement("h2", { style: { margin: "4px 0 0 0", fontSize: 22, fontWeight: 600 } }, headerTitle)
        ),
        // Tenant switch
        React.createElement(
          "div",
          { style: { display: "flex", gap: 6 } },
          TENANT_OPTS.map(function (opt) {
            const active = opt.id === tenantId;
            return React.createElement(
              "button",
              {
                key: opt.id,
                onClick: function () {
                  // Update the global so the topbar TenantSwitcher and any
                  // other screen subscribed to forge:tenant-change re-render.
                  if (typeof window.setActiveTenant === "function") {
                    window.setActiveTenant(opt.id);
                  } else {
                    setTenantId(opt.id);
                  }
                },
                style: {
                  padding: "6px 10px",
                  fontSize: 11,
                  fontFamily: mono,
                  letterSpacing: "0.04em",
                  textTransform: "uppercase",
                  border: "1px solid " + (active ? ink : line),
                  background: active ? ink : "transparent",
                  color: active ? "white" : ink3,
                  cursor: "pointer",
                },
              },
              opt.label
            );
          })
        )
      ),

      // Wave 4C: Machine tab strip. Renders one button per available machine
      // for the active tenant. Aetherion gets eco / phase / traveler;
      // Tritan + Mittelstand get eco / traveler. The selected tab drives the
      // diagram fetch + render via the `machine` state.
      React.createElement(
        "div",
        { style: { display: "flex", gap: 6, marginBottom: 16 } },
        availableMachines.map(function (m) {
          const active = m === machine;
          return React.createElement(
            "button",
            {
              key: m,
              onClick: function () { setMachine(m); },
              style: {
                padding: "6px 14px",
                fontSize: 11,
                fontFamily: mono,
                letterSpacing: "0.04em",
                textTransform: "uppercase",
                border: "1px solid " + (active ? ink : line),
                background: active ? "var(--band, #fafafa)" : "transparent",
                color: active ? ink : ink3,
                cursor: "pointer",
                borderBottomColor: active ? "transparent" : line,
              },
            },
            machineLabel(m)
          );
        })
      ),

      // Body: SVG mount or raw markdown fallback
      React.createElement(
        "div",
        { style: { display: "grid", gridTemplateColumns: "minmax(0, 1fr) 320px", gap: 24 } },
        React.createElement(
          "div",
          null,
          error
            ? React.createElement("div", { style: { color: "var(--err, #c00)", padding: 12, border: "1px solid var(--err, #c00)" } }, error)
            : null,
          !error && !rendered
            ? React.createElement("div", { style: { color: ink3, fontFamily: mono, fontSize: 12 } }, "rendering diagram…")
            : null,
          // SVG mount
          React.createElement("div", {
            ref: mountRef,
            style: {
              minHeight: 280,
              border: "1px solid " + line,
              padding: 16,
              background: "var(--paper, #fff)",
              overflow: "auto",
            },
          })
        ),

        // Sidebar — raw Mermaid source for copy/paste
        React.createElement(
          "div",
          { style: { borderLeft: "1px solid " + line, paddingLeft: 16 } },
          React.createElement("div", { style: { fontSize: 11, letterSpacing: "0.04em", textTransform: "uppercase", color: ink3, fontFamily: mono, marginBottom: 8 } }, "Mermaid source"),
          React.createElement(
            "pre",
            { style: { fontFamily: mono, fontSize: 11, color: ink, background: "var(--band, #fafafa)", padding: 10, whiteSpace: "pre-wrap", lineHeight: 1.4, maxHeight: 360, overflow: "auto" } },
            (diagram && diagram.mermaid) || ""
          ),
          diagram && diagram.transitions
            ? React.createElement(
                "div",
                { style: { marginTop: 14 } },
                React.createElement("div", { style: { fontSize: 11, letterSpacing: "0.04em", textTransform: "uppercase", color: ink3, fontFamily: mono, marginBottom: 6 } }, "Transitions"),
                React.createElement("div", { style: { fontFamily: mono, fontSize: 11, color: ink3 } },
                  String(diagram.transitions.length) + " edges · initial=" + (diagram.initial || "?") + " · final=" + ((diagram.finalStates || []).join(",") || "—")
                )
              )
            : null
        )
      )
    );
  }

  if (typeof window !== "undefined") {
    window.ScreenLifecycleViz = ScreenLifecycleViz;
  }
})();
