/* Animated dev-loop terminal — the hero artifact.
   A continuous SDLC loop: ticket → plan → code → tests → review →
   staging deploy → log monitoring → bug found → fix → prod promote.
   Each step renders realistic dev tooling output (not raw JSON). */

const { useState, useEffect, useRef } = React;

/* ============================================================
   SCRIPT — the loop
   ============================================================ */
const SCRIPT = [
  { t: "input", text: "Ship feature FT-2487 — passwordless magic-link login" },

  { t: "think", text: "Reading ticket + acceptance criteria…" },
  { t: "tool", name: "load_ticket", args: "id=FT-2487", duration: 650, kind: "ticket",
    data: {
      id: "FT-2487", title: "Magic-link auth",
      owner: "growth", priority: "High", estimate: "3d",
      criteria: [
        "Email magic link · 15m TTL · single-use",
        "Rate-limit 3/hr per email address",
        "Fallback to SSO for enterprise tenants",
        "Audit log entry per attempt",
      ],
    },
  },

  { t: "think", text: "Drafting plan against current auth architecture…" },
  { t: "tool", name: "plan_changes", args: "scope=auth.passwordless", duration: 800, kind: "plan",
    data: {
      version: "v1", risk: "low", filesTouched: 11,
      steps: [
        ["MagicLink model + migration",   "db/schema.prisma"],
        ["Token gen + verify utility",    "src/auth/token.ts"],
        ["POST /api/auth/magic-link",     "src/api/auth/route.ts"],
        ["Email template + send",         "src/lib/email/magic.tsx"],
        ["Login UI · magic-link tab",     "src/app/login/page.tsx"],
        ["Rate limiter middleware",       "src/middleware/rate.ts"],
      ],
    },
  },

  { t: "tool", name: "write_code", args: "step=2  src/auth/token.ts", duration: 1100, kind: "code",
    data: {
      file: "src/auth/token.ts",
      lines: [
        'import { nanoid } from "nanoid";',
        'import { redis } from "@/lib/redis";',
        'import { sendMagicLinkEmail } from "@/lib/email/magic";',
        '',
        'export async function issueMagicLink(email: string) {',
        '  const token = nanoid(32);',
        '  await redis.set(`ml:${token}`, email, "EX", 900);',
        '  await sendMagicLinkEmail(email, token);',
        '  return { sent: true, ttl: 900 };',
        '}',
      ],
      footer: "+384 / −52 across 11 files · standards v3.2: passed",
    },
  },

  { t: "tool", name: "run_tests", args: "suite=unit+e2e", duration: 850, kind: "tests",
    data: {
      lines: [
        { lvl: "pass", text: "src/auth/__tests__/token.test.ts          (32 ms)" },
        { lvl: "pass", text: "src/api/auth/__tests__/magic-link.test.ts (118 ms)" },
        { lvl: "pass", text: "src/middleware/__tests__/rate.test.ts     (24 ms)" },
        { lvl: "pass", text: "e2e/login.spec.ts                         (4.4 s)" },
      ],
      summary: [
        ["Tests",    "99 passed, 99 total"],
        ["Coverage", "94.2 % statements · 91.0 % branches"],
        ["Time",     "5.62 s"],
      ],
    },
  },

  { t: "tool", name: "code_review", args: "diff=d_2487 standards=v3.2", duration: 650, kind: "review",
    data: {
      title: "PR #2487 · auto-review",
      lines: [
        { lvl: "ok",   name: "Standards check",        note: "passing"  },
        { lvl: "ok",   name: "Security scan",          note: "no findings" },
        { lvl: "ok",   name: "Coverage gate (≥ 90%)",  note: "94.2 %" },
        { lvl: "warn", name: "token.ts : 18",          note: "rate-limit at issue path" },
        { lvl: "warn", name: "rate.ts : 7",            note: "reuse shared limiter" },
      ],
      verdict: "9/10 · 0 blocking · 2 suggestions",
    },
  },

  { t: "decide", badge: "DEPLOYED → STAGING",
    text: "Live on staging.app — watching logs for anomalies." },

  { t: "tool", name: "monitor_logs", args: "env=staging window=10m", duration: 900, kind: "logs",
    data: {
      lines: [
        { ts: "17:42:01", env: "staging", msg: "POST /api/auth/magic-link · 201 · 12 ms" },
        { ts: "17:42:08", env: "staging", msg: "GET  /auth/verify?t=*** · 200 ·  8 ms" },
        { ts: "17:42:14", env: "staging", msg: "GET  /auth/verify?t=*** · 500 · 14 ms", lvl: "err" },
        { sub: "TypeError: Cannot read property 'email' of null", lvl: "err" },
        { sub: "at verifyToken (src/auth/verify.ts:42:18)",       lvl: "err-dim" },
        { ts: "17:42:14", env: "agent  ", msg: "alert.fire · error_spike · threshold=1", lvl: "alert" },
      ],
    },
  },

  { t: "think", text: "Anomaly detected. Tracing root cause…" },

  { t: "tool", name: "patch_and_verify", args: "err=e_88x  ticket=FT-2487", duration: 800, kind: "diff",
    data: {
      file: "src/auth/verify.ts", stat: "+3 / −1",
      lines: [
        { k: "hunk", text: "@@ -39,7 +39,9 @@ export async function verifyToken(t) {" },
        { k: "ctx",  text: "  const cached = await redis.get(`ml:${t}`);" },
        { k: "rem",  text: "  return { email: cached.email, ok: true };" },
        { k: "add",  text: '  if (!cached) return { ok: false, reason: "expired" };' },
        { k: "add",  text: "  return { email: cached, ok: true };" },
        { k: "ctx",  text: "}" },
      ],
      footer: "✓ token.test.ts · ✓ login.spec.ts · re-deployed",
    },
  },

  { t: "decide", badge: "PROMOTED → PROD",
    text: "Feature live · 12 m end-to-end. Pulling next ticket — loop closes." },
];

