import React, { useCallback, useEffect, useState } from 'react';
import { api } from './api.js';
import { copyToast } from './toast.js';

const STATUS_COLOR = { online: '#36f0b0', pending: '#f2b85f', lost: '#ff9f5a', down: '#ff7a8c' };
const TAG_EMOJI = { backend: '🛠️', model: '🧠', frontend: '🎨', ui: '🖌️', web: '🌐', data: '📊', devops: '⚙️', ml: '🤖', security: '🔐', api: '🔌', bot: '🤖', chat: '💬', test: '🧪', docs: '📄', design: '✏️', ops: '🚦', research: '🔬' };
const classEmoji = (c) => { for (const t of (c.tags || [])) if (TAG_EMOJI[t]) return TAG_EMOJI[t]; return '🗡️'; };
function avatarStyle(name) { let h = 0; for (const ch of String(name)) h = (h * 31 + ch.charCodeAt(0)) >>> 0; const a = h % 360, b = (a + 70 + h % 90) % 360; return { background: `linear-gradient(135deg, hsl(${a} 68% 46%), hsl(${b} 64% 32%))` }; }

// ---- Browse Agents: all public classes, filter by tag --------------------
export function AgentBrowse({ auth, setRoute }) {
  const [classes, setClasses] = useState([]);
  const [tags, setTags] = useState({});
  const [tag, setTag] = useState('');
  const [q, setQ] = useState('');
  const [open, setOpen] = useState(null);
  const [err, setErr] = useState('');
  const [loaded, setLoaded] = useState(false);

  const load = useCallback(async () => {
    setErr('');
    try {
      const [c, s] = await Promise.all([api(`/agents/classes${tag ? `?tag=${encodeURIComponent(tag)}` : ''}`), api('/agents/stats')]);
      setClasses((c.classes || []).filter((x) => !q || (x.name + x.tags.join() + x.description).toLowerCase().includes(q.toLowerCase())));
      setTags(s.tags || {});
    } catch (e) { setErr(e.message); } finally { setLoaded(true); }
  }, [tag, q]);
  useEffect(() => { load(); }, [load]);

  return (
    <div className="ap">
      <div className="ap-store-head">
        <div className="ap-store-intro">
          <h2>The mercenary roster</h2>
          <p>Hire a ready-made agent by skill and tag — chat with it, embed it on your site, or drive its terminal. Bring your own and it joins the roster.</p>
        </div>
        <input className="ap-search" placeholder="search the roster…" value={q} onChange={(e) => setQ(e.target.value)} />
      </div>
      <div className="ap-tags">
        <button className={`ap-tag${!tag ? ' on' : ''}`} onClick={() => setTag('')}>★ all</button>
        {Object.entries(tags).sort((a, b) => b[1] - a[1]).map(([t, n]) => (
          <button key={t} className={`ap-tag${tag === t ? ' on' : ''}`} onClick={() => setTag(t)}>{TAG_EMOJI[t] || '🗡️'} {t} <em>{n}</em></button>
        ))}
      </div>
      {err && <p className="px-auth-err">{err}</p>}
      <div className="ap-grid">
        {!loaded && Array.from({ length: 3 }).map((_, i) => (
          <div key={`sk${i}`} className="ap-card ap-skel" aria-hidden="true">
            <div className="ap-skel-head"><span className="sk-av" /><span className="sk-tt"><i /><i /></span></div>
            <span className="sk-p" /><span className="sk-p sk-short" />
            <div className="ap-skel-foot"><i /><i /></div>
          </div>
        ))}
        {loaded && classes.map((c) => (
          <button key={c.id} className="ap-card" onClick={() => setOpen(c.id)}>
            <div className="ap-card-head2">
              <span className="ap-avatar" style={avatarStyle(c.name)}>{classEmoji(c)}</span>
              <div className="ap-card-titles"><strong>{c.name}</strong><span className="ap-kind">{c.kind}</span></div>
            </div>
            <p className="ap-desc">{c.description || 'No description.'}</p>
            <div className="ap-card-tags">{c.tags.map((t) => <span key={t}>{t}</span>)}</div>
            <div className="ap-card-foot">
              <span>by {c.owner}</span>
              <span className="ap-online"><i className={c.onlineCount ? 'pulse' : ''} style={{ background: c.onlineCount ? STATUS_COLOR.online : '#555' }} />{c.onlineCount}/{c.instanceCount} online</span>
            </div>
          </button>
        ))}
        {loaded && classes.length > 0 && (
          <button className="ap-card ap-card-add" onClick={() => setRoute('booth')}>
            <span className="ap-add-plus" aria-hidden="true">＋</span>
            <strong>Publish your own</strong>
            <p>Register an agent class and run it from your booth — your mercenary joins the roster right here.</p>
            <span className="ap-add-cta">Open My Booth →</span>
          </button>
        )}
        {loaded && !classes.length && (
          <div className="ap-empty-start">
            <h3>No agents here yet — be the first.</h3>
            <ol>
              <li><b>Publish a class</b> in <button className="ap-link" onClick={() => setRoute('booth')}>My Booth</button> — name it, tag it (e.g. <code>backend</code>, <code>model</code>).</li>
              <li><b>Run an instance</b> — your broker connects and it goes <span style={{ color: STATUS_COLOR.online }}>online</span>.</li>
              <li><b>Use it</b> — embed it as a chatbox or drive it through a web terminal.</li>
            </ol>
            <button className="px-action" onClick={() => setRoute('booth')}>Open My Booth →</button>
          </div>
        )}
      </div>
      {open && <ClassModal id={open} auth={auth} onClose={() => { setOpen(null); load(); }} />}
    </div>
  );
}

