// outreach-track-today.jsx — Outreach › Today.
// The daily driver: who's due, exactly what to say, the date. Each touch has an
// Email and a Text version (Text = LinkedIn / SMS / WeChat) — toggle between them.
// Mark sent advances; Draft with AI rewrites one message; click the name for the
// full plan on the profile.
const { useState: useStateTT, useEffect: useEffectTT } = React;
const RStt = window.RaiseShell;

function ttDate(s) { try { return new Date(s + 'T00:00:00').toLocaleDateString(undefined, { month: 'short', day: 'numeric' }); } catch (e) { return s; } }
function ttDays(s) { try { const d = new Date(s + 'T00:00:00'); const t = new Date(); t.setHours(0, 0, 0, 0); return Math.round((d - t) / 86400000); } catch (e) { return 0; } }
function ttOpen(id) { try { if (window.RaiseStore && window.RaiseStore.openPerson) window.RaiseStore.openPerson(id, 'track'); } catch (e) {} }
function ttMsg(t, ch) { return (window.OXTrack && window.OXTrack.msgOf) ? window.OXTrack.msgOf(t, ch) : (t.email || t.message || t.text || ''); }

function TodayCard({ d, active, onSelect }) {
  const LD = window.RaiseLiveData, R = window.RAISE, t = d.touch;
  const [ch, setCh] = useStateTT(t.channel === 'text' ? 'text' : 'email');
  const [busy, setBusy] = useStateTT(false);
  const [aiBusy, setAiBusy] = useStateTT(false);
  const m = R.icpMeta ? R.icpMeta(d.icpKey) : null;
  const dd = ttDays(t.target_date);
  const drafting = t.status === 'drafting';
  const aiDynamic = !!(window.RaiseAI && window.RaiseAI.isDynamic());
  const msg = ttMsg(t, ch);
  const [draft, setDraft] = useStateTT(msg);
  const [dirty, setDirty] = useStateTT(false);
  useEffectTT(() => { setDraft(ttMsg(t, ch)); setDirty(false); }, [ch, t.email, t.text, t.seq]);

  const flush = async () => { if (dirty && draft !== ttMsg(t, ch)) { await LD.patchTouch(d.contactId, t.seq, { [ch]: draft }); setDirty(false); } };
  const markSent = async () => { setBusy(true); if (dirty && draft !== ttMsg(t, ch)) await LD.patchTouch(d.contactId, t.seq, { [ch]: draft }); const r = await LD.logTouch(d.contactId, t.seq, { channel: ch, body: draft }); setBusy(false); setDirty(false); RStt.toast(r && r.ok ? 'Sent — saved exactly what you sent' : 'Failed'); };
  const skip = async () => { setBusy(true); const r = await LD.skipTouch(d.contactId, t.seq); setBusy(false); RStt.toast(r && r.ok ? 'Skipped — logged' : 'Failed'); };
  const draftAi = async () => {
    const AI = window.RaiseAI;
    if (AI && AI.isDynamic()) {
      // DYNAMIC: live rewrite via OpenRouter. Follows the locked outreach heuristic —
      // the edge fn's rewrite_outreach task embeds the voice spec + KLT touch arc, and
      // we pass the touch's step intent (t.label) so it drafts the right stage.
      setAiBusy(true);
      try {
        const c = R.contactById ? R.contactById(d.contactId) : null;
        const channel = ch === 'email' ? 'email' : 'linkedin';
        const ctx = { channel, stepIntent: t.label || '', touch: t.seq, recipient: d.name || '',
          relationship: (c && (c.relationship || c.warmth)) || '' };
        // pull the freshest profile from the live cache (raw LinkedIn intel + the purpose-built outreach brief)
        const full = (LD && LD._cache) ? LD._cache.find((x) => x.id === d.contactId) : null;
        const intel = (c && (c.intel || c.profile)) || (full && full.intel); if (intel) ctx.intel = intel;
        const brief = (c && c.intelBrief) || (full && full.intelBrief); if (brief) ctx.brief = brief;
        const fn = (c && c.firstName) || (full && full.firstName); if (fn) ctx.firstName = String(fn).trim();
        // give touch (touch 2): feed the APPROVED toolbox give so the model uses it and never invents one
        if (/give/i.test(t.label || '')) {
          try { if (LD && LD.gives && !LD._givesOk && LD.loadGives) await LD.loadGives(); } catch (e) {}
          const g = (LD && LD.approvedGiveFor) ? LD.approvedGiveFor(d.icpKey || (c && c.icp)) : null;
          if (g) ctx.give = { title: g.title, source: g.source, url: g.url, hook: g.hook };
          else RStt.toast('No approved give yet — approve one in the Toolbox so it won’t invent content');
        }
        const base = (draft && draft.trim()) ? draft : ttMsg(t, ch);
        const out = await AI.rewrite(base, { task: 'rewrite_outreach', context: ctx });
        setDraft(out); setDirty(true);
        await LD.patchTouch(d.contactId, t.seq, { [ch]: out, status: 'active' });   // also clears any stuck 'drafting'
        RStt.toast('Rewritten — review, then Mark sent');
      } catch (e) {
        const m2 = (e && e.message) || 'error';
        RStt.toast('Rewrite failed — ' + (m2 === 'llm_not_configured' ? 'add OpenRouter key' : m2 === 'provider_error' ? 'check your OpenRouter credit' : m2));
      }
      setAiBusy(false);
    } else {
      // CLAUDE OVERNIGHT: queue a token-free draft (filled by a scheduled session)
      setBusy(true);
      const r = await LD.requestAiDraft(d.contactId, t.seq);
      setBusy(false);
      RStt.toast(r && r.ok ? 'Queued an AI draft — fills in overnight' : 'Failed');
    }
  };
  const copy = () => { try { navigator.clipboard.writeText(draft); RStt.toast('Copied ' + (ch === 'text' ? 'text' : 'email')); } catch (e) {} };

  return (
    <div className={'t2-card' + (d.overdue ? ' over' : '') + (active ? ' sel' : '')} onClick={() => onSelect && onSelect(d.contactId)}>
      <div className="t2-row">
        <span className="t2-name" onClick={(e) => { e.stopPropagation(); ttOpen(d.contactId); }}>{d.name}</span>
        {d.firm && <span className="t2-firm">{d.firm}</span>}
        {m && <span className="t2-icp" style={{ background: m.tint, color: m.color }}>{m.short}</span>}
        <span className="t2-step mono">{t.label} · {t.seq}/{d.total}</span>
        <span className={'t2-when mono' + (d.overdue ? ' over' : '')}>{d.overdue ? ('overdue ' + Math.abs(dd) + 'd') : (dd === 0 ? 'today' : ttDate(t.target_date))}</span>
      </div>
      <div className="t2-chtog">
        <button className={'t2-chbtn' + (ch === 'email' ? ' on' : '')} onClick={() => setCh('email')}>Email</button>
        <button className={'t2-chbtn' + (ch === 'text' ? ' on' : '')} onClick={() => setCh('text')}>Text</button>
        <span className="t2-chnote">Text = LinkedIn · SMS · WeChat</span>
      </div>
      {drafting
        ? <div className="t2-msg"><span className="t2-drafting">Drafting with AI…</span></div>
        : <textarea className="t2-msg" value={draft}
            onChange={(e) => { setDraft(e.target.value); setDirty(true); }}
            onBlur={flush} onClick={(e) => e.stopPropagation()}
            rows={Math.min(12, Math.max(3, (draft || '').split('\n').length + 1))}
            style={{ width: '100%', resize: 'vertical', font: 'inherit', lineHeight: 1.5, color: 'var(--ink)', background: 'var(--surface,#fff)', border: '1px solid var(--line,#e7e2d7)', borderRadius: '0 8px 8px 8px', padding: '8px 10px', boxSizing: 'border-box', position: 'relative', zIndex: 1 }} />}
      {dirty && <div style={{ fontSize: 11, color: 'var(--ink-3)', margin: '2px 2px 0' }}>edited — "Mark sent" saves this version</div>}
      <div className="t2-acts">
        <button className="btn sm" onClick={() => ttOpen(d.contactId)}>Profile</button>
        <button className="btn sm" disabled={busy || aiBusy || (drafting && !aiDynamic)} onClick={draftAi}>{aiBusy ? 'Rewriting…' : 'Rewrite'}</button>
        <button className="btn sm" disabled={busy} onClick={skip}>Skip</button>
        <button className="btn sm" style={{ marginLeft: 'auto' }} onClick={copy}>Copy</button>
        <button className="btn primary sm" disabled={busy} onClick={markSent}>Mark sent →</button>
      </div>
    </div>
  );
}

