/* global React */
// Live routing visualization. Cycles through a small scenario loop:
// 1) query types in, 2) providers probe, 3) one wins, 4) decision summary,
// 5) log stream ticks, 6) reset for next query.

const QUERIES = [
  {
    capability: "search",
    text: "GLP-1 cardiovascular outcomes",
    providers: [
      { id: "exa",    name: "Exa",    cost: 3.0, p50: 640, q: 94 },
      { id: "tavily", name: "Tavily", cost: 2.5, p50: 710, q: 88 },
      { id: "brave",  name: "Brave",  cost: 1.8, p50: 480, q: 79 },
      { id: "linkup", name: "Linkup", cost: 2.2, p50: 820, q: 83 },
    ],
    winner: "exa",
    reason: "highest benchmark score for medical-literature class"
  },
  {
    capability: "crawl",
    text: "cms.gov/medicare/physician-fee-schedule",
    providers: [
      { id: "firecrawl",   name: "Firecrawl",   cost: 2.0, p50: 1100, q: 91 },
      { id: "apify",       name: "Apify",       cost: 2.4, p50: 1680, q: 86 },
      { id: "browserbase", name: "Browserbase", cost: 4.1, p50: 2300, q: 93 },
      { id: "direct",      name: "Direct HTTP", cost: 0.2, p50: 340,  q: 62 },
    ],
    winner: "firecrawl",
    reason: "structured markdown output beat quality floor at 1/2 cost of Browserbase"
  },
  {
    capability: "privacy",
    text: "patientNote (1.2 kB, contains PHI)",
    providers: [
      { id: "presidio", name: "MS Presidio",    cost: 0.0, p50: 90,  q: 89 },
      { id: "oai",      name: "OpenAI Filter",  cost: 0.8, p50: 140, q: 92 },
      { id: "aws",      name: "AWS Comprehend", cost: 1.1, p50: 220, q: 87 },
      { id: "azure",    name: "Azure TA",       cost: 1.0, p50: 260, q: 84 },
    ],
    winner: "oai",
    reason: "vertical: healthcare, highest PHI recall on clinical corpus"
  },
];

const DURATIONS = {
  type:   1400,
  probe:  1500,
  select: 400,
  dwell:  2400,
  reset:  500,
};

function useRoutingScenario() {
  const [qIdx, setQIdx] = React.useState(0);
  const [phase, setPhase] = React.useState("type"); // type → probe → select → dwell → reset
  const [typed, setTyped] = React.useState("");
  const [probed, setProbed] = React.useState({}); // providerId -> "probing"|"done"|"won"
  const [log, setLog] = React.useState([]);

  const q = QUERIES[qIdx];

  const addLog = React.useCallback((lv, msg) => {
    const t = new Date();
    const tt = `${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}:${String(t.getSeconds()).padStart(2,"0")}`;
    setLog(prev => {
      const next = [...prev, { id: prev.length + Math.random(), t: tt, lv, msg }];
      return next.slice(-10);
    });
  }, []);

  // Drive scenario
  React.useEffect(() => {
    let timers = [];
    if (phase === "type") {
      setTyped("");
      setProbed({});
      const chars = q.text.split("");
      chars.forEach((_, i) => {
        timers.push(setTimeout(() => setTyped(q.text.slice(0, i + 1)), (DURATIONS.type / chars.length) * i));
      });
      timers.push(setTimeout(() => {
        addLog("info", <>POST <span className="b">/v1/{q.capability}</span> <span className="dim">routed by</span> <span className="b">balanced</span></>);
        setPhase("probe");
      }, DURATIONS.type + 120));
    } else if (phase === "probe") {
      // Sequentially mark providers as probing then done
      q.providers.forEach((p, i) => {
        const start = (DURATIONS.probe / q.providers.length) * i;
        timers.push(setTimeout(() => {
          setProbed(prev => ({ ...prev, [p.id]: "probing" }));
          addLog("probe", <>probe <span className="b">{p.name}</span> <span className="dim">cost</span> <span className="b">${p.cost.toFixed(1)}/1K</span> <span className="dim">p50</span> <span className="b">{p.p50}ms</span> <span className="dim">q</span> <span className="b">{p.q}</span></>);
        }, start));
        timers.push(setTimeout(() => {
          setProbed(prev => ({ ...prev, [p.id]: "done" }));
        }, start + 380));
      });
      timers.push(setTimeout(() => setPhase("select"), DURATIONS.probe + 250));
    } else if (phase === "select") {
      setProbed(prev => {
        const next = { ...prev };
        q.providers.forEach(p => {
          next[p.id] = p.id === q.winner ? "won" : "done";
        });
        return next;
      });
      const w = q.providers.find(p => p.id === q.winner);
      addLog("win", <>route <span className="b">{w.name}</span> <span className="dim">,  {q.reason}</span></>);
      addLog("ok", <>200 <span className="dim">· response in</span> <span className="b">{w.p50}ms</span></>);
      addLog("aud", <>audit <span className="dim">sha256:</span> <span className="b">{randHash()}</span> <span className="dim">signed</span></>);
      timers.push(setTimeout(() => setPhase("dwell"), DURATIONS.select));
    } else if (phase === "dwell") {
      timers.push(setTimeout(() => setPhase("reset"), DURATIONS.dwell));
    } else if (phase === "reset") {
      timers.push(setTimeout(() => {
        setQIdx(i => (i + 1) % QUERIES.length);
        setPhase("type");
      }, DURATIONS.reset));
    }
    return () => timers.forEach(clearTimeout);
  }, [phase, qIdx, q, addLog]);

  return { q, typed, probed, phase, log };
}

