/* ATP prototype — three tabs:
   1) Builder  — pick endpoint, fill params, send, see request/response
   2) Chat     — type message → kernel routes to agent → reply + envelope
   3) Playground — prompt | ATP envelope | raw response, side-by-side
   Uses window.claude.complete() for real LLM replies where applicable. */

const { useState, useEffect, useRef, useMemo } = React;

const API_BASE = 'https://api.artemis.city'; // visual only — routes mounted under /api/v1/*

/* The four agents the kernel routes between (see src/interface/agent_router.yaml). */
const KERNEL_AGENTS = [
  { id: 'artemis',  role: 'Mayor protocol, governance' },
  { id: 'planner',  role: 'Architect, planning' },
  { id: 'pack_rat', role: 'Courier, safe transfer' },
  { id: 'daemon',   role: 'System anchor, memory' },
];

/* Build an ATPMessage (shape matches src/agents/atp/__init__.py — dataclass). */
function makeATPMessage({ mode, context, priority, action_type, target_zone, special_notes, content }) {
  return {
    mode: mode || 'BUILD',
    context: context || '',
    priority: priority || 'NORMAL',
    action_type: action_type || 'EXECUTE',
    target_zone: target_zone || 'chat/',
    special_notes: special_notes || '',
    content: content || '',
  };
}

/* Pick a mode + action_type from free text — same heuristic the router yaml uses on keywords. */
function inferAtpFromText(text) {
  const t = text.toLowerCase();
  if (/summari[sz]e|tl;dr|distill|brief/.test(t))           return { mode: 'SYNTHESIZE', action_type: 'SUMMARIZE' };
  if (/audit|review|check|policy|governance/.test(t))      return { mode: 'REVIEW',     action_type: 'REFLECT'   };
  if (/plan|roadmap|scaffold|blueprint|checklist/.test(t)) return { mode: 'BUILD',      action_type: 'SCAFFOLD'  };
  if (/save|persist|archive|capture|note/.test(t))         return { mode: 'CAPTURE',    action_type: 'EXECUTE'   };
  if (/commit|finalize|merge|ship/.test(t))                return { mode: 'COMMIT',     action_type: 'EXECUTE'   };
  return { mode: 'BUILD', action_type: 'EXECUTE' };
}

/* Render an ATPMessage as the `#Mode: …` hash-prefix text the parser reads. */
function atpToHashBlock(m) {
  return `#Mode: ${m.mode}\n#Context: ${m.context}\n#Priority: ${m.priority}\n#ActionType: ${m.action_type}\n#TargetZone: ${m.target_zone}\n#SpecialNotes: ${m.special_notes || 'None'}`;
}

/* Syntax-highlight JSON */
function HJSON({ data }) {
  if (data == null) return null;
  const text = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
  // Highlight keys/strings/numbers/booleans
  const html = text
    .replace(/&/g, '&amp;').replace(/</g, '&lt;')
    .replace(/("(?:\\.|[^"\\])*")(\s*:)/g, '<span class="k">$1</span>$2')
    .replace(/:\s*("(?:\\.|[^"\\])*")/g, ': <span class="s">$1</span>')
    .replace(/\b(-?\d+(?:\.\d+)?)\b/g, '<span class="n">$1</span>')
    .replace(/\b(true|false|null)\b/g, '<span class="b">$1</span>')
    .replace(/([{}\[\],])/g, '<span class="ck">$1</span>');
  return <pre className="json" dangerouslySetInnerHTML={{ __html: html }} />;
}

