// lattice-meridian.jsx — MERIDIAN orchestration view.
// The organization as an organism: each meridian is a pipeline carrying data ("energy")
// from organs (sources) through points (modules) to the places that act on it (sinks).
// Everything is a module: install from the registry, wire into a meridian, scope who can read it.

const { useState: merUseState, useEffect: merUseEffect } = React;
const merLS = (k, fb) => { try { const v = localStorage.getItem("lattice:" + k); return v == null ? fb : JSON.parse(v); } catch { return fb; } };
const merSetLS = (k, v) => { try { localStorage.setItem("lattice:" + k, JSON.stringify(v)); } catch {} };

const MER_KIND = { source: "Source", transform: "Transform", model: "Model", sink: "Sink" };
const MER_KIND_ICON = { source: "inbox", transform: "zap", model: "sparkles", sink: "arrow-up-right" };
const MER_SCOPES = ["Ops", "Risk", "Assets", "Customer", "Field service", "Compliance"];

const MER_SEED = [
  { id: "telemetry", name: "Telemetry", desc: "Remote systems & sensors → operations center", hue: "hsl(205 34% 52%)", icon: "activity", paused: false,
    points: [
      { id: "g1", name: "Remote telemetry ingest", kind: "source", rate: "412k pts/s", ver: "3.2.0", in: "telemetry.Frame", out: "ts.Measurement", status: "ok" },
      { id: "g2", name: "High-rate sensor stream", kind: "source", rate: "60 Hz × 1.2k", ver: "1.8.1", in: "sensor.Sample", out: "ts.Measurement", status: "ok" },
      { id: "g3", name: "Schema normalize", kind: "transform", rate: "480k/s", ver: "2.0.4", in: "ts.*", out: "ts.Measurement", status: "ok" },
      { id: "g4", name: "chronos-2.6b anomaly", kind: "model", rate: "p99 12 ms", ver: "20260311", in: "ts.Measurement", out: "lattice.Anomaly", status: "ok" },
      { id: "g5", name: "Ops console", kind: "sink", rate: "4.1k ev/min", ver: "—", in: "lattice.Anomaly", out: "—", status: "ok" },
    ], shares: ["risk", "field"] },
  { id: "risk", name: "Risk signals", desc: "Cameras & environmental feeds → risk decisions", hue: "hsl(22 40% 52%)", icon: "alert-circle", paused: false,
    points: [
      { id: "w1", name: "Camera feeds", kind: "source", rate: "1,140 feeds", ver: "2.4.0", in: "rtsp", out: "media.Frame", status: "ok" },
      { id: "w2", name: "Detection model", kind: "model", rate: "p99 41 ms", ver: "20260502", in: "media.Frame", out: "geo.Detection", status: "warn" },
      { id: "w3", name: "Environmental feeds", kind: "source", rate: "1,620 stations", ver: "1.1.2", in: "env.Obs", out: "env.Obs", status: "ok" },
      { id: "w4", name: "Risk fusion", kind: "transform", rate: "10 s window", ver: "0.9.7", in: "geo.* · env.*", out: "risk.Cell", status: "ok" },
      { id: "w5", name: "Decision board", kind: "sink", rate: "37 zones", ver: "—", in: "risk.Cell", out: "—", status: "ok" },
    ], shares: ["telemetry", "customer"] },
  { id: "asset", name: "Asset health", desc: "Inspection data → maintenance", hue: "hsl(150 26% 42%)", icon: "layers", paused: false,
    points: [
      { id: "a1", name: "Scan data", kind: "source", rate: "9.4 TB/wk", ver: "1.3.0", in: "pointcloud", out: "geo.PointCloud", status: "ok" },
      { id: "a2", name: "Inspection imagery", kind: "source", rate: "2.2k img/h", ver: "2.1.0", in: "jpeg+exif", out: "media.Frame", status: "ok" },
      { id: "a3", name: "defect-cls v5", kind: "model", rate: "p99 88 ms", ver: "20260419", in: "media.Frame", out: "asset.Defect", status: "ok" },
      { id: "a4", name: "Work-order system", kind: "sink", rate: "212 / day", ver: "—", in: "asset.Defect", out: "—", status: "ok" },
    ], shares: ["field"] },
  { id: "customer", name: "Customer", desc: "Device & account signals → service", hue: "hsl(265 22% 56%)", icon: "users", paused: false,
    points: [
      { id: "c1", name: "Endpoint devices", kind: "source", rate: "5.5M devices", ver: "4.0.1", in: "device.Read", out: "device.Read", status: "ok" },
      { id: "c2", name: "Service-impact model", kind: "model", rate: "p99 220 ms", ver: "20260328", in: "device.Read", out: "svc.Impact", status: "ok" },
      { id: "c3", name: "Case management", kind: "sink", rate: "live", ver: "—", in: "svc.Impact", out: "—", status: "ok" },
      { id: "c4", name: "Notifications", kind: "sink", rate: "SMS · app", ver: "—", in: "svc.Impact", out: "—", status: "ok" },
    ], shares: ["risk"] },
  { id: "field", name: "Field service", desc: "Crews, edge nodes, geofences → dispatch", hue: "hsl(42 34% 46%)", icon: "git-branch", paused: false,
    points: [
      { id: "f1", name: "Crew location", kind: "source", rate: "3,900 units", ver: "1.6.0", in: "gps", out: "geo.Track", status: "ok" },
      { id: "f2", name: "Lattice edge nodes", kind: "source", rate: "19 nodes", ver: "lattice 0.14", in: "zenoh", out: "lattice.Event", status: "ok" },
      { id: "f3", name: "geo-fence-eval.wasm", kind: "transform", rate: "42.1 Mpps", ver: "1.9.3", in: "geo.Track", out: "geo.Breach", status: "warn" },
      { id: "f4", name: "Dispatch", kind: "sink", rate: "live", ver: "—", in: "geo.Breach", out: "—", status: "ok" },
    ], shares: ["telemetry", "asset"] },
];