const AGENT_TYPE_MS = 16;
const STEP_GAP_MS = 320;

/* ============================================================
   Syntax highlighter — single-pass tokenizer
   Order in the alternation is precedence: comments / strings win
   over their inner content, so digits inside strings stay quoted.
   ============================================================ */
const TOKEN_RE = /(\/\/[^\n]*)|("[^"]*"|`[^`]*`|'[^']*')|\b(export|import|from|async|await|function|const|let|var|return|if|else|true|false|null|undefined|new|class|extends|throw|try|catch|for|of|in)\b|\b(string|number|boolean|void|any)\b|\b(\d+(?:\.\d+)?)\b|\b([a-zA-Z_$][\w$]*)(?=\s*\()/g;

function tokenize(line) {
  const out = [];
  let last = 0;
  let key = 0;
  let m;
  TOKEN_RE.lastIndex = 0;
  while ((m = TOKEN_RE.exec(line)) !== null) {
    if (m.index > last) {
      out.push({ k: key++, cls: "", v: line.slice(last, m.index) });
    }
    let cls = "";
    if (m[1] !== undefined)      cls = "c-cm";
    else if (m[2] !== undefined) cls = "c-s";
    else if (m[3] !== undefined) cls = "c-k";
    else if (m[4] !== undefined) cls = "c-t";
    else if (m[5] !== undefined) cls = "c-n";
    else if (m[6] !== undefined) cls = "c-fn";
    out.push({ k: key++, cls, v: m[0] });
    last = TOKEN_RE.lastIndex;
  }
  if (last < line.length) {
    out.push({ k: key++, cls: "", v: line.slice(last) });
  }
  return out;
}

/* ============================================================
   Per-kind result renderers
   ============================================================ */
function TicketCard({ data }) {
  return (
    <div className="rc">
      <div className="rc-head">
        <span className="rc-tag">{data.id}</span>
        <span className="rc-title">{data.title}</span>
        <span className="rc-meta">{data.priority} · {data.owner} · est {data.estimate}</span>
      </div>
      <ul className="rc-list">
        {data.criteria.map((c, i) => (
          <li key={i}><span className="li-ico">✓</span><span>{c}</span></li>
        ))}
      </ul>
    </div>
  );
}

function PlanList({ data }) {
  return (
    <div className="rc">
      <div className="rc-head">
        <span className="rc-tag">PLAN {data.version}</span>
        <span className="rc-title">{data.steps.length} steps · {data.filesTouched} files</span>
        <span className="rc-meta">risk: {data.risk}</span>
      </div>
      <ul className="rc-list rc-plan">
        {data.steps.map(([name, file], i) => (
          <li key={i}>
            <span className="li-num">{String(i + 1).padStart(2, "0")}</span>
            <span className="li-name">{name}</span>
            <span className="li-file">{file}</span>
          </li>
        ))}
      </ul>
    </div>
  );
}

