// Screens 2/3: E-BOM, M-BOM, E→M transformation

const { useState: uS2, useMemo: uM2 } = React;

const VARIANT_KEY = "forge.variantSku";

const VARIANT_COPY = {
  "M-27418": {
    label: "M-27418",
    name: "1.0HP / 4in Helios pumpset",
    note: "Hero 500u order · ECO-0051 cut-in at u#101",
    lineImpact: "NRV material change blocks ERP T7 until cost-center + supplier certs clear.",
    effectivity: "serial TPX-H-0101 onward",
  },
  "M-26102": {
    label: "M-26102",
    name: "0.75HP V4 carryover",
    note: "Internal-stock 50u · ECO-0042 approved",
    lineImpact: "V4 carryover reduces tooling load; same line, shorter pump stack and lower winding work.",
    effectivity: "WO-44220 · completed batch",
  },
  "M-31507": {
    label: "M-31507",
    name: "5HP pilot scale-up",
    note: "10u pilot · extra stages and 180SL motor stack",
    lineImpact: "Machine shop and final test absorb the load: 5 impeller stages, larger shafts, longer test takt.",
    effectivity: "WO-44221 · pilot batch",
  },
};

function getVariantMeta(sku) {
  return VARIANT_COPY[sku] || { label: sku || "base", name: "Base model", note: "Engineering baseline", lineImpact: "No downstream impact loaded.", effectivity: "serial 001-∞" };
}

function getTenantSkuList(tenant) {
  if (!tenant || !tenant.boms || !tenant.boms.length) return [];
  // Use PumpPhysics.rollupCost when available (pump-design integration). It is
  // the canonical cost view: pump_rmc + motor_rmc + conversion + freight,
  // matching cost_cascade for M-27418/M-26102/M-31507 within ±₹10. Falls back
  // to direct cost_cascade lookup for tenants without rollupCost (mittelstand,
  // space, OAM) so this helper stays generic.
  const rollup = (typeof window !== "undefined" && window.PumpPhysics && typeof window.PumpPhysics.rollupCost === "function")
    ? window.PumpPhysics.rollupCost
    : null;
  return tenant.boms.map(function(b) {
    let totalInr = null, pumpRmc = null, motorRmc = null, conv = null, freight = null;
    if (rollup && tenant === window.PUMP_TENANT) {
      const r = rollup(b.sku, tenant.parts, tenant.boms);
      totalInr = r.total_inr || null;
      pumpRmc  = r.pump_rmc || null;
      motorRmc = r.motor_rmc || null;
      conv     = r.conversion_inr || null;
      freight  = r.freight_inr || null;
    } else {
      const cost = (tenant.cost_cascade || []).find(function(c) { return c.sku === b.sku; });
      totalInr = cost ? cost.total_inr : null;
      pumpRmc  = cost ? cost.pump_rmc  : null;
      motorRmc = cost ? cost.motor_rmc : null;
    }
    const wo = (tenant.work_orders || []).find(function(w) { return w.sku === b.sku; });
    return Object.assign({}, getVariantMeta(b.sku), {
      sku: b.sku,
      lineCount: (b.lines || []).length,
      totalInr: totalInr,
      pumpRmc: pumpRmc,
      motorRmc: motorRmc,
      conversionInr: conv,
      freightInr: freight,
      workOrder: wo ? wo.id : null,
      status: wo ? wo.status : "engineering",
      qty: wo ? wo.qty : null,
    });
  });
}

function getInitialVariantSku(tenant) {
  const skus = getTenantSkuList(tenant);
  if (!skus.length) return "";
  const saved = (typeof localStorage !== "undefined") ? localStorage.getItem(VARIANT_KEY) : "";
  return skus.some(function(s) { return s.sku === saved; }) ? saved : skus[0].sku;
}

function setActiveVariantSku(sku) {
  if (typeof localStorage !== "undefined") localStorage.setItem(VARIANT_KEY, sku);
  if (typeof window !== "undefined") window.dispatchEvent(new CustomEvent("forge:variant-change", { detail: { sku: sku } }));
}

function useVariantSku(tenant) {
  const [sku, setSku] = uS2(function() { return getInitialVariantSku(tenant); });
  React.useEffect(function() {
    const next = getInitialVariantSku(tenant);
    if (next && next !== sku) setSku(next);
  }, [tenant && tenant.tenant && tenant.tenant.id]);
  React.useEffect(function() {
    const onChange = function(e) { setSku((e && e.detail && e.detail.sku) || getInitialVariantSku(tenant)); };
    window.addEventListener("forge:variant-change", onChange);
    return function() { window.removeEventListener("forge:variant-change", onChange); };
  }, [tenant]);
  return [sku, function(next) { setSku(next); setActiveVariantSku(next); }];
}

function getBomForSku(tenant, sku) {
  return tenant && tenant.boms ? (tenant.boms.find(function(b) { return b.sku === sku; }) || tenant.boms[0]) : null;
}

function stationForPartNum(partNum) {
  const p = String(partNum || "");
  if (p.indexOf("10.04") === 0 || p.indexOf("10.05") === 0 || p.indexOf("20.06") === 0) return "s4";
  if (p.indexOf("10.") === 0) return "s5";
  if (p.indexOf("20.") === 0) return "s7";
  if (p.indexOf("30.") === 0 || p.indexOf("40.") === 0) return "s7";
  return "s2";
}