/* ====== Tab 1: Builder ====== */
function Builder() {
  const [activeId, setActiveId] = useState(ENDPOINTS[0].id);
  const endpoint = ENDPOINTS.find((e) => e.id === activeId);

  // Init values from endpoint defaults
  const [values, setValues] = useState({});
  useEffect(() => {
    const v = {};
    endpoint.params.forEach((p) => { if (p.default !== undefined) v[p.name] = p.default; });
    setValues(v);
    setResp(null);
  }, [activeId]);

  const [pending, setPending] = useState(false);
  const [resp, setResp] = useState(null);
  const [respMs, setRespMs] = useState(0);

  async function send() {
    setPending(true);
    const t0 = performance.now();
    // Simulated network latency
    await new Promise((r) => setTimeout(r, 280 + Math.random() * 320));
    const payload = endpoint.sample(values);
    setResp(payload);
    setRespMs(Math.round(performance.now() - t0));
    setPending(false);
  }

  const requestPreview = useMemo(() => {
    const queryParams = endpoint.method === 'GET'
      ? Object.entries(values).filter(([, v]) => v !== '' && v !== undefined).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&')
      : '';
    let urlPath = endpoint.path;
    Object.entries(values).forEach(([k, v]) => {
      urlPath = urlPath.replace(`{${k}}`, encodeURIComponent(v));
    });
    return {
      method: endpoint.method,
      url: API_BASE + urlPath + (queryParams ? '?' + queryParams : ''),
      headers: {
        Authorization: 'Bearer <descope-jwt>',
        'X-Kernel-Session': 'a4f3-elect-12',
        'Content-Type': 'application/json',
      },
      body: endpoint.method !== 'GET' ? values : undefined,
    };
  }, [endpoint, values]);

  return (
    <div className="grid3">
      <div className="panel">
        <div className="panel-head"><h3>Endpoints</h3><span className="meta">{ENDPOINTS.length} routes</span></div>
        <div className="endpoints">
          {ENDPOINT_GROUPS.map((g) => (
            <div key={g.name}>
              <div className="grp-head">{g.name}</div>
              {g.items.map((e) => (
                <div key={e.id} className={'endpoint ' + (e.id === activeId ? 'on' : '')} onClick={() => setActiveId(e.id)}>
                  <div className="top">
                    <span className={'method ' + e.method}>{e.method}</span>
                    <span className="path">{e.path}</span>
                  </div>
                  <span className="desc">{e.desc}</span>
                </div>
              ))}
            </div>
          ))}
        </div>
      </div>

      <div className="panel">
        <div className="panel-head">
          <h3><span style={{ marginRight: 8, padding: '2px 6px', borderRadius: 4, fontSize: 10, background: 'rgba(34,211,238,0.18)', color: '#67e8f9', fontFamily: 'JetBrains Mono', fontWeight: 600 }}>{endpoint.method}</span>{endpoint.path}</h3>
          <span className="meta">params · {endpoint.params.length}</span>
        </div>
        <div className="panel-body">
          <div style={{ marginBottom: 14, fontSize: 13, color: 'var(--fg-2)', lineHeight: 1.5 }}>{endpoint.desc}</div>
          {endpoint.params.length === 0 && (
            <div style={{ fontSize: 13, color: 'var(--fg-3)', fontStyle: 'italic', padding: 8 }}>No parameters — send the request directly.</div>
          )}
          {endpoint.params.map((p) => (
            <div key={p.name} className="field">
              <label>
                {p.name}{p.required && <span className="req">*</span>}
                <span className="type">{p.type}</span>
              </label>
              {p.type.startsWith('enum:') ? (
                <select value={values[p.name] || ''} onChange={(e) => setValues({ ...values, [p.name]: e.target.value })}>
                  {p.type.slice(5).split(',').map((o) => <option key={o} value={o}>{o}</option>)}
                </select>
              ) : p.multi ? (
                <textarea value={values[p.name] || ''} onChange={(e) => setValues({ ...values, [p.name]: e.target.value })} placeholder={p.desc} />
              ) : (
                <input type={p.type === 'number' ? 'number' : 'text'} value={values[p.name] ?? ''} onChange={(e) => setValues({ ...values, [p.name]: p.type === 'number' ? +e.target.value : e.target.value })} placeholder={p.desc} />
              )}
              {p.desc && <div style={{ fontSize: 11, color: 'var(--fg-3)' }}>{p.desc}</div>}
            </div>
          ))}
          <div className="form-foot">
            <button className="btn primary" onClick={send} disabled={pending}>
              {pending ? 'Sending…' : '▶  Send request'}
            </button>
            <button className="btn ghost" onClick={() => { const v = {}; endpoint.params.forEach((p) => { if (p.default !== undefined) v[p.name] = p.default; }); setValues(v); }}>↺  Reset</button>
          </div>
        </div>
      </div>

      <div className="panel">
        <div className="panel-head">
          <h3>Request / Response</h3>
          {resp && <span className="meta" style={{ color: '#86efac' }}>● 200 OK · {respMs}ms</span>}
        </div>
        <div className="panel-body" style={{ padding: 0 }}>
          <div style={{ padding: '14px 16px', borderBottom: '1px solid rgba(255,255,255,0.06)' }}>
            <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-3)', letterSpacing: '0.10em', textTransform: 'uppercase', marginBottom: 6 }}>Request</div>
            <HJSON data={requestPreview} />
          </div>
          {resp ? (
            <div style={{ padding: '14px 16px' }}>
              <div className="resp-head" style={{ padding: 0, background: 'none', border: 'none', marginBottom: 6 }}>
                <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-3)', letterSpacing: '0.10em', textTransform: 'uppercase' }}>Response</div>
                <span className="status-pill">200 OK</span>
                <span style={{ color: 'var(--fg-3)' }}>· {respMs}ms · 1.2KB</span>
              </div>
              <HJSON data={resp} />
            </div>
          ) : (
            <div style={{ padding: 24, fontSize: 13, color: 'var(--fg-3)', textAlign: 'center' }}>
              <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 8 }}>● awaiting send</div>
              Press <kbd style={{ background: 'rgba(255,255,255,0.08)', padding: '2px 6px', borderRadius: 3, fontFamily: 'var(--font-mono)' }}>Send request</kbd> to see the response.
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* ====== Tab 2: Chat ====== */
function ChatTab() {
  const [msgs, setMsgs] = useState([]);
  const [draft, setDraft] = useState('');
  const [pending, setPending] = useState(false);
  const [envelope, setEnvelope] = useState(null);
  const scrollRef = useRef(null);

  useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [msgs, pending]);

  async function send() {
    const text = draft.trim();
    if (!text || pending) return;
    setDraft('');
    setPending(true);

    setMsgs((m) => [...m, { role: 'user', content: text }]);
    setMsgs((m) => [...m, { role: 'assistant', content: '', typing: true }]);

    // Build the real ATPMessage (mirrors src/agents/atp/__init__.py dataclass)
    const inferred = inferAtpFromText(text);
    const env = makeATPMessage({
      mode: inferred.mode,
      context: text.slice(0, 80),
      priority: 'NORMAL',
      action_type: inferred.action_type,
      target_zone: 'chat/',
      content: text,
    });
    // Dispatch metadata returned by /api/v1/atp/dispatch (envelope_id, routed_to, receipt)
    const dispatch = {
      envelope_id: 'env_' + Math.random().toString(16).slice(2, 10),
      routed_to: env.mode === 'SYNTHESIZE' ? 'planner' : env.mode === 'CAPTURE' ? 'pack_rat' : 'artemis',
      weight: 0.91,
      receipt: 'rcpt_' + Math.random().toString(16).slice(2, 6),
      signed_at: new Date().toISOString(),
    };
    setEnvelope({ ...env, _dispatch: dispatch });

      try {
      const reply = await window.claude.complete({
        messages: [{
          role: 'user',
          content: `You are Artemis, the Mayor-protocol orchestrator agent of Artemis City. Reply concisely (max 80 words). You are receiving an ATP-wrapped task. Output only the human-readable answer.\n\nUser: ${text}`,
        }],
      });
      setMsgs((m) => {
        const copy = [...m];
        copy[copy.length - 1] = { role: 'assistant', content: reply };
        return copy;
      });
      // Reflect the response receipt back onto the dispatch metadata
      setEnvelope((e) => e && { ...e, _dispatch: { ...e._dispatch, reply_in_ms: 412, output_tokens: (reply.length / 4) | 0 } });
    } catch (err) {
      setMsgs((m) => {
        const copy = [...m];
        copy[copy.length - 1] = { role: 'assistant', content: '⚠ Kernel error: ' + (err?.message || 'LLM unreachable.'), error: true };
        return copy;
      });
    } finally {
      setPending(false);
    }
  }

  function handleKey(e) {
    if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); }
  }

  return (
    <div className="grid-chat">
      <div className="panel chat-stage">
        <div className="panel-head">
          <h3>Chat · routed via kernel</h3>
          <span className="meta">mayor: artemis · ATP v1</span>
        </div>
        <div className="chat-thread" ref={scrollRef}>
          {msgs.length === 0 && (
            <div style={{ margin: 'auto', textAlign: 'center', maxWidth: 460, color: 'var(--fg-2)', padding: 28 }}>
              <div style={{ fontFamily: 'var(--font-display)', fontSize: 24, fontWeight: 700, background: 'var(--gradient-kernel)', WebkitBackgroundClip: 'text', backgroundClip: 'text', color: 'transparent', marginBottom: 10 }}>Chat via ATP</div>
              <p style={{ lineHeight: 1.55, margin: '0 0 14px' }}>Type a message — the kernel parses it into an ATPMessage, picks an agent by router keywords, and shows you the round-trip in real time.</p>
              <div style={{ display: 'grid', gap: 6 }}>
                <button className="btn ghost" onClick={() => setDraft('Audit today\'s trust-decay deltas. Anything I should review?')}>Audit today's trust-decay deltas. Anything I should review?</button>
                <button className="btn ghost" onClick={() => setDraft('Plan a 3-day spike to add Notion two-way sync to the memory bus.')}>Plan a 3-day spike to add Notion two-way sync.</button>
                <button className="btn ghost" onClick={() => setDraft('Summarize the Q1 OKR doc into a CAPTURE-mode briefing.')}>Summarize the Q1 OKR doc into a CAPTURE briefing.</button>
              </div>
            </div>
          )}
          {msgs.map((m, i) => (
            <div key={i} className={'bubble-row' + (m.role === 'user' ? ' user' : '')}>
              <div className="av" style={{ background: m.role === 'user' ? undefined : 'linear-gradient(135deg, #fbbf24, #f59e0b)' }}>{m.role === 'user' ? 'YOU' : 'A'}</div>
              <div className={'bubble' + (m.role === 'user' ? ' user' : '')}>
                {m.role === 'assistant' && <div className="who"><b>artemis</b> · mayor protocol</div>}
                {m.typing && !m.content ? <span className="typing"><span></span><span></span><span></span></span> : m.content}
              </div>
            </div>
          ))}
        </div>
        <div className="chat-composer">
          <div className="row-input">
            <textarea placeholder="Send to kernel… (Enter to send · Shift+Enter newline)" value={draft} onChange={(e) => setDraft(e.target.value)} onKeyDown={handleKey} />
            <button className="send" disabled={pending || !draft.trim()} onClick={send}>▶</button>
          </div>
        </div>
      </div>

      <div className="panel">
        <div className="panel-head">
          <h3>ATP message</h3>
          <span className="meta">{envelope ? 'parsed · dispatched' : 'awaiting send'}</span>
        </div>
        <div className="panel-body">
          {envelope ? <HJSON data={envelope} /> : (
            <div style={{ textAlign: 'center', color: 'var(--fg-3)', padding: 30 }}>
              <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 6 }}>● ATPMessage inspector</div>
              <p style={{ fontSize: 13 }}>The kernel parses every chat message into an <code style={{ background: 'rgba(255,255,255,0.06)', padding: '1px 5px', borderRadius: 4 }}>ATPMessage</code> dataclass &mdash; mode, context, priority, action_type, target_zone &mdash; then routes it. Send one to see it.</p>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* ====== Tab 3: Playground ====== */
function Playground() {
  const [prompt, setPrompt] = useState('Audit the Q1 trust-decay log. Surface anything that crosses 0.05/cycle.');
  const [pending, setPending] = useState(false);
  const [reply, setReply] = useState('');
  const [envelope, setEnvelope] = useState(null);
  const [raw, setRaw] = useState(null);
  const [agent, setAgent] = useState('artemis');
  const [priority, setPriority] = useState('NORMAL');
  const [mode, setMode] = useState('REVIEW');

  async function run() {
    if (pending) return;
    setPending(true);
    setReply(''); setEnvelope(null); setRaw(null);

    const env = makeATPMessage({
      mode,
      context: prompt.slice(0, 80),
      priority,
      action_type: mode === 'SYNTHESIZE' ? 'SUMMARIZE' : mode === 'BUILD' ? 'SCAFFOLD' : mode === 'REVIEW' ? 'REFLECT' : 'EXECUTE',
      target_zone: 'playground/',
      special_notes: `routed-to: ${agent}`,
      content: prompt,
    });
    const dispatch = {
      envelope_id: 'env_' + Math.random().toString(16).slice(2, 10),
      routed_to: agent,
      receipt: 'rcpt_' + Math.random().toString(16).slice(2, 6),
      signed_at: new Date().toISOString(),
    };
    setEnvelope({ ...env, _dispatch: dispatch });

    const t0 = performance.now();
    try {
      const r = await window.claude.complete({ messages: [{ role: 'user', content: `Answer concisely as agent "${agent}". Max 90 words.\n\nUser prompt: ${prompt}` }] });
      setReply(r);
      const latency = Math.round(performance.now() - t0);
      setRaw({
        model: 'claude-haiku-4-5',
        provider: 'anthropic',
        request_id: 'req_' + Math.random().toString(16).slice(2, 10),
        latency_ms: latency,
        usage: { input_tokens: prompt.length / 4 | 0, output_tokens: r.length / 4 | 0 },
        stop_reason: 'end_turn',
        envelope_id: dispatch.envelope_id,
        receipt: dispatch.receipt,
        completion: r,
      });
    } catch (err) {
      setReply('⚠ ' + (err?.message || 'request failed'));
    } finally {
      setPending(false);
    }
  }

  return (
    <div className="grid-pg">
      <div className="panel">
        <div className="panel-head"><h3>Prompt</h3><span className="meta">input</span></div>
        <div className="panel-body">
          <div className="field">
            <label>Agent <span className="type">enum</span></label>
            <select value={agent} onChange={(e) => setAgent(e.target.value)}>
              <option value="artemis">artemis — mayor protocol, governance</option>
              <option value="planner">planner — architect, planning</option>
              <option value="pack_rat">pack_rat — courier, safe transfer</option>
              <option value="daemon">daemon — system anchor, memory</option>
            </select>
          </div>
          <div className="field">
            <label>ATP Mode <span className="type">enum</span></label>
            <select value={mode} onChange={(e) => setMode(e.target.value)}>
              <option value="BUILD">BUILD</option>
              <option value="REVIEW">REVIEW</option>
              <option value="ORGANIZE">ORGANIZE</option>
              <option value="CAPTURE">CAPTURE</option>
              <option value="SYNTHESIZE">SYNTHESIZE</option>
              <option value="COMMIT">COMMIT</option>
            </select>
          </div>
          <div className="field">
            <label>Priority <span className="type">enum</span></label>
            <select value={priority} onChange={(e) => setPriority(e.target.value)}>
              <option value="CRITICAL">CRITICAL</option>
              <option value="HIGH">HIGH</option>
              <option value="NORMAL">NORMAL (default)</option>
              <option value="LOW">LOW</option>
            </select>
          </div>
          <div className="field" style={{ marginBottom: 0 }}>
            <label>Prompt <span className="req">*</span><span className="type">string</span></label>
            <textarea value={prompt} onChange={(e) => setPrompt(e.target.value)} rows={8} style={{ minHeight: 180 }} />
          </div>
          <div className="form-foot">
            <button className="btn primary" disabled={pending} onClick={run}>{pending ? 'Routing…' : '▶  Route through kernel'}</button>
          </div>
        </div>
      </div>

      <div className="panel">
        <div className="panel-head"><h3>ATP message</h3><span className="meta">{envelope ? 'sealed' : 'pending'}</span></div>
        <div className="panel-body">
          {envelope ? <HJSON data={envelope} /> : <Placeholder label="The kernel parses your prompt into an ATPMessage. Press Route to seal & dispatch." />}
        </div>
      </div>

      <div className="panel">
        <div className="panel-head"><h3>Reply + raw</h3><span className="meta">{raw ? `${raw.latency_ms}ms · ${raw.usage.output_tokens}t` : 'pending'}</span></div>
        <div className="panel-body" style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          {reply ? (
            <>
              <div style={{ padding: 14, background: 'rgba(34,211,238,0.06)', border: '1px solid rgba(34,211,238,0.30)', borderRadius: 10, fontSize: 13, lineHeight: 1.55, color: 'var(--fg-1)', whiteSpace: 'pre-wrap' }}>{reply || (pending && <span className="typing"><span></span><span></span><span></span></span>)}</div>
              {raw && (
                <div>
                  <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-3)', letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 6 }}>Raw response</div>
                  <HJSON data={raw} />
                </div>
              )}
            </>
          ) : pending ? (
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, color: 'var(--fg-2)', padding: 18 }}><span className="typing"><span></span><span></span><span></span></span> Routing via kernel…</div>
          ) : <Placeholder label="The agent's reply + raw provider response appear here." />}
        </div>
      </div>
    </div>
  );
}