function CodeBlock({ data }) {
  return (
    <div className="rc rc-code">
      <div className="rc-head">
        <span className="rc-tag">FILE</span>
        <span className="rc-title">{data.file}</span>
      </div>
      <pre className="code">
        {data.lines.map((line, i) => (
          <div className="code-line" key={i}>
            <span className="ln">{i + 1}</span>
            <span className="src">
              {line === ""
                ? "\u00A0"
                : tokenize(line).map((tk) => (
                    <span key={tk.k} className={tk.cls}>{tk.v}</span>
                  ))}
            </span>
          </div>
        ))}
      </pre>
      <div className="rc-foot">{data.footer}</div>
    </div>
  );
}

function TestOutput({ data }) {
  return (
    <div className="rc">
      <div className="rc-head">
        <span className="rc-tag">TESTS</span>
        <span className="rc-title">vitest · 4 suites</span>
      </div>
      <div className="rc-mono">
        {data.lines.map((l, i) => (
          <div key={i} className={`test-line lvl-${l.lvl}`}>
            <span className="test-mark">{l.lvl === "pass" ? "PASS" : l.lvl.toUpperCase()}</span>
            <span className="test-text">{l.text}</span>
          </div>
        ))}
      </div>
      <div className="rc-grid">
        {data.summary.map(([k, v], i) => (
          <div key={i} className="kv-row"><span className="k">{k}</span><span className="v">{v}</span></div>
        ))}
      </div>
    </div>
  );
}

function ReviewOutput({ data }) {
  return (
    <div className="rc">
      <div className="rc-head">
        <span className="rc-tag">REVIEW</span>
        <span className="rc-title">{data.title}</span>
      </div>
      <ul className="rc-list rc-review">
        {data.lines.map((l, i) => (
          <li key={i}>
            <span className={`rv-mark mk-${l.lvl}`}>{l.lvl === "ok" ? "✓" : "!"}</span>
            <span className="rv-name">{l.name}</span>
            <span className="rv-note">{l.note}</span>
          </li>
        ))}
      </ul>
      <div className="rc-foot accent">{data.verdict}</div>
    </div>
  );
}

