// lattice-panels.jsx — Bottom-strip dashboard panels.
// All cards expose to window so the App can compose them in any order.

const { useMemo } = React;

// ─── Sparkline (reused everywhere) ────────────────────────────────────
function Sparkline({ points, color = "var(--primary)", height = 36 }) {
  const w = 280;
  if (!points.length) return null;
  const min = Math.min(...points), max = Math.max(...points);
  const norm = v => height - 4 - ((v - min) / (max - min || 1)) * (height - 8);
  const step = w / (points.length - 1);
  const d = points.map((p, i) => `${i === 0 ? "M" : "L"}${(i*step).toFixed(1)},${norm(p).toFixed(1)}`).join(" ");
  const area = d + ` L${w},${height} L0,${height} Z`;
  const gradId = "sg-" + color.replace(/\W/g, "");
  return (
    <svg className="spark" viewBox={`0 0 ${w} ${height}`} preserveAspectRatio="none" style={{ height }}>
      <defs>
        <linearGradient id={gradId} x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%"  stopColor={color} stopOpacity="0.32"/>
          <stop offset="100%" stopColor={color} stopOpacity="0"/>
        </linearGradient>
      </defs>
      <path d={area} fill={`url(#${gradId})`}/>
      <path d={d} fill="none" stroke={color} strokeWidth="1.4" strokeLinejoin="round" strokeLinecap="round"/>
    </svg>
  );
}