function Placeholder({ label }) {
  return (
    <div style={{ textAlign: 'center', color: 'var(--fg-3)', padding: 30, fontSize: 13 }}>
      <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 6 }}>● placeholder</div>
      {label}
    </div>
  );
}

/* ====== Root ====== */
function App() {
  const [tab, setTab] = useState('builder');

  return (
    <>
      <div className="aurora">
        <div className="blob b1"></div>
        <div className="blob b2"></div>
        <div className="blob b3"></div>
      </div>

      <div className="app">
        <div className="topbar">
          <div className="brand">
            <span className="glyph">⚡</span>
            <div>
              <div className="title">ATP <span style={{ color: 'var(--fg-3)', fontWeight: 500 }}>· Artemis Transmission Protocol</span></div>
              <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-3)', letterSpacing: '0.12em', textTransform: 'uppercase', marginTop: 2 }}>linked · AgenticGovernance/AgenticGovernance-ArtemisCity</div>
            </div>
            <span className="tag">v1.0.0</span>
          </div>
          <div className="right">
            <span className="chip" style={{ background: 'rgba(245,158,11,0.08)', borderColor: 'rgba(245,158,11,0.30)', color: '#fcd34d' }}>
              <span className="dot" style={{ background: '#f59e0b', boxShadow: '0 0 8px #f59e0b' }}></span>
              {API_BASE}
            </span>
            <span className="chip"><span className="dot"></span> Descope · session valid</span>
          </div>
        </div>

        <div className="tabs">
          <button className={'tab ' + (tab === 'builder' ? 'on' : '')} onClick={() => setTab('builder')}>Builder<span className="badge">{ENDPOINTS.length}</span></button>
          <button className={'tab ' + (tab === 'chat' ? 'on' : '')} onClick={() => setTab('chat')}>Chat <span className="badge" style={{ background: 'rgba(34,211,238,0.16)', color: '#67e8f9' }}>live</span></button>
          <button className={'tab ' + (tab === 'pg' ? 'on' : '')} onClick={() => setTab('pg')}>Playground</button>
        </div>

        <div className="body">
          {tab === 'builder' && <Builder />}
          {tab === 'chat' && <ChatTab />}
          {tab === 'pg' && <Playground />}
        </div>
      </div>
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