function randHash() {
  const chars = "0123456789abcdef";
  let out = "";
  for (let i = 0; i < 8; i++) out += chars[Math.floor(Math.random() * 16)];
  return out;
}

function RoutingViz() {
  const { q, typed, probed, phase, log } = useRoutingScenario();
  const winner = q.providers.find(p => p.id === q.winner);
  const logRef = React.useRef(null);

  React.useEffect(() => {
    if (logRef.current) {
      logRef.current.scrollTop = logRef.current.scrollHeight;
    }
  }, [log]);

  return (
    <div className="viz-shell" aria-label="Live routing visualization">
      <div className="viz-header">
        <span className="dots" aria-hidden="true"><span /><span /><span /></span>
        <span className="title">synapse.{q.capability}(), live router</span>
        <span className="status"><span className="dot" /> routing</span>
      </div>
      <div className="viz-body">
        <div className="viz-left">
          <div>
            <div className="viz-label">Query</div>
            <div className="query-bar" style={{marginTop: 8}}>
              <span className="caret">›</span>
              <span className="typed">{typed}</span>
              {phase === "type" && <span className="cursor" aria-hidden="true" />}
            </div>
          </div>
          <div>
            <div className="viz-label">Candidate providers</div>
            <div className="providers" style={{marginTop: 8}}>
              {q.providers.map(p => {
                const st = probed[p.id] || "idle";
                return (
                  <div key={p.id} className="provider" data-state={st}>
                    <span className="bullet" aria-hidden="true" />
                    <div>
                      <div className="name">{p.name}</div>
                      <div className="stats">
                        <span>${p.cost.toFixed(1)}<b>/1K</b></span>
                        <span>{p.p50}<b>ms</b></span>
                        <span>q<b>{p.q}</b></span>
                      </div>
                    </div>
                    <span className="winner-tag">routed</span>
                  </div>
                );
              })}
            </div>
          </div>
          <div className="decision-summary">
            {phase === "type" ? (
              <>
                <span className="k">awaiting query…</span>
              </>
            ) : phase === "probe" ? (
              <>
                <span className="k">probing</span> <span className="v">{q.providers.length} providers</span> <span className="k">across</span> <span className="v">cost · p50 · quality</span> <span className="k">…</span>
              </>
            ) : (
              <>
                <span className="k">→ routed to</span> <span className="accent">{winner.name}</span>{" "}
                <span className="k">· mode</span> <span className="v">balanced</span>{" "}
                <span className="k">· q-floor</span> <span className="v">80</span>
                <br />
                <span className="k">why:</span> <span className="v">{q.reason}</span>
              </>
            )}
          </div>
        </div>
        <div className="viz-right">
          <div className="log-header">
            <span>Decision log · {q.capability}()</span>
            <span className="controls">
              <button className="active">live</button>
              <button>audit</button>
              <button>trace</button>
            </span>
          </div>
          <div className="log-stream" ref={logRef}>
            {log.map(l => (
              <div className="log-line show" key={l.id}>
                <span className="t">{l.t}</span>
                <span className={"lv " + l.lv}>{l.lv}</span>
                <span className="msg">{l.msg}</span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { RoutingViz });