// ─── WASM modules ────────────────────────────────────────────────────
function ModulesCard() {
  return (
    <div className="card">
      <div className="card__head">
        <div className="card__title">WASM modules · edge</div>
        <span className="row" style={{ gap: 6 }}>
          <span className="pill pill--ok">85 / 114 hosts</span>
          <Icon name="plus" size={12} style={{ color: "var(--muted-foreground)", cursor: "grab" }}/>
        </span>
      </div>
      <div className="card__body modules">
        {MODULES.map(m => (
          <div className="modules__row" key={m.name}>
            <div className="modules__row-name">{m.name}</div>
            <div className="modules__row-host mono">{m.deployed}/{m.total}</div>
            <div className="modules__bar"><span style={{ width: `${m.load * 100}%`, background: m.status === "warn" ? "var(--warning)" : "var(--primary)" }}/></div>
            <div className="modules__rate">{m.rate}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ─── AI inference ────────────────────────────────────────────────────
function InferenceCard() {
  return (
    <div className="card">
      <div className="card__head">
        <div className="card__title">Active inference · lattice</div>
        <span className="pill"><Icon name="sparkles" size={10}/> {MODELS.length} models</span>
      </div>
      <div className="card__body col">
        {MODELS.map(m => (
          <div className="lane" key={m.id}>
            <span className="dot" style={{ color: m.tone === "warn" ? "var(--warning)" : "var(--info)" }}/>
            <span className="lane__name">{m.id}</span>
            <span className="lane__task muted">{m.task}</span>
            <span className="lane__val">{m.p99}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

// ─── Telemetry sparklines ───────────────────────────────────────────
function TelemetryCard({ tick }) {
  const series = useMemo(() => {
    const len = 60;
    const seed = (off, base, amp, freq) => Array.from({length: len}, (_, i) =>
      base + Math.sin((i + off) / freq) * amp + (Math.random() - 0.5) * amp * 0.18);
    return {
      ingest:  seed(tick * 0.6, 88,  18, 5.5),
      latency: seed(tick * 0.4, 18,   6, 7),
      mesh:    seed(tick * 0.3, 96,   1.6, 9),
    };
  }, [tick]);
  const last = (a) => a[a.length - 1];
  return (
    <div className="card spark-card">
      <div className="card__head" style={{ padding: 0, borderBottom: "none", marginBottom: 2 }}>
        <div className="card__title">Telemetry</div>
        <span className="muted mono" style={{ fontSize: 10 }}>60s window</span>
      </div>
      <div className="col" style={{ gap: 2 }}>
        <div className="lane">
          <span className="lane__name">ingest</span>
          <Sparkline points={series.ingest}  color="var(--info)"    height={22}/>
          <span className="lane__val mono">{last(series.ingest).toFixed(1)} <span className="muted">Mpps</span></span>
        </div>
        <div className="lane">
          <span className="lane__name">p99 lat</span>
          <Sparkline points={series.latency} color="var(--warning)" height={22}/>
          <span className="lane__val mono">{last(series.latency).toFixed(0)} <span className="muted">ms</span></span>
        </div>
        <div className="lane">
          <span className="lane__name">mesh</span>
          <Sparkline points={series.mesh}    color="var(--success)" height={22}/>
          <span className="lane__val mono">{last(series.mesh).toFixed(1)} <span className="muted">%</span></span>
        </div>
      </div>
    </div>
  );
}

// ─── Alarm fusion (compact, dashboard variant) ─────────────────────
function AlarmFusionCard({ tick }) {
  const wobble = (base, amp) => Math.max(0.05, Math.min(0.99, base + (Math.sin(tick * 0.4 + base * 10) * amp)));
  const signals = [
    ["camera",   wobble(0.92, 0.03), "var(--info)"],
    ["radar",    wobble(0.84, 0.04), "var(--info)"],
    ["RF",       wobble(0.66, 0.05), "var(--warning)"],
    ["acoustic", wobble(0.41, 0.06), "var(--muted-foreground)"],
    ["lidar",    wobble(0.78, 0.04), "var(--info)"],
  ];
  const fused = Math.min(0.97, 0.55 * signals[0][1] + 0.18 * signals[1][1] + 0.10 * signals[2][1] + 0.05 * signals[3][1] + 0.12 * signals[4][1]);
  return (
    <div className="card">
      <div className="card__head">
        <div className="card__title">Alarm fusion</div>
        <span className="pill pill--crit">CONFIRMED · {fused.toFixed(2)}</span>
      </div>
      <div className="fusion__rows">
        {signals.map(([name, conf, color]) => (
          <div className="fusion__row" key={name}>
            <span className="fusion__name">{name}</span>
            <div className="fusion__bar"><span style={{ width: `${conf*100}%`, background: color }}/></div>
            <span className="fusion__val">{conf.toFixed(2)}</span>
          </div>
        ))}
        <div className="fusion__row fusion__row--fused">
          <span className="fusion__name">fused</span>
          <div className="fusion__bar"><span style={{ width: `${fused*100}%` }}/></div>
          <span className="fusion__val">{fused.toFixed(2)}</span>
        </div>
      </div>
    </div>
  );
}

// ─── Drone fleet (compact) ─────────────────────────────────────────
function DroneFleetCard({ dispatched, flights, onClear }) {
  const fleet = [
    { id: "FR-AF-01", base: "Nakuru",    status: "ready",  battery: 92 },
    { id: "FR-AF-02", base: "Nakuru",    status: "ready",  battery: 76 },
    { id: "FR-AF-03", base: "Nakuru",    status: "ready",  battery: 64 },
    { id: "FR-EU-01", base: "Frankfurt", status: "ready",  battery: 88 },
    { id: "FR-AS-01", base: "Singapore", status: "ready",  battery: 71 },
  ];
  return (
    <div className="card">
      <div className="card__head">
        <div className="card__title">Flight units · {fleet.length} ready · {flights.length} in flight</div>
        <button className="icon-btn" onClick={onClear} title="Recall all"><Icon name="x" size={12}/></button>
      </div>
      <div className="card__body col" style={{ gap: 4 }}>
        {fleet.map(d => {
          const out = dispatched.includes(d.id);
          return (
            <div className="lane" key={d.id}>
              <span className="dot" style={{ color: out ? "var(--warning)" : "var(--success)" }}/>
              <span className="lane__name" style={{ minWidth: 100 }}>{d.id}</span>
              <span className="lane__task muted">{d.base}</span>
              <span className="lane__val muted">{d.battery}%</span>
              <span className="lane__val" style={{ minWidth: 70 }}>
                <span className={"pill " + (out ? "pill--warn" : "pill--ok")} style={{ fontSize: 8 }}>{out ? "IN FLIGHT" : "READY"}</span>
              </span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

Object.assign(window, { Sparkline, ModulesCard, InferenceCard, TelemetryCard, AlarmFusionCard, DroneFleetCard });
