// RetellCallOverlay — terminal-styled modal that opens when "BOOK A CALL" is clicked.
// 1. Posts to /api/retell-token → gets a short-lived access_token
// 2. Uses retell-client-js-sdk (loaded from unpkg) to start a browser web-call
// 3. Streams transcript events live into a fake terminal log for that cyberpunk feel

window.OpenBookCall = function OpenBookCall(prefill) {
  window.dispatchEvent(new CustomEvent('forge:open-call', { detail: prefill || {} }));
};

function RetellCallOverlay() {
  const [open, setOpen] = React.useState(false);
  const [phase, setPhase] = React.useState('idle'); // idle|prompt|connecting|live|ended|error
  const [log, setLog] = React.useState([]);
  const [form, setForm] = React.useState({ name: '', email: '' });
  const [err, setErr] = React.useState('');
  const [elapsed, setElapsed] = React.useState(0);
  const clientRef = React.useRef(null);
  const sdkRef = React.useRef(null);
  const startRef = React.useRef(0);

  React.useEffect(() => {
    const onOpen = (e) => {
      setOpen(true);
      setPhase('prompt');
      setLog([]);
      setErr('');
      if (e.detail) setForm((f) => ({ ...f, ...e.detail }));
    };
    window.addEventListener('forge:open-call', onOpen);
    return () => window.removeEventListener('forge:open-call', onOpen);
  }, []);

  React.useEffect(() => {
    if (phase !== 'live') return;
    startRef.current = Date.now();
    setElapsed(0);
    const id = setInterval(() => setElapsed(Math.floor((Date.now() - startRef.current) / 1000)), 500);
    return () => clearInterval(id);
  }, [phase]);

  const push = (line, tone = 'dim') => setLog((l) => [...l, { line, tone }]);

  async function loadSDK() {
    if (sdkRef.current) return sdkRef.current;
    // Load vendored deps in order: eventemitter3 → livekit-client → retell sdk wrapper.
    // All three live in /vendor/ on our own origin.
    const loadScript = (src) => new Promise((resolve, reject) => {
      // skip if already present
      const existing = document.querySelector(`script[data-vendor="${src}"]`);
      if (existing) return resolve();
      const s = document.createElement('script');
      s.src = src;
      s.dataset.vendor = src;
      s.onload = resolve;
      s.onerror = () => reject(new Error('vendor·load·failed · ' + src));
      document.head.appendChild(s);
    });

    await loadScript('/vendor/eventemitter3.js');
    await loadScript('/vendor/livekit-client.js');

    // The Retell UMD wrapper reads `window.eventemitter3` and `window.livekitClient`
    // (camelCase). Different builds of those libs attach under different casings —
    // alias whatever we find to the exact names Retell expects.
    if (!window.livekitClient) {
      window.livekitClient =
        window.LivekitClient || window.LiveKitClient || window.livekit || window.LiveKit;
    }
    if (!window.eventemitter3) {
      window.eventemitter3 = window.EventEmitter3 || window.EventEmitter;
    }

    await loadScript('/vendor/retell-web-client.js');

    // Retell's UMD wrapper attaches to window.retellClientJsSdk
    const mod = window.retellClientJsSdk || window.RetellClientJsSdk;
    const Ctor = mod?.RetellWebClient || window.RetellWebClient;
    if (typeof Ctor !== 'function') {
      const keys = Object.keys(window).filter((k) => /retell|livekit|event/i.test(k));
      throw new Error('retell·sdk·no·constructor · keys: ' + keys.join(','));
    }
    sdkRef.current = Ctor;
    return Ctor;
  }

  async function startCall() {
    try {
      setPhase('connecting');
      setLog([]);
      push('[init]  compiling handshake …');
      const res = await fetch('/api/retell-token', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(form),
      });
      if (!res.ok) {
        const t = await res.text();
        throw new Error('token·error · ' + t.slice(0, 160));
      }
      const { access_token } = await res.json();
      push('[ok]    token · received', 'accent');
      push('[init]  loading voice·client …');

      const RetellWebClient = await loadSDK();
      const client = new RetellWebClient();
      clientRef.current = client;

      client.on('call_started', () => { push('[live]  channel · open', 'accent'); setPhase('live'); });
      client.on('call_ended',   () => { push('[end]   channel · closed'); setPhase('ended'); });
      client.on('error', (e) => { push('[err]   ' + (e?.message || 'unknown'), 'err'); setErr(String(e?.message || e)); setPhase('error'); });
      client.on('update', (u) => {
        if (u?.transcript && Array.isArray(u.transcript)) {
          // Retell sends the FULL transcript array on every update. Replace any
          // existing transcript lines (tone === 'agent'/'you') in the log with the
          // current turn-by-turn state, preserving the [init]/[ok]/[live] system lines.
          setLog((prev) => {
            const sysLines = prev.filter((l) => l.tone !== 'agent' && l.tone !== 'you');
            const turnLines = u.transcript
              .filter((t) => t && t.content)
              .map((t) => {
                const who = t.role === 'agent' ? 'agent' : 'you';
                return { line: `${who}: ${t.content}`, tone: who };
              });
            return [...sysLines, ...turnLines];
          });
        }
      });

      push('[tx]    starting web·call …');
      await client.startCall({ accessToken: access_token });
    } catch (e) {
      setErr(e.message || String(e));
      push('[err]   ' + (e.message || String(e)), 'err');
      setPhase('error');
    }
  }

  function endCall() {
    try { clientRef.current?.stopCall(); } catch {}
    setPhase('ended');
  }

  function close() {
    try { clientRef.current?.stopCall(); } catch {}
    setOpen(false);
    setPhase('idle');
  }

  if (!open) return null;

  const dur = `${String(Math.floor(elapsed / 60)).padStart(2, '0')}:${String(elapsed % 60).padStart(2, '0')}`;

  return (
    <div className="call-overlay" onClick={close}>
      <div className="call-modal" onClick={(e) => e.stopPropagation()}>
        <div className="call-modal__top">
          <div className="mono upper">
            <span className="dot-live" /> SECURE·VOICE·CHANNEL
          </div>
          <button className="call-close" onClick={close}>×</button>
        </div>

        {phase === 'prompt' && (
          <div className="call-body">
            <p className="call-blurb dim">
              You're about to talk to an AI agent that will scope what you want to build.
              It records + transcribes. Click CONNECT when ready.
            </p>
            <label className="field">
              <span className="field-label mono upper dim">name · optional</span>
              <input className="field-input mono" value={form.name}
                onChange={(e) => setForm({ ...form, name: e.target.value })} placeholder="operator" />
            </label>
            <label className="field">
              <span className="field-label mono upper dim">email · optional</span>
              <input className="field-input mono" value={form.email}
                onChange={(e) => setForm({ ...form, email: e.target.value })} placeholder="you@domain" />
            </label>
            <button className="cta" onClick={startCall}>&gt;_ CONNECT <span className="cta-arrow">→</span></button>
            <div className="mono dim call-mic-note">· requires microphone access</div>
          </div>
        )}

        {(phase === 'connecting' || phase === 'live' || phase === 'ended' || phase === 'error') && (
          <div className="call-body">
            <div className="call-status mono upper">
              {phase === 'connecting' && <><span className="blink">▌</span> CONNECTING …</>}
              {phase === 'live' && <><span className="dot-live" /> LIVE · {dur}</>}
              {phase === 'ended' && <>CHANNEL · CLOSED</>}
              {phase === 'error' && <>SIGNAL · LOST</>}
            </div>
            <div className="form-log mono call-log">
              {log.map((l, i) => {
                const cls =
                  l.tone === 'agent' ? 'accent' :
                  l.tone === 'you' ? '' :
                  l.tone === 'accent' ? 'accent' :
                  l.tone === 'err' ? 'err' :
                  l.tone === 'fg' ? '' :
                  'dim';
                return <div key={i} className={cls}>{l.line}</div>;
              })}
              {phase === 'live' && <div className="waveform"><span /><span /><span /><span /><span /><span /></div>}
            </div>
            <div className="call-actions">
              {phase === 'live' && (
                <button className="cta cta--ghost" onClick={endCall}>END CALL</button>
              )}
              {(phase === 'ended' || phase === 'error') && (
                <>
                  <button className="cta" onClick={() => setPhase('prompt')}>RECONNECT</button>
                  <button className="cta cta--ghost" onClick={close}>CLOSE</button>
                </>
              )}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

window.RetellCallOverlay = RetellCallOverlay;