function buildVariantBomTree(tenant, sku) {
  const bom = getBomForSku(tenant, sku);
  if (!tenant || !tenant.parts || !bom) return buildTenantBomTree(tenant && tenant.parts);

  const byNum = {};
  tenant.parts.forEach(function(p) { byNum[p.num] = p; });
  const qtyByPart = {};
  (bom.lines || []).forEach(function(l) { qtyByPart[l.part_num] = l.qty; });

  const keep = {};
  (bom.lines || []).forEach(function(l) {
    let cur = byNum[l.part_num];
    while (cur) {
      keep[cur.num] = true;
      cur = cur.p ? byNum[cur.p] : null;
    }
  });
  tenant.parts.forEach(function(p) { if (!p.p) keep[p.num] = true; });

  const children = {};
  tenant.parts.forEach(function(p) {
    if (keep[p.num] && p.p && keep[p.p]) (children[p.p] = children[p.p] || []).push(p);
  });

  function mkNode(item) {
    const kids = (children[item.num] || []).map(mkNode);
    return {
      id: item.num,
      pn: item.num,
      name: item.p ? item.name : (sku + " · " + getVariantMeta(sku).name),
      type: kids.length ? "ASM" : "PRT",
      qty: qtyByPart[item.num] || item.qty || 1,
      rev: "B",
      mat: item.tolerance && item.tolerance !== "—" ? "SPEC" : "—",
      source: item.supplier === "in-house" ? "MAKE" : "BUY",
      status: qtyByPart[item.num] ? "released" : "in-work",
      children: kids,
      cost_inr: item.cost_inr,
      tolerance: item.tolerance,
      lead_time_days: item.lead_time_days,
      supplier: item.supplier,
    };
  }

  const root = tenant.parts.find(function(p) { return !p.p; });
  return root ? mkNode(root) : buildTenantBomTree(tenant.parts);
}

function VariantSelector({ tenant, sku, onSku, compact }) {
  const skus = getTenantSkuList(tenant);
  if (!skus.length) return null;
  return (
    <div style={{ display: "grid", gridTemplateColumns: compact ? "repeat(3, minmax(0, 1fr))" : "repeat(3, minmax(150px, 1fr))", gap: 8 }}>
      {skus.map(function(v) {
        const active = v.sku === sku;
        return (
          <button key={v.sku} onClick={function() { onSku(v.sku); }}
            style={{
              textAlign: "left",
              padding: compact ? "7px 9px" : "9px 10px",
              borderRadius: 5,
              border: "1px solid " + (active ? "var(--accent)" : "var(--line-soft)"),
              background: active ? "var(--bg-2)" : "var(--bg-1)",
              cursor: "pointer",
            }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8, flexWrap: "wrap", rowGap: 4 }}>
              <span className="mono" style={{ fontSize: 12, color: active ? "var(--accent)" : "var(--ink)" }}>{v.label}</span>
              <Pill tone={active ? "accent" : ""}>{v.status}</Pill>
            </div>
            <div style={{ fontSize: compact ? 11 : 12, color: "var(--ink)", marginTop: 3 }}>{v.name}</div>
            {!compact && <div className="muted mono" style={{ fontSize: 12, marginTop: 2 }}>{v.lineCount} EBOM lines · {v.workOrder || "no WO"} · {v.qty ? v.qty + "u" : "—"}</div>}
          </button>
        );
      })}
    </div>
  );
}

// ---------- helpers: build a generic flat→nested tree for tenant parts ----------
function buildTenantBomTree(parts) {
  if (!parts || !parts.length) return null;
  const cm = {};
  parts.forEach(function(x) { if (x.p) { (cm[x.p] = cm[x.p] || []).push(x); } });
  function mkNode(item) {
    const kids = (cm[item.num] || []).map(mkNode);
    return {
      id: item.num, pn: item.num, name: item.name,
      type: kids.length ? "ASM" : "PRT",
      qty: item.qty, rev: "B",
      mat: item.tolerance && item.tolerance !== "—" ? "SPEC" : "—",
      source: item.supplier === "in-house" ? "MAKE" : "BUY",
      status: "in-work",
      children: kids,
      cost_inr: item.cost_inr, cost_eur: item.cost_eur,
      tolerance: item.tolerance, lead_time_days: item.lead_time_days, supplier: item.supplier,
    };
  }
  const tops = parts.filter(function(x) { return !x.p; });
  if (!tops.length) return null;
  const root = tops[0];
  return mkNode(root);
}

