// lattice-data.jsx — Shared data. Real lat/lng coords for MapLibre.

// 19 edge nodes with real geography.
const NODES = [
  { id:"LAT-NA-01", city:"San Francisco", region:"NA", country:"USA",     lng:-122.42, lat: 37.77, type:"fusion",    status:"ok",   cpu:42, mem:61, ingest:18.4 },
  { id:"LAT-NA-02", city:"New York",      region:"NA", country:"USA",     lng: -74.00, lat: 40.71, type:"fusion",    status:"ok",   cpu:38, mem:55, ingest:21.7 },
  { id:"LAT-NA-03", city:"Seattle",       region:"NA", country:"USA",     lng:-122.33, lat: 47.61, type:"edge",      status:"ok",   cpu:22, mem:33, ingest: 6.1 },
  { id:"LAT-NA-04", city:"Mexico City",   region:"NA", country:"Mexico",  lng: -99.13, lat: 19.43, type:"edge",      status:"warn", cpu:78, mem:71, ingest:11.3 },
  { id:"LAT-SA-01", city:"São Paulo",     region:"SA", country:"Brazil",  lng: -46.63, lat:-23.55, type:"fusion",    status:"ok",   cpu:51, mem:64, ingest:17.0 },
  { id:"LAT-SA-02", city:"Bogotá",        region:"SA", country:"Colombia",lng: -74.07, lat:  4.71, type:"sensor",    status:"warn", cpu:18, mem:24, ingest: 2.9 },
  { id:"LAT-EU-01", city:"London",        region:"EU", country:"UK",      lng:  -0.13, lat: 51.51, type:"fusion",    status:"ok",   cpu:44, mem:58, ingest:23.8 },
  { id:"LAT-EU-02", city:"Frankfurt",     region:"EU", country:"Germany", lng:   8.68, lat: 50.11, type:"inference", status:"ok",   cpu:71, mem:69, ingest:14.2 },
  { id:"LAT-EU-03", city:"Madrid",        region:"EU", country:"Spain",   lng:  -3.70, lat: 40.42, type:"edge",      status:"ok",   cpu:33, mem:47, ingest: 8.9 },
  { id:"LAT-AF-01", city:"Lagos",         region:"AF", country:"Nigeria", lng:   3.38, lat:  6.52, type:"sensor",    status:"ok",   cpu:14, mem:21, ingest: 1.7 },
  { id:"LAT-AF-02", city:"Nairobi",       region:"AF", country:"Kenya",   lng:  36.82, lat: -1.29, type:"sensor",    status:"crit", cpu:91, mem:88, ingest: 0.4 },
  { id:"LAT-AF-03", city:"Johannesburg",  region:"AF", country:"S.Africa",lng:  28.04, lat:-26.20, type:"edge",      status:"ok",   cpu:29, mem:40, ingest: 5.5 },
  { id:"LAT-ME-01", city:"Dubai",         region:"ME", country:"UAE",     lng:  55.27, lat: 25.20, type:"fusion",    status:"warn", cpu:82, mem:74, ingest:19.6 },
  { id:"LAT-AS-01", city:"Mumbai",        region:"AS", country:"India",   lng:  72.88, lat: 19.08, type:"edge",      status:"ok",   cpu:55, mem:62, ingest:12.4 },
  { id:"LAT-AS-02", city:"Singapore",     region:"AS", country:"SG",      lng: 103.82, lat:  1.35, type:"fusion",    status:"ok",   cpu:48, mem:60, ingest:28.1 },
  { id:"LAT-AS-03", city:"Tokyo",         region:"AS", country:"Japan",   lng: 139.69, lat: 35.69, type:"fusion",    status:"ok",   cpu:39, mem:54, ingest:24.5 },
  { id:"LAT-AS-04", city:"Seoul",         region:"AS", country:"S.Korea", lng: 127.00, lat: 37.57, type:"inference", status:"ok",   cpu:66, mem:71, ingest: 9.7 },
  { id:"LAT-OC-01", city:"Sydney",        region:"OC", country:"Australia",lng:151.21, lat:-33.87, type:"fusion",    status:"ok",   cpu:31, mem:46, ingest:13.2 },
  { id:"LAT-OC-02", city:"Perth",         region:"OC", country:"Australia",lng:115.86, lat:-31.95, type:"edge",      status:"ok",   cpu:24, mem:35, ingest: 4.6 },
];

const REGIONS = {
  "Global":      { center: [10, 25],   zoom: 1.4 },
  "Americas":    { center: [-80, 20],  zoom: 2.4 },
  "EMEA":        { center: [25, 30],   zoom: 2.6 },
  "APAC":        { center: [120, 10],  zoom: 2.4 },
  "Pacific Rim": { center: [180, 5],   zoom: 2.0 },
};

const MODULES = [
  { name: "detect-anomaly.wasm",     deployed: 14, total: 19, rate: "18.4 Mpps", load: 0.74, status: "ok" },
  { name: "geo-fence-eval.wasm",     deployed: 19, total: 19, rate: "42.1 Mpps", load: 0.91, status: "warn" },
  { name: "pose-fusion.wasm",        deployed: 11, total: 19, rate:  "6.2 Mpps", load: 0.32, status: "ok" },
  { name: "mesh-route-quic.wasm",    deployed: 19, total: 19, rate:"130.6 Mpps", load: 0.96, status: "warn" },
  { name: "pii-redact.wasm",         deployed:  8, total: 19, rate:  "1.1 Mpps", load: 0.18, status: "ok" },
  { name: "threat-classify-v3.wasm", deployed: 14, total: 19, rate:  "9.8 Mpps", load: 0.55, status: "ok" },
];