function ClassModal({ id, auth, onClose }) {
  const [data, setData] = useState(null);
  const [sub, setSub] = useState(null);
  const [use, setUse] = useState(null); // instance to use
  const [err, setErr] = useState('');
  const load = useCallback(() => api(`/agents/classes/${id}`).then(setData).catch((e) => setErr(e.message)), [id]);
  useEffect(() => { load(); }, [load]);
  const subscribe = async () => { try { const r = await api(`/agents/classes/${id}/subscribe`, { method: 'POST' }); setSub(r.token); } catch (e) { setErr(e.message); } };
  if (!data) return null;
  const c = data.class;
  return (
    <div className="ap-modal" onClick={onClose}>
      <div className="ap-modal-box" onClick={(e) => e.stopPropagation()}>
        <div className="ap-modal-head">
          <div className="ap-modal-title">
            <span className="ap-avatar" style={avatarStyle(c.name)}>{classEmoji(c)}</span>
            <div><h3>{c.name}</h3><span className="ap-kind">{c.kind}</span> <span className="ap-by">by {c.owner}</span></div>
          </div>
          <button onClick={onClose}>✕</button>
        </div>
        <p className="ap-desc">{c.description}</p>
        <div className="ap-card-tags">{c.tags.map((t) => <span key={t}>{t}</span>)}</div>
        {err && <p className="px-auth-err">{err}</p>}
        <div className="ap-sub">
          {auth.user ? <button className="px-action" onClick={subscribe}>Get subscription token</button> : <span className="ap-hint">Log in to subscribe.</span>}
          {sub && <code className="ap-token" onClick={() => copyToast(sub)}>{sub} ⧉</code>}
        </div>
        <h4 className="ap-h4">Instances</h4>
        <div className="ap-inst-list">
          {data.instances.map((i) => (
            <div key={i.id} className="ap-inst">
              <span className="ap-inst-status" style={{ background: STATUS_COLOR[i.status] }} title={i.status} />
              <span className="ap-inst-name">#{i.id} {i.name}</span>
              <span className="ap-inst-meta">{i.status}{i.broker ? ` · ${i.broker}` : ''} · {i.visibility}</span>
              <button className="px-action" disabled={i.status !== 'online'} onClick={() => setUse(i)}>Use ▸</button>
            </div>
          ))}
          {!data.instances.length && <p className="ap-hint">No instances published. The owner can publish one in My Booth.</p>}
        </div>
        {use && <UsePanel instance={use} onClose={() => setUse(null)} />}
      </div>
    </div>
  );
}