// ---------- E-BOM ----------
function ScreenEBOM({ selectedPn, setSelectedPn }) {
  const tenant = useActiveTenant();
  const tenantId = tenant && tenant.tenant ? tenant.tenant.id : null;
  const tenantTree = uM2(function() { return tenant ? buildTenantBomTree(tenant.parts) : null; }, [tenant]);
  const isTritan = tenantId === "tritan";
  const isMittel = tenantId === "mittelstand";
  // Wave 6B: router's defaultSelectedPn() falls back to HTU-220.10.02 (legacy
  // wind-turbine placeholder) when the active tenant is Aetherion or Mittelstand.
  // Override here so the Selection panel surfaces a tenant-appropriate part
  // number instead of the HTU-220 stub. Tritan keeps its prop value unchanged.
  function _resolveSelectedPn() {
    if (isTritan) return selectedPn || "—";
    const looksLikeHtuStub = typeof selectedPn === "string" && selectedPn.indexOf("HTU-220") === 0;
    if (selectedPn && !looksLikeHtuStub) return selectedPn;
    if (tenant && tenant.parts && tenant.parts.length) {
      // Skip the top assembly (parts[0]) when a sub-assembly exists — gives a
      // more representative pick than the program-level rollup line.
      const pick = tenant.parts[Math.min(1, tenant.parts.length - 1)];
      return (pick && (pick.num || pick.part_num)) || "—";
    }
    return "—";
  }
  const displaySelectedPn = _resolveSelectedPn();
  const [sku, setSku] = useVariantSku(tenant);
  const variantTree = uM2(function() { return isTritan ? buildVariantBomTree(tenant, sku) : tenantTree; }, [tenant, sku, isTritan]);
  const variantMeta = getVariantMeta(sku);

  // Default program selector — when tenant has its own boms, use first SKU.
  // Falls back to legacy "tritan"/"oam" sentinel values otherwise.
  const tenantBomSkus = (tenant && tenant.boms && tenant.boms.length) ? tenant.boms.map(function(b) { return b.sku; }) : [];
  const initialProg = tenantBomSkus.length
    ? tenantBomSkus[0]
    : (isTritan ? "tritan" : (isMittel && tenantTree ? "tritan" : "oam"));
  const [prog, setProg]  = uS2(initialProg); // tenant SKU | "oam" | "tritan"
  React.useEffect(function() { setProg(initialProg); }, [tenantId]);
  const isLegacyProg = (prog === "oam" || prog === "tritan");
  const root = !isLegacyProg
    ? (variantTree || tenantTree)
    : (prog === "tritan" && (variantTree || tenantTree)
        ? (variantTree || tenantTree)
        : (prog === "oam" ? window.OAM_EBOM_TREE : EBOM));
  const rootKey = (root && (root.pn || root.id)) || "OAM-00-00";
  const defaultOpen = prog === "oam"
    ? { "OAM-00-00": true }
    : (function() { var o = {}; o[rootKey] = true; return o; })();
  const [open, setOpen] = uS2(defaultOpen);
  const cols = "minmax(0, 1fr) 54px 44px 54px 90px 70px";

  // When program changes, reset open state
  const handleProg = (p) => {
    setProg(p);
    if (p === "oam") setOpen({ "OAM-00-00": true });
    else {
      var o = {}; o[rootKey] = true; setOpen(o);
      if (isTritan && p !== "tritan" && tenantBomSkus.indexOf(p) >= 0) setSku(p);
    }
  };

  // D/M/T decoration for OAM nodes
  const decorateOAM = (node) => {
    if (node.d === undefined) return <Pill tone={node.status === "released" ? "ok" : "warn"}>{node.status}</Pill>;
    return (
      <div style={{ display: "flex", gap: 4 }}>
        {[["D", node.d, "var(--info)"], ["M", node.m, "var(--accent)"]].map(([l, v, c]) => (
          <div key={l} style={{ display: "flex", alignItems: "center", gap: 2 }}>
            <span className="mono" style={{ fontSize: 12, color: "var(--ink-3)" }}>{l}</span>
            <div style={{ width: 24, height: 4, background: "var(--bg-3)", borderRadius: 2, overflow: "hidden" }}>
              <div style={{ width: `${v}%`, height: "100%", background: c }} />
            </div>
          </div>
        ))}
      </div>
    );
  };

  return (
    <div style={{ padding: 14, display: "grid", gridTemplateColumns: "1fr 320px", gap: 14, minHeight: 0, height: "100%" }}>
      <Panel title="E-BOM · engineering hierarchy" right={<>
        <div style={{ display: "flex", border: "1px solid var(--line)", borderRadius: 4, overflow: "hidden" }}>
          {(() => {
            // Tenant-derived SKU tabs: each tenant's boms[].sku becomes a tab.
            // Falls back to OAM legacy tab if the tenant has no boms.
            const __progItems = [];
            const tenantSkus = (tenant && tenant.boms && tenant.boms.length)
              ? tenant.boms.map(function(b) { return [b.sku, b.sku]; })
              : [];
            if (tenantSkus.length) {
              for (const __it of tenantSkus) __progItems.push(__it);
            } else {
              __progItems.push(["oam", "OAM · Satellite"]);
              if (tenantTree) __progItems.push(["tritan", (tenant && tenant.tenant && tenant.tenant.name) || "Active tenant"]);
            }
            return __progItems;
          })().map(([id, lbl]) => (
            <button key={id} onClick={() => handleProg(id)}
              style={{ padding: "3px 10px", border: 0, fontFamily: "var(--font-mono)", fontSize: 12, cursor: "pointer",
                background: prog === id ? "var(--accent)" : "var(--bg-2)",
                color: prog === id ? "var(--accent-ink)" : "var(--ink-3)" }}>
              {lbl}
            </button>
          ))}
        </div>
        <Btn size="sm" icon="Filter" onClick={() => window.forgeToast && window.forgeToast("filter queued — wired in v2")}>filter</Btn>
        <Btn size="sm" icon="Plus" onClick={() => window.forgeToast && window.forgeToast("add part queued — wired in v2")}>add part</Btn>
      </>}>
        <div style={{ display: "flex", flexDirection: "column", minHeight: 0, height: "100%" }}>
          <TreeHeader cols={cols}/>
          <div style={{ overflow: "auto", flex: 1 }}>
            <Tree node={root} open={open} setOpen={setOpen}
              onSelect={(n) => n.pn && setSelectedPn(n.pn)} selectedPn={selectedPn}
              decorate={prog === "oam" ? decorateOAM : undefined}/>
          </div>
        </div>
      </Panel>

      <div style={{ display: "grid", gridTemplateRows: "auto 1fr auto", gap: 14, minHeight: 0 }}>
        {isTritan && (
          <Panel title="Model variants" right={<Tag>{sku}</Tag>}>
            <div style={{ padding: 10 }}>
              <VariantSelector tenant={tenant} sku={sku} onSku={setSku} compact />
              <div className="hr"/>
              <KV k="Current model" v={variantMeta.name} />
              <KV k="Effectivity" v={variantMeta.effectivity} />
              <KV k="Downstream" v={variantMeta.lineImpact} />
            </div>
          </Panel>
        )}
        <Panel title="Selection">
          <div style={{ padding: 12 }}>
            <div className="label">Selected part</div>
            <div className="mono" style={{ fontSize: 13, fontWeight: 500, color: "var(--ink)", marginTop: 2 }}>{displaySelectedPn}</div>
            <div className="hr"/>
            <KV k="Configuration" v={isTritan ? (sku + " · as-designed") : "base · as-designed"} />
            <KV k="Effectivity"   v={isTritan ? variantMeta.effectivity : "serial 001-∞"} />
            <KV k="Make/Buy"      v="MAKE" />
            <KV k="Classification" v="Primary structure" />
            <KV k="Export control" v="EAR99" />
          </div>
        </Panel>
        {isTritan && (
          <Panel title="Rev history">
            <table className="dtable">
              <thead><tr><th>Rev</th><th>Date</th><th>Author</th><th>Change</th></tr></thead>
              <tbody>
                <tr><td>B</td><td className="tnum" style={{ whiteSpace: "nowrap" }}>2026-04-15</td><td style={{ whiteSpace: "nowrap" }}>Devansh A.</td><td>NRV CI → S.G.-400 (ECO-0051)</td></tr>
                <tr><td>A</td><td className="tnum" style={{ whiteSpace: "nowrap" }}>2026-03-10</td><td style={{ whiteSpace: "nowrap" }}>Devansh A.</td><td>Routing rev published</td></tr>
                <tr><td>-</td><td className="tnum" style={{ whiteSpace: "nowrap" }}>2026-02-15</td><td style={{ whiteSpace: "nowrap" }}>Devansh A.</td><td>Initial release</td></tr>
              </tbody>
            </table>
          </Panel>
        )}
        {!isTritan && tenant && tenant.eco && tenant.eco.length > 0 && (
          <Panel title="Rev history">
            <table className="dtable">
              <thead><tr><th>ECO</th><th>Date</th><th>Owner</th><th>Change</th></tr></thead>
              <tbody>
                {tenant.eco.slice(0, 4).map(function(e, i) {
                  return (
                    <tr key={(e.id || e.eco_id || i)}>
                      <td style={{ whiteSpace: "nowrap" }}>{e.id || e.eco_id || "—"}</td>
                      <td className="tnum" style={{ whiteSpace: "nowrap" }}>{e.date || e.opened || e.created || "—"}</td>
                      <td style={{ whiteSpace: "nowrap" }}>{e.owner || e.lead || "—"}</td>
                      <td>{e.title || e.summary || e.note || "—"}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </Panel>
        )}
        {isTritan && (
          <Panel title="Traceability">
            <div style={{ padding: 10, fontSize: 12, color: "var(--ink-2)" }}>
              <div>Requirements · <span className="mono">QG-01..QG-30</span></div>
              <div>Verifies · <span className="mono">physical test (no sim)</span></div>
              <div>Approves · <span className="mono">ECO-0051 (in-review)</span></div>
            </div>
          </Panel>
        )}
      </div>
    </div>
  );
}

// Normalize tenant routing rows across shapes. Tritan uses id/seq/owner/station_type;
// Aetherion uses station/code/wi_ref/op_codes; Mittelstand may use either. Downstream
// consumers expect {id, seq, name, owner, station_type, cycle_min}.
function normalizeRoutingRow(r) {
  if (!r) return r;
  return {
    id: r.id || r.code || r.station,
    seq: r.seq,
    name: r.name || r.station,
    owner: r.owner || r.lead,
    station_type: r.station_type || r.type || "op",
    cycle_min: r.cycle_min || r.time_min || null,
    op_codes: r.op_codes || null,
    wi_ref: r.wi_ref || null,
  };
}

// ---------- M-BOM ----------
function ScreenMBOM() {
  const tenant = useActiveTenant();
  const useTenantRouting = !!(tenant && tenant.routing && tenant.routing.length);
  const isTritan = !!(tenant && tenant.tenant && tenant.tenant.id === "tritan");
  const [sku, setSku] = useVariantSku(tenant);
  const bom = getBomForSku(tenant, sku);
  const variantMeta = getVariantMeta(sku);
  // Build a station array shaped like the existing MBOM.stations contract.
  // Routing rows are normalized first so Aetherion's station/code shape works.
  const stations = useTenantRouting
    ? tenant.routing.map(function(raw) {
        const r = normalizeRoutingRow(raw);
        return {
          id: r.id, name: r.name,
          ops: (r.op_codes && r.op_codes.length) || 4,
          hours: r.cycle_min ? +(r.cycle_min/60).toFixed(2) : 0,
          wi: r.wi_ref || ("WI-" + (r.id || "").toUpperCase()),
          owner: r.owner, station_type: r.station_type,
          op_codes: r.op_codes,
          parts: [],
        };
      })
    : MBOM.stations;
  const [station, setStation] = uS2(useTenantRouting ? "s5" : (stations[1] ? stations[1].id : stations[0].id));
  const st = stations.find(s => s.id === station) || stations[0];
  // For tenant routing, fall back to MBOM.stations[1].parts if available, else stub picklist
  const stParts = useTenantRouting
    ? (bom && bom.lines
        ? (function() {
            const partsByNum = new Map();
            for (const x of (tenant.parts || [])) partsByNum.set(x.num, x);
            const out = []; let i = 0;
            for (const l of bom.lines) {
              if (stationForPartNum(l.part_num) !== st.id) continue;
              const p = partsByNum.get(l.part_num);
              out.push({ pn: l.part_num, name: p ? p.name : l.position, qty: l.qty, op: "OP-" + (st.id || "s").toUpperCase() + "-" + String(i+1).padStart(2,"0"), time: 4 });
              i++;
            }
            return out;
          })()
        : [])
    : (st.parts || []);
  const variantImpactRows = sku === "M-31507" ? [
      ["Δ-01","Machine shop: larger rotor + pump shafts","active"],
      ["Δ-02","Motor assy: 180SL stator stack, 5HP winding","queued"],
      ["Δ-03","Pump assy: 5-stage stack replaces 3-stage","queued"],
      ["Δ-04","Final test: longer pressure + efficiency run","queued"],
    ] : sku === "M-26102" ? [
      ["Δ-01","Carry over V4 chassis and 100SL stack","done"],
      ["Δ-02","Remove one pump stage from standard routing","done"],
      ["Δ-03","Reuse tooling from completed WO-44220 batch","done"],
      ["Δ-04","Close MES batch after final audit","active"],
    ] : [
      ["Δ-01","Cut in 20.07b NRV after serial TPX-H-0100","active"],
      ["Δ-02","Add S.G.-400 incoming cert gate at s2","queued"],
      ["Δ-03","Update ERP cost-center before T7 release","queued"],
      ["Δ-04","Line readiness holds one supplier expedite","queued"],
    ];
  const defaultTaskRows = [
    ["PK-01","Gearbox to fixture","done"],
    ["PK-02","Main shaft align","done"],
    ["PK-03","Generator couple","active"],
    ["PK-04","Brake caliper × 2","queued"],
    ["PK-05","Manifold hose kit","queued"],
    ["QA-06","Torque audit","queued"],
  ];
  const taskRows = isTritan ? variantImpactRows : defaultTaskRows;
  return (
    <div style={{ padding: 14, display: "grid", gridTemplateColumns: "220px minmax(0, 1fr) 240px", gap: 14, minHeight: 0, height: "100%" }}>
      <Panel title="Assembly sequence">
        <div style={{ padding: 8 }}>
          {isTritan && (
            <div style={{ marginBottom: 10 }}>
              <VariantSelector tenant={tenant} sku={sku} onSku={setSku} compact />
            </div>
          )}
          {stations.map((s, i) => {
            const _stationRowStyle = {
              display: "grid", gridTemplateColumns: "28px 1fr", gap: 8, padding: "8px 8px", cursor: "pointer",
              borderLeft: `2px solid ${s.id===station?"var(--accent)":"transparent"}`,
              background: s.id===station ? "var(--bg-2)" : "transparent", borderRadius: 4,
            };
            return (
            <div key={s.id} role="button" tabIndex={0} onClick={()=>setStation(s.id)} onKeyDown={(e)=>{ if(e.key==="Enter"||e.key===" "){ e.preventDefault(); setStation(s.id); } }} style={_stationRowStyle}>
              <div className="mono" style={{ fontSize: 12, color: "var(--ink-3)" }}>{String(i+1).padStart(2,"0")}</div>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 12, color: "var(--ink)" }}>{s.name}</div>
                <div className="mono" style={{ fontSize: 12, color: "var(--ink-3)" }}>{s.ops} ops · {s.hours}h · {s.wi}{s.owner?" · "+s.owner:""}</div>
              </div>
            </div>
            );
          })}
          <div className="hr"/>
          <div style={{ padding: 8 }}>
            <div className="label">Plan totals</div>
            <div style={{ display: "flex", justifyContent: "space-between", marginTop: 4 }}>
              <div><div className="label">Stations</div><div className="mono tnum" style={{ fontSize: 14 }}>{stations.length}</div></div>
              <div><div className="label">Hours</div><div className="mono tnum" style={{ fontSize: 14 }}>{stations.reduce((a,s)=>a+(s.hours||0),0).toFixed(1)}</div></div>
              <div><div className="label">Ops</div><div className="mono tnum" style={{ fontSize: 14 }}>{stations.reduce((a,s)=>a+(s.ops||0),0)}</div></div>
            </div>
          </div>
        </div>
      </Panel>

      <Panel title={`${st.name} · ${isTritan ? sku + " " : ""}routing & picklist`} right={<>
        <Tag>{st.wi}</Tag>
        <Btn size="sm" icon="Route" onClick={() => window.forgeToast && window.forgeToast("Routing view queued — wired in v2")}>routing</Btn>
        <Btn size="sm" icon="Clipboard" onClick={() => window.forgeToast && window.forgeToast("Work instruction opened — wired in v2")}>work instr.</Btn>
      </>}>
        <table className="dtable">
          <thead><tr><th>#</th><th>Part</th><th>Name</th><th style={{ textAlign: "right" }}>Qty</th><th>Op</th><th style={{ textAlign: "right" }}>Time</th><th>Kind</th></tr></thead>
          <tbody>
            {stParts.length ? stParts.map((p, i) => (
              <tr key={p.pn+i}>
                <td>{String(i+1).padStart(2,"0")}</td>
                <td style={{ color: "var(--ink)", fontWeight: 500 }}>{p.pn}</td>
                <td>{p.name}</td>
                <td className="tnum" style={{ textAlign: "right" }}>{p.qty}</td>
                <td>{p.op}</td>
                <td className="tnum" style={{ textAlign: "right" }}>{p.time}</td>
                <td>
                  {p.cons ? <Pill tone="warn">consumable</Pill>
                   : p.test ? <Pill tone="info">test</Pill>
                   : <Pill tone="ok">engineered</Pill>}
                </td>
              </tr>
            )) : (
              <tr>
                <td colSpan="7" style={{ color: "var(--ink-3)", padding: 14 }}>
                  No SKU-specific picklist rows at this station for {sku || "this model"}.
                </td>
              </tr>
            )}
          </tbody>
        </table>
        {(function() {
          // Derive ops list per active station/tenant:
          //  - Aetherion routing rows carry op_codes — use them directly.
          //  - Tritan keeps its legacy hardcoded ops strip.
          //  - Otherwise hide if neither source has ops.
          const ops = isTritan
            ? ["OP-MOT-10 Stator wind","OP-MOT-20 Rotor press","OP-PMP-10 Stage stack","OP-PMP-20 Bowl seal","OP-FIN-10 Couple","QA-30 No-load"]
            : (st && st.op_codes && st.op_codes.length ? st.op_codes : null);
          if (!ops) return null;
          return (
            <div style={{ padding: 12, borderTop: "1px solid var(--line-soft)" }}>
              <div className="label">Station routing</div>
              <div style={{ display: "flex", alignItems: "center", gap: 0, marginTop: 8, overflowX: "auto" }}>
                {ops.map((op, i, arr) => (
                  <React.Fragment key={op}>
                    {(() => {
                      const _opPillStyle = { padding: "6px 10px", border: "1px solid var(--line)", background: "var(--bg-2)",
                        borderRadius: 4, whiteSpace: "nowrap", fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--ink-2)" };
                      return <div style={_opPillStyle}>{op}</div>;
                    })()}
                    {i < arr.length-1 && <div style={{ width: 24, height: 1, background: "var(--line-strong)" }} />}
                  </React.Fragment>
                ))}
              </div>
            </div>
          );
        })()}
      </Panel>

      <div style={{ display: "grid", gridTemplateRows: "1fr 1fr", gap: 14, minHeight: 0 }}>
        <Panel title="Work cell · live">
          <div style={{ padding: 12 }}>
            <Stripes label="Station camera · cell-02" h={120}>
              <div style={{ position:"absolute", bottom: 6, left: 8 }} className="mono">
                <span className="pill ok"><span className="dot pulse"/>LIVE · 24 fps</span>
              </div>
            </Stripes>
            <div style={{ marginTop: 10 }}>
              <KV k="Operator"      v={isTritan ? "Rohit B." : "T. Nasser"} />
              <KV k="Torque wrench" v={isTritan ? "TRQ-2 · cal 2026-03-12" : "TRQ-4 · cal 2026-03-02"} />
              <KV k="WIP"           v={isTritan ? "S/N TPX-H-0044" : "S/N 004"} />
              <KV k="Takt"          v={isTritan ? "8m 40s / 9m 20s" : "11h 12m / 11h 20m"} />
            </div>
          </div>
        </Panel>
        <Panel title={isTritan ? "Variant downstream impact" : "Pick/Place tasks"}>
          <div style={{ padding: 8 }}>
            {isTritan ? (
              <>
                <div style={{ padding: "4px 8px 10px" }}>
                  <KV k="Model" v={variantMeta.name} />
                  <KV k="EBOM lines" v={bom && bom.lines ? String(bom.lines.length) : "—"} />
                  <KV k="Line change" v={variantMeta.lineImpact} />
                </div>
              </>
            ) : null}
            {taskRows.map(([id, t, s]) => (
              <div key={id} style={{ display: "grid", gridTemplateColumns: "auto 1fr auto", gap: 8, alignItems: "center",
                padding: "6px 8px", borderBottom: "1px solid var(--line-soft)" }}>
                <span className="tag">{id}</span>
                <span style={{ fontSize: 12, color: s==="done"?"var(--ink-3)":"var(--ink-2)", textDecoration: s==="done"?"line-through":"none" }}>{t}</span>
                <Pill tone={s==="done"?"ok":s==="active"?"accent":""}>{s}</Pill>
              </div>
            ))}
          </div>
        </Panel>
      </div>
    </div>
  );
}

// ---------- E → M transformation canvas ----------
function ScreenETM({ mode = "dag" }) {
  const tenant = useActiveTenant();
  const isTritan = !!(tenant && tenant.tenant && tenant.tenant.id === "tritan");
  const [sku, setSku] = useVariantSku(tenant);
  const [run, setRun] = uS2({ T1: true, T2: true, T3: true, T4: true, T5: false, T6: true, T7: true });
  return (
    <div style={{ padding: 14, display: "grid", gridTemplateRows: "auto 1fr", gap: 14, height: "100%", minHeight: 0 }}>
      <Panel title="Transformation rules · E-BOM → M-BOM" right={<>
        <Tag>pipeline</Tag>
        <Btn size="sm" icon="Play" variant="primary" onClick={() => window.forgeToast && window.forgeToast("Pipeline run queued — wired in v2")}>Run pipeline</Btn>
        <Btn size="sm" icon="Diff" onClick={() => window.forgeToast && window.forgeToast("Diff preview queued — wired in v2")}>Diff preview</Btn>
      </>}>
        {isTritan && (
          <div style={{ padding: "10px 10px 0" }}>
            <VariantSelector tenant={tenant} sku={sku} onSku={setSku} />
          </div>
        )}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(7, 1fr)", padding: 10, gap: 10 }}>
          {TRANSFORMS.map((t, i) => (
            <div key={t.id} style={{ padding: 10, border: "1px solid var(--line-soft)", borderRadius: 6,
              background: run[t.id] ? "var(--bg-2)" : "var(--bg-1)" }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                <span className="mono" style={{ fontSize: 12, color: "var(--ink-3)" }}>T{i+1} · {t.kind}</span>
                <input type="checkbox" id={"ebom-transform-" + t.id} name={"ebom-transform-" + t.id}
                  aria-label={"Include " + t.name + " in pipeline run"}
                  checked={run[t.id]} onChange={e=>setRun(prev => ({...prev, [t.id]: e.target.checked}))}
                  style={{ accentColor: "var(--accent)" }}/>
              </div>
              <div style={{ fontSize: 12, color: "var(--ink)", marginTop: 4 }}>{t.name}</div>
              <div className="muted" style={{ fontSize: 12, marginTop: 2 }}>{t.desc}</div>
            </div>
          ))}
        </div>
      </Panel>

      <Panel title="Transformation canvas · DAG" right={<>
        {isTritan && <Tag>{sku}</Tag>}
        <Tag>7 stages</Tag>
        <Pill tone="ok">last run OK · 2m ago</Pill>
      </>}>
        <ETMCanvas run={run} tenant={tenant} sku={sku}/>
      </Panel>
    </div>
  );
}

function ETMCanvas({ run, tenant, sku }) {
  // three-column flow: E-BOM sources → transforms → M-BOM outputs
  const tenantRouting = tenant && tenant.routing && tenant.routing.length ? tenant.routing : null;
  const tenantId = tenant && tenant.tenant ? tenant.tenant.id : null;
  const bom = getBomForSku(tenant, sku);
  const variantMeta = getVariantMeta(sku);
  const lineCount = bom && bom.lines ? bom.lines.length : 112;
  const consumableCount = tenantId === "tritan" ? Math.max(8, Math.round(lineCount * 0.8)) : 38;
  const testCount = tenantId === "tritan" ? (sku === "M-31507" ? 9 : 7) : 7;
  const outCount = lineCount + consumableCount + testCount;

  const sources = tenantRouting
    ? [
        { id: "E-MOT",  label: "E-BOM · Motor",      sub: tenantId === "tritan" ? "10.*" : "engineering",      tone: "info"   },
        { id: "E-PUMP", label: "E-BOM · Pump",       sub: tenantId === "tritan" ? "20.*" : "engineering",      tone: "info"   },
        { id: "E-CBL",  label: "E-BOM · Cable kit",  sub: tenantId === "tritan" ? "30.*" : "—",                tone: "info"   },
        { id: "E-PKG",  label: "E-BOM · Packaging",  sub: tenantId === "tritan" ? "40.*" : "—",                tone: "info"   },
        { id: "K-SUP",  label: "Supplier Kits",      sub: "incoming inspect",  tone: "accent" },
        { id: "P-QA",   label: "Quality Gates",      sub: "30 CTQ checks",     tone: "accent" },
      ]
    : [
        { id: "E-ROT", label: "E-BOM · Rotor",       sub: "HTU-220.10.*", tone: "info" },
        { id: "E-NAC", label: "E-BOM · Nacelle",     sub: "HTU-220.20.*", tone: "info" },
        { id: "E-MON", label: "E-BOM · Monopile",    sub: "HTU-220.30.*", tone: "info" },
        { id: "E-ELE", label: "E-BOM · Electrical",  sub: "HTU-220.40.*", tone: "info" },
        { id: "K-SUP", label: "Supplier Kits",       sub: "consumables DB", tone: "accent" },
        { id: "P-QA",  label: "QA Test Plans",       sub: "FAT procedures", tone: "accent" },
      ];

  const outputs = tenantRouting
    ? tenantRouting.slice(0, 6).map(function(s) {
        return {
          id: "ST-" + (s.id || "").toUpperCase(),
          label: "M-BOM · " + s.name,
          sub: "routing · " + s.cycle_min + " min · " + (s.owner || "—"),
        };
      }).concat([{ id: "ERP", label: "ERP · item-master upsert", sub: "→ sync queue" }]).slice(0, 6)
    : [
        { id: "ST-10", label: "M-BOM · ST-10 Rotor",      sub: "routing · 4 ops · 6.5h" },
        { id: "ST-20", label: "M-BOM · ST-20 Nacelle",    sub: "routing · 6 ops · 11.2h" },
        { id: "ST-30", label: "M-BOM · ST-30 Monopile",   sub: "routing · 3 ops · 4.0h" },
        { id: "ST-40", label: "M-BOM · ST-40 Electrical", sub: "routing · 5 ops · 7.6h" },
        { id: "ST-50", label: "M-BOM · ST-50 FAT",        sub: "procedures · 2 ops · 4.0h" },
        { id: "ERP",   label: "ERP · item-master upsert", sub: "→ sync queue" },
      ];

  const stages = TRANSFORMS;

  return (
    <div style={{ position: "relative", height: "100%", padding: 20, overflow: "auto" }}>
      <svg style={{ position: "absolute", inset: 0, width: "100%", height: "100%", pointerEvents: "none" }}>
        <defs>
          <linearGradient id="flow" x1="0" x2="1">
            <stop offset="0" stopColor="var(--cool)" stopOpacity="0.0"/>
            <stop offset="0.5" stopColor="var(--accent)" stopOpacity="0.9"/>
            <stop offset="1" stopColor="var(--ok)" stopOpacity="0.0"/>
          </linearGradient>
        </defs>
        {/* decorative flow lines */}
        {Array.from({length: 18}).map((_, i) => {
          const y = 60 + i * 34;
          return <path key={i} d={`M 220 ${y} C 380 ${y + (i%2?20:-20)}, 620 ${y + (i%3?-16:22)}, 820 ${y}`}
            stroke="url(#flow)" strokeWidth="0.9" fill="none" opacity="0.35"/>;
        })}
      </svg>

      <div style={{ position: "relative", display: "grid", gridTemplateColumns: "220px 1fr 220px", gap: 20, alignItems: "start" }}>
        <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          <div className="label">Sources</div>
          {sources.map(s => <NodeBlock key={s.id} {...s} />)}
        </div>

        <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
          <div className="label" style={{ textAlign: "center" }}>Pipeline</div>
          {stages.map((t, i) => {
            const _stageRowStyle = {
              display: "grid", gridTemplateColumns: "34px 1fr auto", gap: 10, alignItems: "center",
              padding: "10px 12px", border: `1px solid ${run[t.id] ? "var(--line-strong)" : "var(--line-soft)"}`,
              borderRadius: 6, background: run[t.id] ? "var(--bg-2)" : "var(--bg-1)",
              opacity: run[t.id] ? 1 : 0.5,
            };
            return (
            <div key={t.id} style={_stageRowStyle}>
              <div className="mono" style={{ fontSize: 12, color: "var(--accent)", textAlign: "center", borderRight: "1px solid var(--line-soft)", paddingRight: 10 }}>T{i+1}</div>
              <div>
                <div style={{ fontSize: 12, color: "var(--ink)" }}>{t.name}</div>
                <div className="muted" style={{ fontSize: 12 }}>{t.desc}</div>
              </div>
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <Tag>{t.kind}</Tag>
                {run[t.id] ? <Pill tone="ok">ACTIVE</Pill> : <Pill>SKIP</Pill>}
              </div>
            </div>
            );
          })}
        </div>

        <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          <div className="label" style={{ textAlign: "right" }}>Outputs</div>
          {outputs.map(o => <NodeBlock key={o.id} {...o} right tone="ok"/>)}
        </div>
      </div>

      {/* diff summary strip */}
      <div style={{ position: "relative", marginTop: 24, border: "1px solid var(--line-soft)", borderRadius: 6, overflow: "hidden" }}>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", borderBottom: "1px solid var(--line-soft)" }}>
          {[
            ["E-BOM items in", String(lineCount)],
            ["Consumables injected", "+" + consumableCount],
            ["Tests injected", "+" + testCount],
            ["M-BOM items out", String(outCount)],
          ].map(([k,v]) => (
            <div key={k} style={{ padding: "10px 12px", borderRight: "1px solid var(--line-soft)" }}>
              <div className="label">{k}</div>
              <div className="mono tnum" style={{ fontSize: 20 }}>{v}</div>
            </div>
          ))}
        </div>
        {tenantId === "tritan" && (
          <div style={{ padding: 12, fontSize: 12, color: "var(--ink-2)" }}>
            <div><span className="mono" style={{ color: "var(--ok)" }}>+ ADD</span> {sku} station plan: receiving → inspect → storage → machine shop → motor assy → test → final.</div>
            <div><span className="mono" style={{ color: "var(--ok)" }}>+ ADD</span> {consumableCount} consumables and shop-floor docs from T2/T4 for {variantMeta.name}.</div>
            <div><span className="mono" style={{ color: "var(--warn)" }}>~ CHG</span> Variant effectivity: {variantMeta.effectivity}.</div>
            <div><span className="mono" style={{ color: "var(--warn)" }}>~ CHG</span> Manufacturing line impact: {variantMeta.lineImpact}</div>
            <div><span className="mono" style={{ color: sku === "M-27418" ? "var(--err)" : "var(--ok)" }}>{sku === "M-27418" ? "! VAL" : "✓ VAL"}</span> {sku === "M-27418" ? "20.07 NRV body missing cost-center on rev B — blocks T7 (ERP mapping)" : "ERP mapping clears with SKU-specific item-master and routing rev."}</div>
          </div>
        )}
      </div>
    </div>
  );
}
function NodeBlock({ label, sub, tone = "info", right }) {
  return (
    <div style={{ padding: 10, border: "1px solid var(--line-soft)", borderRadius: 6,
      background: "var(--bg-1)", textAlign: right ? "right" : "left" }}>
      <div style={{ display: "flex", justifyContent: right ? "flex-end" : "flex-start", marginBottom: 4 }}>
        <Pill tone={tone}>{tone === "ok" ? "OUT" : tone === "accent" ? "INJECT" : "IN"}</Pill>
      </div>
      <div style={{ fontSize: 12, color: "var(--ink)" }}>{label}</div>
      <div className="muted mono" style={{ fontSize: 12 }}>{sub}</div>
    </div>
  );
}

Object.assign(window, { ScreenEBOM, ScreenMBOM, ScreenETM });