const MODELS = [
  { id: "chronos-2.6b",     task: "temporal anomaly",     hosts: 14, p99: "12 ms", fps: "4.2k/s",  size: "2.6 GB", tone: "ok",   build: "20260311" },
  { id: "gridseg-v4",       task: "spatial segmentation", hosts: 11, p99: "28 ms", fps: "1.1k/s",  size: "780 MB", tone: "ok",   build: "20260408" },
  { id: "intent-flow-1.4",  task: "behavioral fusion",    hosts:  8, p99: "41 ms", fps: "640/s",   size: "1.4 GB", tone: "warn", build: "20260501" },
  { id: "lidar-ct-mini",    task: "object localization",  hosts: 19, p99:  "9 ms", fps: "8.0k/s",  size: "320 MB", tone: "ok",   build: "20260512" },
];

const EVENT_TEMPLATES = [
  { sev: "crit", t: "anomaly",   title: "thermal divergence",   msg: (n) => `node ${n} drift +3.4σ over baseline; auto-isolating` },
  { sev: "warn", t: "throttle",  title: "ingest throttled",     msg: (n) => `node ${n} q-depth > 4096 packets; backpressure applied` },
  { sev: "info", t: "model",     title: "model promoted",       msg: ()  => `gridseg-v4 → canary 25% on EU lattice` },
  { sev: "info", t: "deploy",    title: "wasm deploy",          msg: (n) => `pose-fusion.wasm v1.4 → ${n} (3 hosts)` },
  { sev: "info", t: "telemetry", title: "rate observed",        msg: ()  => `lattice ingest crossed 120 Mpps · sustained 90s` },
  { sev: "info", t: "mesh",      title: "lease rebalanced",     msg: (n) => `zenoh subscriber migrated APAC → ${n}` },
  { sev: "warn", t: "security",  title: "key rotation pending", msg: (n) => `node ${n} hsm key age 89d, schedule rotation` },
  { sev: "crit", t: "security",  title: "geofence breach",      msg: (n) => `unauthorized device entered polygon GF-417 near ${n}` },
  { sev: "info", t: "inference", title: "p99 normalized",       msg: ()  => `chronos-2.6b · APAC p99 returned to 12 ms` },
  { sev: "info", t: "telemetry", title: "epoch advanced",       msg: ()  => `clock epoch 0x4f2 · drift 0.8 ppm across mesh` },
];

const formatTime = (date) => date.toTimeString().slice(0,8);

function buildEvent(now) {
  const tpl = EVENT_TEMPLATES[Math.floor(Math.random() * EVENT_TEMPLATES.length)];
  const node = NODES[Math.floor(Math.random() * NODES.length)];
  return {
    id: Math.random().toString(36).slice(2, 9),
    time: formatTime(now),
    ts: now.getTime(),
    sev: tpl.sev,
    type: tpl.t,
    title: tpl.title,
    msg: tpl.msg(node.id),
    node: node.id,
    new: true,
  };
}

function seedEvents() {
  const out = [];
  const base = new Date(Date.now() - 60_000);
  for (let i = 0; i < 14; i++) {
    out.push({ ...buildEvent(new Date(base.getTime() + i * 5000)), new: false });
  }
  return out.reverse();
}

// Status helpers (one source of truth).
const statusColor = (s) =>
  s === "crit" ? "var(--destructive)" :
  s === "warn" ? "var(--warning)" :
                 "var(--info)";
const statusPill = (s) =>
  s === "crit" ? "pill--crit" :
  s === "warn" ? "pill--warn" :
                 "pill--ok";

// Mesh edges by lng/lat distance.
const lngLatDist = (a, b) => {
  const toRad = d => d * Math.PI / 180;
  const dLat = toRad(b.lat - a.lat), dLng = toRad(b.lng - a.lng);
  const x = dLng * Math.cos(toRad((a.lat + b.lat) / 2));
  return Math.sqrt(x*x + dLat*dLat) * 6371; // km
};

function computeMesh(nodes) {
  const edges = new Set();
  for (const a of nodes) {
    const others = nodes.filter(n => n.id !== a.id)
      .map(n => ({ n, d: lngLatDist(a, n) }))
      .filter(o => o.d < 11000) // ~11,000 km neighbor radius
      .sort((p, q) => p.d - q.d).slice(0, 3);
    for (const { n: b } of others) {
      const key = [a.id, b.id].sort().join("|");
      edges.add(key);
    }
  }
  return [...edges].map(k => {
    const [aId, bId] = k.split("|");
    return [nodes.find(n => n.id === aId), nodes.find(n => n.id === bId)];
  });
}

// Inline-mask icon helper.
function Icon({ name, size = 14, style = {} }) {
  const src = (window.__resources && window.__resources["icon-" + name]) || `../../assets/icons/${name}.svg`;
  return (
    <span role="img" aria-label={name} style={{
      display: "inline-block", width: size, height: size,
      background: "currentColor",
      WebkitMask: `url(${src}) center / contain no-repeat`,
              mask: `url(${src}) center / contain no-repeat`,
      flexShrink: 0, ...style,
    }}/>
  );
}

const ChromaticMark = ({ size = 18 }) => (
  <svg width={size} height={size} viewBox="0 0 32 32" fill="none" stroke="currentColor" strokeLinecap="round">
    <circle cx="16" cy="16" r="13" strokeWidth="1.5" opacity="0.35"/>
    <path d="M27 9.5A13 13 0 1 0 27 22.5" strokeWidth="1.5" opacity="0.7"/>
    <path d="M23 12A8 8 0 1 0 23 20" strokeWidth="2"/>
  </svg>
);

Object.assign(window, { NODES, REGIONS, MODULES, MODELS, EVENT_TEMPLATES, buildEvent, seedEvents, formatTime, statusColor, statusPill, computeMesh, lngLatDist, Icon, ChromaticMark });
