/* global React */
const { useState: useStateTS, useMemo: useMemoTS } = React;

const TOOLS = [
  {
    name: "search_web",
    desc: "Run a Google-style web search.",
    schema: {
      query: { type: "string", desc: "Natural-language search query." },
      top_k: { type: "integer", desc: "Number of results.", default: 5 },
    },
    sample: { query: "latest GPT-5 release date", top_k: 3 },
    result: [
      { title: "OpenAI announces GPT-5 — official blog", url: "openai.com/blog/gpt-5", snippet: "Released on March 14, 2026, focusing on..." },
      { title: "GPT-5 capabilities deep-dive — TechReview", url: "techreview.com/gpt5", snippet: "Independent benchmarks across reasoning..." },
      { title: "What's new in GPT-5 — Hacker News", url: "news.yc/item?id=...", snippet: "Discussion thread with first impressions..." },
    ],
  },
  {
    name: "get_weather",
    desc: "Current weather for a city.",
    schema: {
      city: { type: "string", desc: "City name, e.g. 'Tokyo'." },
      units: { type: "string", desc: "'metric' or 'imperial'.", default: "metric" },
    },
    sample: { city: "Bengaluru", units: "metric" },
    result: { city: "Bengaluru", temp_c: 27.4, condition: "Partly cloudy", humidity: 62, wind_kph: 9.3 },
  },
  {
    name: "sql_query",
    desc: "Run a read-only SQL query against the analytics DB.",
    schema: {
      query: { type: "string", desc: "A SELECT statement; no DDL/DML." },
    },
    sample: { query: "SELECT user_id, COUNT(*) AS sessions FROM events WHERE day='2026-04-01' GROUP BY 1 ORDER BY 2 DESC LIMIT 5;" },
    result: [
      { user_id: "u_8821", sessions: 142 },
      { user_id: "u_3019", sessions: 118 },
      { user_id: "u_7740", sessions: 97 },
      { user_id: "u_2218", sessions: 84 },
      { user_id: "u_5503", sessions: 73 },
    ],
  },
  {
    name: "send_email",
    desc: "Send a transactional email via SES.",
    schema: {
      to: { type: "string", desc: "Recipient address." },
      subject: { type: "string", desc: "Subject line." },
      body: { type: "string", desc: "Plain-text body." },
    },
    sample: { to: "ana@acme.com", subject: "Sales report ready", body: "Hi Ana,\n\nThe Q1 sales report is attached..." },
    result: { id: "msg_4f9c12", status: "sent", queued_at: "2026-04-28T09:14:21Z" },
  },
  {
    name: "calculator",
    desc: "Evaluate a math expression.",
    schema: { expr: { type: "string", desc: "Arithmetic expression like '2*(3+4)'." } },
    sample: { expr: "(184 * 0.18) + 184" },
    result: { value: 217.12 },
  },
];

function ToolSimulator() {
  const [active, setActive] = useStateTS(0);
  const [phase, setPhase] = useStateTS(0); // 0=schema, 1=args, 2=result
  const tool = TOOLS[active];

  const phases = ["schema", "args", "result"];

  const next = () => setPhase(p => Math.min(2, p + 1));
  const prev = () => setPhase(p => Math.max(0, p - 1));

  return (
    <Diagram
      title="Tool Call Simulator"
      controls={
        <>
          <button className="btn ghost" onClick={prev} disabled={phase === 0}>‹ Prev</button>
          <button className="btn primary" onClick={() => setPhase((phase + 1) % 3)}>
            {phase === 0 ? "Show LLM args →" : phase === 1 ? "Run tool →" : "↻ Reset"}
          </button>
          <button className="btn ghost" onClick={next} disabled={phase === 2}>Next ›</button>
        </>
      }
    >
      <div className="tool-sim">
        <div className="tool-sim-list">
          {TOOLS.map((t, i) => (
            <div key={t.name}
                 className={`tool-card ${active === i ? "active" : ""}`}
                 onClick={() => { setActive(i); setPhase(0); }}>
              <div className="tname">{t.name}</div>
              <div className="tdesc">{t.desc}</div>
            </div>
          ))}
        </div>
        <div className="tool-detail">
          <div style={{ display: "flex", gap: 8, marginBottom: 12 }}>
            {phases.map((p, i) => (
              <span key={p} className={`tag ${i === phase ? "electric" : ""}`}
                    style={{ opacity: i <= phase ? 1 : 0.5 }}>
                {i + 1}. {p}
              </span>
            ))}
          </div>

          {phase === 0 && (
            <>
              <h4 className="mini-title" style={{ margin: "0 0 6px" }}>JSON Schema · what the LLM sees</h4>
              <p style={{ fontSize: 13.5, color: "var(--ink-3)", margin: "0 0 8px" }}>
                LangChain converts your Python function (or <code>BaseTool</code>) into this OpenAI-style schema and ships it as part of the prompt.
              </p>
              <CodeBlock file={`${tool.name}.schema.json`} lang="json">
{JSON.stringify({
  type: "function",
  function: {
    name: tool.name,
    description: tool.desc,
    parameters: {
      type: "object",
      properties: Object.fromEntries(
        Object.entries(tool.schema).map(([k, v]) => [k, { type: v.type, description: v.desc, ...(v.default !== undefined ? { default: v.default } : {}) }])
      ),
      required: Object.keys(tool.schema).filter(k => tool.schema[k].default === undefined),
    }
  }
}, null, 2)}
              </CodeBlock>
            </>
          )}

          {phase === 1 && (
            <>
              <h4 className="mini-title" style={{ margin: "0 0 6px" }}>The LLM's tool_call · structured output</h4>
              <p style={{ fontSize: 13.5, color: "var(--ink-3)", margin: "0 0 8px" }}>
                The model emits a <code>tool_calls</code> field — JSON arguments matching the schema. LangChain validates them with Pydantic before invoking the tool.
              </p>
              <CodeBlock file="ai_message.json" lang="json">
{JSON.stringify({
  role: "assistant",
  content: "",
  tool_calls: [{
    id: "call_8c1f",
    type: "function",
    function: {
      name: tool.name,
      arguments: JSON.stringify(tool.sample),
    }
  }]
}, null, 2)}
              </CodeBlock>
            </>
          )}

          {phase === 2 && (
            <>
              <h4 className="mini-title" style={{ margin: "0 0 6px" }}>Tool result · fed back as ToolMessage</h4>
              <p style={{ fontSize: 13.5, color: "var(--ink-3)", margin: "0 0 8px" }}>
                The runtime executes the function, captures the return value, and appends it as a <code>ToolMessage</code> linked to the same <code>tool_call_id</code>.
              </p>
              <CodeBlock file="tool_message.json" lang="json">
{JSON.stringify({
  role: "tool",
  tool_call_id: "call_8c1f",
  name: tool.name,
  content: tool.result,
}, null, 2)}
              </CodeBlock>
            </>
          )}
        </div>
      </div>
    </Diagram>
  );
}

window.ToolSimulator = ToolSimulator;