function LogTail({ data }) {
  return (
    <div className="rc">
      <div className="rc-head">
        <span className="rc-tag">LOGS</span>
        <span className="rc-title">tail · staging · 10 m window</span>
      </div>
      <div className="rc-mono log-tail">
        {data.lines.map((l, i) => {
          if (l.sub) return <div key={i} className={`log-sub ${l.lvl || ""}`}>↳ {l.sub}</div>;
          return (
            <div key={i} className={`log-line ${l.lvl || ""}`}>
              <span className="ts">{l.ts}</span>
              <span className="env">[{l.env}]</span>
              <span className="msg">{l.msg}</span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function DiffBlock({ data }) {
  return (
    <div className="rc">
      <div className="rc-head">
        <span className="rc-tag">DIFF</span>
        <span className="rc-title">{data.file}</span>
        <span className="rc-meta">{data.stat}</span>
      </div>
      <pre className="code diff">
        {data.lines.map((l, i) => (
          <div key={i} className={`diff-line ${l.k}`}>
            <span className="sigil">
              {l.k === "add" ? "+" : l.k === "rem" ? "−" : l.k === "hunk" ? "@" : " "}
            </span>
            <span className="src">{l.text}</span>
          </div>
        ))}
      </pre>
      <div className="rc-foot accent">{data.footer}</div>
    </div>
  );
}

const RENDERERS = {
  ticket: TicketCard,
  plan:   PlanList,
  code:   CodeBlock,
  tests:  TestOutput,
  review: ReviewOutput,
  logs:   LogTail,
  diff:   DiffBlock,
};

/* ============================================================
   Terminal chrome
   ============================================================ */
function TerminalChrome({ children, kbd, status }) {
  return (
    <div className="term">
      <div className="term-bar">
        <div className="term-dots">
          <span className="d r" />
          <span className="d y" />
          <span className="d g" />
        </div>
        <div className="term-title">
          <span className="path">~/framework</span>
          <span className="sep">/</span>
          <span className="cmd">agent --ship FT-2487</span>
        </div>
        <div className="term-status">
          <span className="led" />
          {status}
        </div>
      </div>
      <div className="term-body">{children}</div>
      <div className="term-foot">
        <span className="hint"><kbd>↵</kbd> {kbd}</span>
        <span className="hint right">
          <span className="lat">23 ms</span> · <span className="mod">plan · code · test · ship · monitor</span>
        </span>
      </div>
    </div>
  );
}

/* ============================================================
   Typewriter
   ============================================================ */
function Typewriter({ text, speed = AGENT_TYPE_MS, onDone, className }) {
  const [out, setOut] = useState("");
  const idx = useRef(0);
  useEffect(() => {
    setOut("");
    idx.current = 0;
    let cancelled = false;
    function tick() {
      if (cancelled) return;
      if (idx.current >= text.length) { onDone && onDone(); return; }
      idx.current += 1;
      setOut(text.slice(0, idx.current));
      setTimeout(tick, speed + (Math.random() * 16 - 8));
    }
    tick();
    return () => { cancelled = true; };
  }, [text]);
  return <span className={className}>{out}</span>;
}

/* ============================================================
   Tool block
   ============================================================ */
function ToolCallBlock({ step, onDone }) {
  const [phase, setPhase] = useState("calling");
  useEffect(() => {
    let alive = true;
    const t1 = setTimeout(() => alive && setPhase("running"), 280);
    const t2 = setTimeout(() => {
      if (!alive) return;
      setPhase("done");
      onDone && onDone();
    }, 280 + step.duration);
    return () => { alive = false; clearTimeout(t1); clearTimeout(t2); };
  }, []);

  const Renderer = RENDERERS[step.kind];

  return (
    <div className="tool">
      <div className="tool-head">
        <span className="t-icn">
          {phase === "done" ? "✓" : <span className="spin" />}
        </span>
        <span className="t-name">{step.name}</span>
        <span className="t-arg">({step.args})</span>
        <span className={`t-state s-${phase}`}>
          {phase === "calling" ? "calling" : phase === "running" ? "running" : "ok"}
        </span>
      </div>
      {phase === "done" && Renderer && (
        <div className="tool-result">
          <Renderer data={step.data} />
        </div>
      )}
    </div>
  );
}

/* ============================================================
   HeroAgent root
   ============================================================ */
function HeroAgent() {
  const [step, setStep] = useState(0);
  const [tick, setTick] = useState(0);
  const logRef = useRef(null);

  // auto-scroll to bottom on every render
  useEffect(() => {
    const el = logRef.current;
    if (!el) return;
    const id = setTimeout(() => {
      el.scrollTo({ top: el.scrollHeight, behavior: "smooth" });
    }, 80);
    return () => clearTimeout(id);
  });

  const nextStep = () => {
    setTimeout(() => {
      setStep(s => {
        if (s + 1 >= SCRIPT.length) {
          setTimeout(() => {
            setStep(0);
            setTick(t => t + 1);
          }, 4800);
          return s + 1;
        }
        return s + 1;
      });
    }, STEP_GAP_MS);
  };

  const visible = SCRIPT.slice(0, step + 1);

  // status word changes as the loop progresses
  const statusFor = (s) => {
    if (s >= SCRIPT.length - 1) return "shipped";
    if (s >= 11) return "patching";
    if (s >= 8)  return "monitoring";
    if (s >= 4)  return "building";
    return "planning";
  };

  return (
    <TerminalChrome kbd="run · ⌘K command" status={statusFor(step)}>
      <div className="agent-log" ref={logRef} key={tick}>
        {visible.map((s, i) => {
          const isLast = i === visible.length - 1;
          const advance = isLast ? nextStep : undefined;
          if (s.t === "input") {
            return (
              <div className="row r-input" key={`${tick}-${i}`}>
                <span className="prompt">›</span>
                <Typewriter text={s.text} className="user-text" onDone={advance} />
                {isLast && <span className="caret" />}
              </div>
            );
          }
          if (s.t === "think") {
            return (
              <div className="row r-think" key={`${tick}-${i}`}>
                <span className="ico">⌁</span>
                <Typewriter text={s.text} className="think-text" speed={14} onDone={advance} />
              </div>
            );
          }
          if (s.t === "tool") {
            return <ToolCallBlock step={s} key={`${tick}-${i}`} onDone={advance} />;
          }
          if (s.t === "decide") {
            return (
              <div className="row r-decide" key={`${tick}-${i}`}>
                <div className="d-badge">{s.badge}</div>
                <Typewriter text={s.text} className="d-text" speed={18} onDone={advance} />
              </div>
            );
          }
          return null;
        })}
      </div>
    </TerminalChrome>
  );
}

window.HeroAgent = HeroAgent;