// ---- Use an instance: chatbox + web-pty ----------------------------------
export function UsePanel({ instance, onClose }) {
  const [mode, setMode] = useState('chatbox');
  const [sess, setSess] = useState(null);
  const [accesskey, setAccesskey] = useState(instance.accesskey || '');
  const [err, setErr] = useState('');
  const start = useCallback(async () => {
    setErr('');
    try {
      const r = await api(`/agents/instances/${instance.id}/sessions`, { method: 'POST', body: { connector: mode, accesskey: accesskey || undefined } });
      setSess(r);
    } catch (e) { setErr(e.message); }
  }, [instance.id, mode, accesskey]);
  useEffect(() => { if (instance.accesskey) start(); }, []); // owner: auto-start

  return (
    <div className="ap-use">
      <div className="ap-use-head">
        <div className="ap-use-tabs">
          <button className={mode === 'chatbox' ? 'on' : ''} onClick={() => { setMode('chatbox'); setSess(null); }}>Chatbox</button>
          <button className={mode === 'webpty' ? 'on' : ''} onClick={() => { setMode('webpty'); setSess(null); }}>Web PTY</button>
        </div>
        <button className="ap-use-x" onClick={onClose}>close ✕</button>
      </div>
      {!sess && (
        <div className="ap-use-start">
          {!instance.accesskey && instance.visibility !== 'public' && (
            <input placeholder="instance accesskey (private)" value={accesskey} onChange={(e) => setAccesskey(e.target.value)} />
          )}
          <button className="px-action" onClick={start}>Connect {mode}</button>
          {err && <p className="px-auth-err">{err}</p>}
        </div>
      )}
      {sess && (
        <>
          <iframe title="agent" className="ap-iframe" src={`https://webagent.amerc.ai/chat_session?session=${encodeURIComponent(sess.relayToken)}`} />
          {mode === 'chatbox' && (
            <div className="ap-embed">
              <div className="ap-embed-head"><span>📎 Embed this agent on any website</span><button className="px-action" onClick={() => copyToast(`<script src="${sess.chatboxJs}"></script>`, 'Embed snippet copied')}>Copy snippet</button></div>
              <code>{`<script src="${sess.chatboxJs}"></script>`}</code>
              <p className="ap-hint">Paste before <code>&lt;/body&gt;</code> — a chat bubble appears bottom-right, and on connect your page's skills are injected into the agent.</p>
            </div>
          )}
          {mode === 'webpty' && <p className="ap-hint ap-pty-note">🖥️ Switch to the <b>后台 / Backstage</b> tab above to watch and drive the agent's live terminal.</p>}
        </>
      )}
    </div>
  );
}

// ---- My Booth: publish classes + instances, manage ------------------------
export function KeysCard() {
  const [keys, setKeys] = useState([]);
  const [name, setName] = useState('');
  const [created, setCreated] = useState(null);
  const [err, setErr] = useState('');
  const load = useCallback(() => api('/keys').then((d) => setKeys(d.keys || [])).catch((e) => setErr(e.message)), []);
  useEffect(() => { load(); }, [load]);
  const mint = async (e) => { e.preventDefault(); setErr(''); try { const r = await api('/keys', { method: 'POST', body: { name } }); setCreated(r); setName(''); load(); } catch (e2) { setErr(e2.message); } };
  const del = async (id) => { try { await api(`/keys/${id}`, { method: 'DELETE' }); load(); } catch (e2) { setErr(e2.message); } };
  return (
    <div className="ap-keys">
      <h4 className="ap-h4">🔑 My agent keys</h4>
      <p className="ap-hint">Mint a key for your own agent to read/write amerc docs, netdisk and the agent platform. Send it as <code>Authorization: Bearer &lt;key&gt;</code>.</p>
      <form className="ap-keys-mint" onSubmit={mint}>
        <input placeholder="key name (e.g. my-bot)" value={name} onChange={(e) => setName(e.target.value)} required />
        <button className="px-action" type="submit">+ Mint key</button>
      </form>
      {created && <div className="mn-created"><p>✅ minted — copy now, shown once:</p><code className="ap-token" onClick={() => copyToast(created.key)}>{created.key} ⧉</code></div>}
      {err && <p className="px-auth-err">{err}</p>}
      {keys.map((k) => (
        <div key={k.id} className="ap-mine-inst">
          <code className="ap-token">{k.prefix}…</code> <em>{k.name}</em>
          <span className="ap-hint" style={{ marginLeft: 'auto' }}>{k.last_used ? `used ${new Date(k.last_used).toLocaleDateString()}` : 'never used'}</span>
          <button className="px-action" onClick={() => del(k.id)}>revoke</button>
        </div>
      ))}
      {!keys.length && <p className="ap-hint">No keys yet — mint one above.</p>}
    </div>
  );
}

export function BoothDashboard({ auth, setRoute }) {
  const [classes, setClasses] = useState([]);
  const [insts, setInsts] = useState([]);
  const [err, setErr] = useState('');
  const [form, setForm] = useState({ name: '', tags: '', description: '', kind: 'codex', command: 'codex --yolo', visibility: 'public' });
  const [newInst, setNewInst] = useState(null);
  const [loaded, setLoaded] = useState(false);

  const load = useCallback(async () => {
    setErr('');
    try {
      const c = await api('/agents/classes?mine=1');
      setClasses(c.classes || []);
      const all = await Promise.all((c.classes || []).map((x) => api(`/agents/instances?classId=${x.id}`).then((r) => r.instances).catch(() => [])));
      setInsts(all.flat());
    } catch (e) { setErr(e.message); } finally { setLoaded(true); }
  }, []);
  useEffect(() => { if (auth.user) load(); }, [auth.user, load]);

  if (!auth.ready) return <div className="ap"><p>Loading…</p></div>;
  if (!auth.user) return (
    <div className="ap ap-gate"><h2>My Booth</h2><p>Log in to publish and run agents.</p><button className="px-action" onClick={() => setRoute('signin')}>Go to Login</button></div>
  );

  const publishClass = async (e) => {
    e.preventDefault();
    try { await api('/agents/classes', { method: 'POST', body: { ...form, tags: form.tags.split(',').map((t) => t.trim()).filter(Boolean) } }); setForm({ ...form, name: '', tags: '', description: '' }); load(); }
    catch (e2) { setErr(e2.message); }
  };
  const publishInstance = async (classId) => {
    try { const r = await api('/agents/instances', { method: 'POST', body: { classId, visibility: 'public' } }); setNewInst(r); load(); }
    catch (e2) { setErr(e2.message); }
  };
  const shutdown = async (i) => { try { await api(`/agents/instances/${i.id}`, { method: 'DELETE', body: { accesskey: i.accesskey } }); load(); } catch (e2) { setErr(e2.message); } };

  return (
    <div className="ap">
      <div className="ap-head"><h2>My Booth</h2><span className="ap-by">{auth.user.handle}</span></div>
      {err && <p className="px-auth-err">{err}</p>}
      <div className="ap-booth-grid">
        <form className="ap-publish" onSubmit={publishClass}>
          <h4 className="ap-h4">Publish an agent class</h4>
          <input placeholder="class name" value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} required />
          <input placeholder="tags (comma): backend, model" value={form.tags} onChange={(e) => setForm({ ...form, tags: e.target.value })} />
          <textarea placeholder="description" value={form.description} onChange={(e) => setForm({ ...form, description: e.target.value })} />
          <div className="ap-row">
            <input placeholder="kind (codex)" value={form.kind} onChange={(e) => setForm({ ...form, kind: e.target.value })} />
            <select value={form.visibility} onChange={(e) => setForm({ ...form, visibility: e.target.value })}><option value="public">public</option><option value="private">private publish</option></select>
          </div>
          <input placeholder="launch command" value={form.command} onChange={(e) => setForm({ ...form, command: e.target.value })} />
          <button className="px-action px-auth-submit" type="submit">Publish class</button>
        </form>
        <div className="ap-mine">
          {!loaded ? (
            <div className="ap-mine-skel" aria-hidden="true">
              <span className="sk-p" style={{ width: '40%', height: 12 }} />
              <div className="ap-skel-row"><span className="sk-av" /><span className="sk-p" style={{ flex: 1 }} /></div>
              <div className="ap-skel-row"><span className="sk-av" /><span className="sk-p" style={{ flex: 1 }} /></div>
              <span className="sk-p" style={{ width: '30%', height: 12, marginTop: 14 }} />
              <div className="ap-skel-row"><span className="sk-p" style={{ flex: 1 }} /></div>
            </div>
          ) : !classes.length ? (
            <div className="ap-booth-welcome">
              <span className="ap-booth-welcome-ico" aria-hidden="true">🗡️</span>
              <h3>Welcome to your booth, {auth.user.handle}.</h3>
              <p>This is where you arm and dispatch your mercenaries. Three steps to go live:</p>
              <ol>
                <li><b>Publish a class</b> — name your agent and tag its skills, in the form on the left.</li>
                <li><b>Run an instance</b> — your broker connects and it turns <span className="ap-on-word">online</span>.</li>
                <li><b>Deliver it</b> — embed a chatbox, drive a web terminal, or expose a local port via the <b>Mansion</b>.</li>
              </ol>
              <p className="ap-hint">Your broker authenticates with an instance accesskey (shown when you publish one) or an agent key — mint one below.</p>
            </div>
          ) : (
            <>
              <h4 className="ap-h4">My classes</h4>
              {classes.map((c) => (
                <div key={c.id} className="ap-mine-class">
                  <div className="ap-mine-row">
                    <span className="ap-avatar ap-avatar-sm" style={avatarStyle(c.name)}>{classEmoji(c)}</span>
                    <strong>{c.name}</strong><span className="ap-kind">{c.visibility}</span>
                    <span className="ap-online"><i className={c.onlineCount ? 'pulse' : ''} style={{ background: c.onlineCount ? STATUS_COLOR.online : '#555' }} />{c.onlineCount}/{c.instanceCount}</span>
                    <button className="px-action" onClick={() => publishInstance(c.id)}>+ Publish instance</button></div>
                  <div className="ap-card-tags">{c.tags.map((t) => <span key={t}>{t}</span>)}</div>
                </div>
              ))}
              <h4 className="ap-h4">My instances</h4>
              {insts.map((i) => (
                <div key={i.id} className="ap-mine-inst">
                  <span className={`ap-inst-status${i.status === 'online' ? ' pulse' : ''}`} style={{ background: STATUS_COLOR[i.status] }} /> #{i.id} <em>{i.status}</em>
                  {i.accesskey && <code className="ap-token" title="accesskey — your broker connects with this" onClick={() => copyToast(i.accesskey)}>{i.accesskey.slice(0, 14)}… ⧉</code>}
                  <button className="px-action" onClick={() => shutdown(i)}>shut down</button>
                </div>
              ))}
              {!insts.length && <p className="ap-hint">No instances. Publish one from a class above.</p>}
            </>
          )}
        </div>
      </div>
      <KeysCard />
      {newInst && (() => {
        const hb = `while true; do curl -s -XPOST https://amerc.ai/api/agents/instances/${newInst.id}/heartbeat -H 'content-type: application/json' -d '{"accesskey":"${newInst.accesskey}","status":"online","broker":"my-broker"}' >/dev/null; sleep 10; done`;
        return (
          <div className="ap-modal" onClick={() => setNewInst(null)}>
            <div className="ap-modal-box" onClick={(e) => e.stopPropagation()}>
              <div className="ap-modal-head"><h3>Instance #{newInst.id} — bring it online</h3><button onClick={() => setNewInst(null)}>✕</button></div>
              <p className="ap-hint">Registered, but <b style={{ color: '#ff9f5a' }}>offline</b> until a broker checks in. Two steps bring it to life:</p>
              <ol className="ap-steps">
                <li><b>Heartbeat</b> — keeps it marked online (check in every &lt;30s). Paste this anywhere with <code>curl</code>:
                  <div className="ap-codeblock"><code>{hb}</code><button className="px-action" onClick={() => copyToast(hb, 'Heartbeat loop copied')}>copy</button></div>
                </li>
                <li><b>Relay</b> — bridge your agent so live sessions reach it, over the broker WebSocket:
                  <code className="ap-token" onClick={() => copyToast(newInst.relayWs)}>{newInst.relayWs} ⧉</code>
                  <span className="ap-hint">The amerc webagent broker speaks this relay for you — point it at the accesskey below.</span>
                </li>
              </ol>
              <label className="ap-field">accesskey · your broker's secret<code className="ap-token" onClick={() => copyToast(newInst.accesskey)}>{newInst.accesskey} ⧉</code></label>
            </div>
          </div>
        );
      })()}
    </div>
  );
}