const MER_REGISTRY = [
  { name: "Time-series historian", kind: "source", meta: "Archived tags", rate: "210k tags", in: "ts.Point", out: "ts.Measurement" },
  { name: "GIS feature service", kind: "source", meta: "Spatial layers", rate: "4.8M features", in: "geojson", out: "geo.Feature" },
  { name: "Satellite imagery", kind: "source", meta: "Thermal · optical", rate: "5 min", in: "netcdf", out: "geo.Detection" },
  { name: "Unit convert", kind: "transform", meta: "WASM · 42 KB", rate: "~2M/s", in: "ts.*", out: "ts.*" },
  { name: "PII redact", kind: "transform", meta: "WASM · policy", rate: "~800k/s", in: "any", out: "any" },
  { name: "Window aggregate", kind: "transform", meta: "WASM · tumbling", rate: "~1M/s", in: "any", out: "agg.Window" },
  { name: "segment-v4", kind: "model", meta: "Spatial segmentation", rate: "p99 28 ms", in: "geo.PointCloud", out: "geo.Segment" },
  { name: "demand-forecast", kind: "model", meta: "48 h horizon", rate: "p99 1.2 s", in: "ts.Measurement", out: "fc.Demand" },
  { name: "Data warehouse", kind: "sink", meta: "Batch export", rate: "every 60 s", in: "any", out: "—" },
  { name: "Compliance reporting", kind: "sink", meta: "Scheduled filings", rate: "daily", in: "risk.* · svc.*", out: "—" },
  { name: "Chat & paging", kind: "sink", meta: "Alerting", rate: "live", in: "lattice.Anomaly", out: "—" },
];