function OXToday() {
  const LD = window.RaiseLiveData;
  const [, bump] = useStateTT(0);
  useEffectTT(() => {
    const h = () => bump(x => x + 1);
    window.addEventListener('raise-livedata', h);
    if (LD && !LD.isTracksLive()) LD.loadTracks();
    if (LD && !LD.isSequenceTemplatesLive()) LD.loadSequenceTemplates();
    return () => window.removeEventListener('raise-livedata', h);
  }, []);
  const [win, setWin] = useStateTT(0);   // default: only what's due now (today + overdue)
  const due = (LD && LD.dueTouches) ? LD.dueTouches(win) : [];
  const [selected, setSelected] = useStateTT(null);
  // keep a valid selection as the due list changes (defaults to the first card)
  useEffectTT(() => {
    if (!selected || !due.some(d => d.contactId === selected)) setSelected(due[0] ? due[0].contactId : null);
  }, [due.map(d => d.contactId).join(',')]);

  return (
    <div className="today2-split">
      <div className="today2 scroll">
        <div className="t2-hd">
          <span className="t2-t">Due now</span>
          <span className="t2-c">{due.length}</span>
          <div className="t2-win">{[['Now', 0], ['7d', 7], ['14d', 14], ['30d', 30]].map(([lbl, w]) => <button key={w} className={'t2w' + (win === w ? ' on' : '')} onClick={() => setWin(w)}>{lbl}</button>)}</div>
        </div>
        {due.length === 0
          ? <div className="t2-empty">{win === 0
              ? 'Nothing due now — you’re cleared for today. Tap 7d / 14d / 30d to look ahead.'
              : ('Nothing due in the next ' + win + ' days. Classify a contact (set ICP + Tier in the pipeline) to start a sequence, or widen the window.')}</div>
          : due.map(d => <TodayCard key={d.contactId + d.touch.seq} d={d} active={selected === d.contactId} onSelect={setSelected} />)}
      </div>
      <div className="t2-profile">
        {window.OXProfilePane ? <window.OXProfilePane cid={selected} /> : null}
      </div>
    </div>
  );
}

window.OXToday = OXToday;