function MeridianView() {
  const [meridians, setMeridians] = merUseState(() => merLS("meridians:v2", MER_SEED));
  const [focus, setFocus] = merUseState("telemetry");
  const [sel, setSel] = merUseState(() => ({ m: "telemetry", p: "g4" }));
  const [q, setQ] = merUseState("");
  const [pending, setPending] = merUseState(0);
  const [toast, setToast] = merUseState(null);
  const [cfg, setCfg] = merUseState({});
  const [regOpen, setRegOpen] = merUseState(false);

  merUseEffect(() => merSetLS("meridians:v2", meridians), [meridians]);
  merUseEffect(() => { if (!toast) return; const t = setTimeout(() => setToast(null), 2400); return () => clearTimeout(t); }, [toast]);

  const mer = meridians.find(m => m.id === sel?.m);
  const pt = mer?.points.find(p => p.id === sel?.p);
  const pcfg = (pt && cfg[pt.id]) || { mode: "stream", sample: "1 s", retention: "30 days", scopes: ["Ops", "Risk"] };
  const setP = (patch) => { setCfg(c => ({ ...c, [pt.id]: { ...pcfg, ...patch } })); setPending(n => n + 1); };

  const update = (mid, fn) => setMeridians(ms => ms.map(m => m.id === mid ? fn(m) : m));
  const togglePause = (mid) => { update(mid, m => ({ ...m, paused: !m.paused })); setPending(n => n + 1); };
  const togglePoint = () => { update(mer.id, m => ({ ...m, points: m.points.map(p => p.id === pt.id ? { ...p, status: p.status === "off" ? "ok" : "off" } : p) })); setPending(n => n + 1); };
  const removePoint = () => { update(mer.id, m => ({ ...m, points: m.points.filter(p => p.id !== pt.id) })); setSel(null); setPending(n => n + 1); };
  const install = (r) => {
    const id = "x" + Math.random().toString(36).slice(2, 7);
    update(focus, m => {
      const pts = [...m.points];
      const firstSink = pts.findIndex(p => p.kind === "sink");
      const at = r.kind === "sink" ? pts.length : r.kind === "source" ? 0 : (firstSink < 0 ? pts.length : firstSink);
      pts.splice(at, 0, { id, name: r.name, kind: r.kind, rate: r.rate, ver: "1.0.0", in: r.in, out: r.out, status: "ok", fresh: true });
      return { ...m, points: pts };
    });
    setSel({ m: focus, p: id }); setPending(n => n + 1);
    setRegOpen(false);
    setToast(`${r.name} wired into ${meridians.find(m => m.id === focus).name}`);
  };

  const reg = MER_REGISTRY.filter(r => !q || (r.name + r.meta + r.kind).toLowerCase().includes(q.toLowerCase()));
  const totalPts = meridians.reduce((s, m) => s + m.points.length, 0);
  const flowing = meridians.filter(m => !m.paused).length;
  const focusM = meridians.find(m => m.id === focus);

  return (
    <div className="mer">
      {regOpen && <div className="mer__scrim" onClick={() => setRegOpen(false)}/>}
      <aside className={"mer__side mer__side--l" + (regOpen ? " mer__side--open" : "")}>
        <div className="mer__sidehead">
          <div>
            <div className="row" style={{ justifyContent: "space-between" }}><div className="mer__h">Module registry</div><button className="icon-btn mer__only-narrow" onClick={() => setRegOpen(false)} aria-label="close"><Icon name="x" size={14}/></button></div>
            <div className="mer__sub">Adds to <b style={{ color: "var(--foreground)" }}>{focusM?.name}</b> — pick a meridian to retarget.</div>
          </div>
          <div className="mer__search"><Icon name="search" size={14}/><input placeholder="Search plugins" value={q} onChange={e => setQ(e.target.value)}/></div>
        </div>
        <div className="mer__scroll">
          {["source", "transform", "model", "sink"].map(k => {
            const items = reg.filter(r => r.kind === k);
            if (!items.length) return null;
            return (
              <div key={k}>
                <div className="mer__group"><span>{MER_KIND[k]}s</span><span>{items.length}</span></div>
                {items.map(r => (
                  <div className="mer__plug" key={r.name} onClick={() => install(r)}>
                    <span className="mer__plug-ic"><Icon name={MER_KIND_ICON[k]} size={15}/></span>
                    <div style={{ minWidth: 0 }}>
                      <div className="mer__plug-name">{r.name}</div>
                      <div className="mer__plug-meta">{r.meta}</div>
                    </div>
                    <button className="mer__plug-add" aria-label={"add " + r.name}><Icon name="plus" size={13}/></button>
                  </div>
                ))}
              </div>
            );
          })}
        </div>
      </aside>

      <main className="mer__center">
        <div className="mer__top">
          <div>
            <div className="mer__title">Meridian</div>
            <div className="mer__lead">Every system in the organization is a module. Meridians are the pipelines that carry its data between them — wire, scope and pause each one here.</div>
          </div>
          <div className="mer__actions">
            <button className="btn btn--secondary mer__only-mid" onClick={() => setRegOpen(true)}><Icon name="plus" size={14}/> Add module</button>
            <button className="btn btn--secondary" onClick={() => setToast("Contracts valid · 0 schema conflicts")}><Icon name="check-circle" size={14}/> Validate</button>
            <button className="btn btn--primary" disabled={!pending} style={{ opacity: pending ? 1 : 0.5 }}
              onClick={() => { setToast(`Deployed ${pending} change${pending > 1 ? "s" : ""} to 19 edge nodes`); setPending(0); }}>
              Deploy{pending ? ` ${pending} change${pending > 1 ? "s" : ""}` : ""}
            </button>
          </div>
        </div>

        <div className="mer__kpis">
          <div className="mer__kpi"><div className="mer__kpi-l">Meridians flowing</div><div className="mer__kpi-v">{flowing}<small>/ {meridians.length}</small></div></div>
          <div className="mer__kpi"><div className="mer__kpi-l">Modules wired</div><div className="mer__kpi-v">{totalPts}</div></div>
          <div className="mer__kpi"><div className="mer__kpi-l">Throughput</div><div className="mer__kpi-v">2.14<small>GB/s</small></div></div>
          <div className="mer__kpi"><div className="mer__kpi-l">Cross-meridian links</div><div className="mer__kpi-v">{meridians.reduce((s, m) => s + m.shares.length, 0)}</div></div>
        </div>

        <div className="mer__lanes">
          {meridians.map(m => (
            <section key={m.id} style={{ "--hue": m.hue }}
              className={"mer-lane" + (focus === m.id ? " mer-lane--focus" : "") + (m.paused ? " mer-lane--paused" : "")}>
              <div className="mer-lane__head" onClick={() => setFocus(m.id)}>
                <span className="mer-lane__glyph"><Icon name={m.icon} size={17}/></span>
                <div>
                  <div className="mer-lane__name">{m.name}</div>
                  <div className="mer-lane__desc">{m.desc}</div>
                </div>
                <div className="mer-lane__stats">
                  <div className="mer-lane__stat"><b>{m.points.length}</b><span>modules</span></div>
                  <div className="mer-lane__stat"><b>{m.paused ? "Paused" : "Flowing"}</b><span>state</span></div>
                  <button className="icon-btn" style={{ border: "1px solid var(--border)" }} aria-label="pause"
                    onClick={(e) => { e.stopPropagation(); togglePause(m.id); }}>
                    <Icon name={m.paused ? "play" : "pause"} size={14}/>
                  </button>
                </div>
              </div>
              <div className="mer-lane__flow">
                {m.points.map((p, i) => (
                  <React.Fragment key={p.id}>
                    {i > 0 && <span className="mer-link"/>}
                    <div className={"mer-pt" + (sel?.p === p.id ? " mer-pt--sel" : "") + (p.status === "off" ? " mer-pt--off" : "") + (p.fresh ? " mer-pt--new" : "")}
                      onClick={() => { setSel({ m: m.id, p: p.id }); setFocus(m.id); }}>
                      <div className="mer-pt__kind"><span>{MER_KIND[p.kind]}</span><span className={"mer-pt__st" + (p.status === "warn" ? " mer-pt__st--warn" : p.status === "off" ? " mer-pt__st--off" : "")}/></div>
                      <div className="mer-pt__name" title={p.name}>{p.name}</div>
                      <div className="mer-pt__rate">{p.rate}</div>
                    </div>
                  </React.Fragment>
                ))}
              </div>
              <div className="mer-lane__share">
                <span>Shares energy with</span>
                {m.shares.map(s => { const o = meridians.find(x => x.id === s); return o && <span key={s} className="mer-tag" style={{ "--hue": o.hue }}><i/>{o.name}</span>; })}
              </div>
            </section>
          ))}
        </div>
      </main>

      <aside className={"mer__side mer__side--r" + (pt ? " mer__side--has" : "")}>
        {!pt ? (
          <div className="mer__insp-empty">Select a module in any meridian to configure how it runs, what it emits, and which parts of the organization can see its data.</div>
        ) : (
          <>
            <div className="mer__sidehead" style={{ borderBottom: "1px solid var(--border)", paddingBottom: 20 }}>
              <div className="row" style={{ gap: 12 }}>
                <button className="icon-btn mer__only-narrow" style={{ order: 2, marginLeft: "auto" }} onClick={() => setSel(null)} aria-label="close"><Icon name="x" size={14}/></button>
                <span className="mer__plug-ic" style={{ width: 40, height: 40, borderRadius: 11, color: mer.hue, background: `hsl(from ${mer.hue} h s l / 0.14)` }}><Icon name={MER_KIND_ICON[pt.kind]} size={18}/></span>
                <div style={{ minWidth: 0 }}>
                  <div className="mer__h" style={{ fontSize: 18 }}>{pt.name}</div>
                  <div className="mer__sub">{MER_KIND[pt.kind]} · {mer.name} · v{pt.ver}</div>
                </div>
              </div>
              <div className="row" style={{ gap: 8 }}>
                <span className={"pill " + (pt.status === "off" ? "pill--mute" : pt.status === "warn" ? "pill--warn" : "pill--ok")}>{pt.status === "off" ? "disabled" : pt.status === "warn" ? "degraded" : "healthy"}</span>
                <span className="mer__sub mono" style={{ fontFamily: "var(--font-code)" }}>{pt.rate}</span>
              </div>
            </div>
            <div className="mer__insp">
              <div className="mer__field">
                <div className="mer__label">Delivery</div>
                <div className="mer__seg">
                  {["stream", "batch", "on-demand"].map(v => <button key={v} className={pcfg.mode === v ? "on" : ""} onClick={() => setP({ mode: v })}>{v[0].toUpperCase() + v.slice(1)}</button>)}
                </div>
              </div>
              <div className="grid grid--2" style={{ gap: 12 }}>
                <div className="mer__field">
                  <div className="mer__label">Sample rate</div>
                  <select className="mer__select" value={pcfg.sample} onChange={e => setP({ sample: e.target.value })}>
                    {["100 ms", "1 s", "10 s", "1 min"].map(o => <option key={o}>{o}</option>)}
                  </select>
                </div>
                <div className="mer__field">
                  <div className="mer__label">Retention</div>
                  <select className="mer__select" value={pcfg.retention} onChange={e => setP({ retention: e.target.value })}>
                    {["24 hours", "7 days", "30 days", "7 years"].map(o => <option key={o}>{o}</option>)}
                  </select>
                </div>
              </div>
              <div className="mer__field">
                <div className="mer__label">Visible to</div>
                <div className="mer__chips">
                  {MER_SCOPES.map(s => {
                    const on = pcfg.scopes.includes(s);
                    return <button key={s} className={"mer__chip" + (on ? " on" : "")} onClick={() => setP({ scopes: on ? pcfg.scopes.filter(x => x !== s) : [...pcfg.scopes, s] })}>{s}</button>;
                  })}
                </div>
              </div>
              <div className="mer__field">
                <div className="mer__label">Contract</div>
                <dl className="mer__contract">
                  <dt>Consumes</dt><dd>{pt.in}</dd>
                  <dt>Emits</dt><dd>{pt.out}</dd>
                  <dt>Runtime</dt><dd>{pt.kind === "transform" ? "wasm32-wasip2" : pt.kind === "model" ? "onnx · edge" : "connector"}</dd>
                  <dt>Version</dt><dd>{pt.ver}</dd>
                </dl>
              </div>
            </div>
            <div className="mer__bar">
              <button className="btn btn--secondary" style={{ flex: 1, justifyContent: "center" }} onClick={togglePoint}>{pt.status === "off" ? "Enable" : "Disable"}</button>
              <button className="btn btn--ghost" style={{ color: "var(--destructive)" }} onClick={removePoint}><Icon name="trash" size={14}/> Remove</button>
            </div>
          </>
        )}
      </aside>
      {toast && <div className="mer__toast"><Icon name="check-circle" size={15}/>{toast}</div>}
    </div>
  );
}

Object.assign(window, { MeridianView, MER_SEED, MER_REGISTRY });
