// Draft Review — final stage. Subject + email editable inline + copy + send-to-clipboard.
// One draft per brand. Tone is warm/friendly/consultative. Never mentions news trigger directly.

function DraftReview({ brands, selectedBrandId, onSelectBrand, onUpdateDraft, onNavigate, onToast, onGenerateDraft, onUpdateBrand, onRebuildAll, currentUser, onMoveToResearch, approvals }) {
  const [generatingId, setGeneratingId] = React.useState(null);
  const [rebuilding, setRebuilding] = React.useState(false);
  const [confirm, confirmEl] = useConfirm();

  const handleRebuildAll = async () => {
    if (!onRebuildAll || rebuilding) return;
    const ok = await confirm({
      title: 'Rebuild all drafts?',
      message: 'Every existing draft is rewritten by the AI in IPSEM’s proven partnership-proposal format (fixed intro and close, bespoke middle). This replaces the current draft text for all brands that have one, including any manual edits, and can take a few minutes.',
      confirmLabel: 'Rebuild all',
      danger: true,
    });
    if (!ok) return;
    setRebuilding(true);
    try { await onRebuildAll(); } finally { setRebuilding(false); }
  };

  const runGenerate = async (id) => {
    if (!onGenerateDraft || generatingId) return;
    setGeneratingId(id);
    onToast('Writing outreach draft…');
    try { await onGenerateDraft(id); }
    catch (e) { /* toast handled upstream */ }
    finally { setGeneratingId(null); }
  };

  // Any brand with a confirmed property (draft or not) — so brands without a
  // draft still appear, with a "Generate draft" action. Newest first (by
  // review date), matching Brand Research and Property Match.
  // Same shared test as Contacts, plus: a brand keeps its draft when its property
  // is removed (confirmMatch supports that), and draftReadyNotSent still counts
  // it. The hand-rolled version dropped those rows from this page while the
  // Dashboard tile and sidebar badge still counted them — clicking the tile
  // landed on a list that did not contain the brand. It also let held/closed
  // brands into "All", so that tab never summed to the other four.
  const draftable = brands.filter((b) =>
    !pbIsHeldOrClosed(b) && (pbConfirmed(b).length > 0 || !!b.draft));
  // Shared with Research, Match and Contacts — one filter setting for the flow.
  const f = useBrandFilters(draftable);
  // The three states a draft can be in, which are three different jobs: write
  // it, send it, or wait for a reply.
  const [gate, setGate] = usePersistentState('draft.gate', 'todo'); // todo | needs | ready | sent | all
  const counts = React.useMemo(() => {
    const c = { needs: 0, ready: 0, sent: 0 };
    draftable.forEach((b) => {
      if (needsDraft(b)) c.needs += 1;
      else if (draftReadyNotSent(b)) c.ready += 1;
      else if (draftSent(b)) c.sent += 1;
    });
    return { ...c, todo: c.needs + c.ready, all: draftable.length };
  }, [draftable]);

  const sorted = [...draftable]
    .filter((b) => {
      if (!f.matches(b)) return false;
      if (gate === 'all')   return true;
      if (gate === 'todo')  return needsDraft(b) || draftReadyNotSent(b);
      if (gate === 'needs') return needsDraft(b);
      if (gate === 'ready') return draftReadyNotSent(b);
      if (gate === 'sent')  return draftSent(b);
      return true;
    })
    // Needs-a-draft first, then ready-to-send, then sent; newest within each.
    .sort((a, b) => {
      const rank = (x) => needsDraft(x) ? 0 : draftReadyNotSent(x) ? 1 : 2;
      const ra = rank(a), rb = rank(b);
      if (ra !== rb) return ra - rb;
      // Among sent brands, most recently sent first — that is the useful order
      // when you are chasing replies.
      if (ra === 2) return String(sentInstant(b) || '').localeCompare(String(sentInstant(a) || ''));
      return (b.reviewDate || '').localeCompare(a.reviewDate || '');
    });

  const selected = brands.find((b) => b.id === selectedBrandId && draftable.some((d) => d.id === b.id)) || sorted[0];

  React.useEffect(() => {
    if (selected && (!selectedBrandId || !draftable.some((d) => d.id === selectedBrandId))) {
      onSelectBrand(selected.id);
    }
  }, []);

  if (!selected) {
    return (
      <div className="page page-cap">
        <SectionHeader
          eyebrow="Step 05 · Drafted automatically · You approve"
          title="Draft review"
          sub="Brands arrive here once you have confirmed a property for them."
        />
        <Card lg>
          <div className="empty">
            <div style={{ fontWeight: 600, color: 'var(--ink)' }}>
              {f.active ? 'No brands match these filters.' : 'Nothing to draft yet.'}
            </div>
            <div className="text-sm" style={{ marginTop: 6, maxWidth: 460, marginInline: 'auto', lineHeight: 1.6 }}>
              {f.active
                ? 'The shared tier / category / assignee / country filters are hiding every confirmed brand.'
                : 'Confirm a property match for a brand and it appears here, ready for a draft.'}
            </div>
            <div className="row gap-2" style={{ marginTop: 14, justifyContent: 'center' }}>
              {f.active ? (
                <button className="btn btn-sm btn-primary" onClick={f.clear}>Clear filters</button>
              ) : (
                <button className="btn btn-sm btn-primary" onClick={() => onNavigate('match')}>
                  Open Property Match
                  <window.I.arrowRight size={12} />
                </button>
              )}
            </div>
          </div>
        </Card>
      </div>
    );
  }

  return (
    <div className="page page-cap">
      <SectionHeader
        eyebrow="Step 05 · Drafted automatically · You approve & send"
        title="Draft review"
        sub="One draft per brand. Edits save automatically. Pick who to email in the To field, then copy and paste into your mailer."
        right={
          onRebuildAll ? (
            <button className="btn" onClick={handleRebuildAll} disabled={rebuilding} title="Regenerate every existing draft with the current template (no AI)">
              <window.I.refresh size={14} className={rebuilding ? 'spin' : ''} />
              {rebuilding ? 'Rebuilding…' : 'Rebuild all drafts'}
            </button>
          ) : null
        }
      />

      <div className="responsive-split">
        <Card pad={false} style={{ position: 'sticky', top: 80, maxHeight: 'calc(100vh - 120px)', overflowY: 'auto' }}>
          <div style={{ padding: '12px 14px', borderBottom: '1px solid var(--hairline)' }}>
            <div className="row" style={{ justifyContent: 'space-between', alignItems: 'flex-start' }}>
              <div>
                <div className="eyebrow">Drafts</div>
                <div className="text-xs text-3" style={{ marginTop: 4 }}>
                  {counts.needs} to write · {counts.ready} to send · {counts.sent} sent
                </div>
              </div>
              <button
                className="btn btn-icon btn-ghost"
                onClick={() => f.setOpen((x) => !x)}
                title="Filter brands"
                style={{ color: f.active ? 'var(--accent)' : 'var(--ink-3)' }}
              >
                <window.I.filter size={14} />
              </button>
            </div>
          </div>
          <StageFilterBar
            value={gate}
            onChange={setGate}
            options={[
              { id: 'todo',  label: 'To do',  count: counts.todo,  title: 'Everything still needing you — no draft yet, or drafted but not sent' },
              { id: 'needs', label: 'To write', count: counts.needs, title: 'A property is confirmed but no draft exists yet' },
              { id: 'ready', label: 'To send',  count: counts.ready, title: 'Draft written and not sent' },
              { id: 'sent',  label: 'Sent',     count: counts.sent,  title: 'Email confirmed sent — most recent first' },
              { id: 'all',   label: 'All',      count: counts.all },
            ]}
          />
          {f.open ? <BrandFilterPanel f={f} /> : null}
          {sorted.map((b) => {
            const isSel = selected.id === b.id;
            const propMode = b.draft?.propertyMode;
            const propCount = (b.confirmedProperties || []).filter((p) => p !== 'none').length;
            return (
              <div
                key={b.id}
                onClick={() => onSelectBrand(b.id)}
                style={{
                  padding: '12px 14px',
                  borderBottom: '1px solid var(--hairline)',
                  cursor: 'pointer',
                  background: isSel ? 'var(--accent-soft-bg)' : 'transparent',
                  borderLeft: isSel ? '3px solid var(--accent)' : '3px solid transparent',
                }}
              >
                <div className="row gap-2" style={{ alignItems: 'center' }}>
                  <BrandLogo brand={b} size={22} />
                  <span style={{ fontWeight: 600, fontSize: 13.5 }}>{b.brand}</span>
                  <span className="right">
                    <PriorityPill priority={b.priority} />
                  </span>
                </div>
                <div className="row gap-1" style={{ marginTop: 6 }}>
                  {b.draft ? (
                    <>
                      <span className="pill" style={{ background: 'var(--card-alt)', color: 'var(--ink-3)', fontSize: 10.5 }}>
                        {/* Count comes from the brand's CURRENT confirmed
                            properties, not from the mode stored on the draft.
                            The draft keeps whatever mode it was written with, so
                            changing the property selection afterwards left the
                            two disagreeing: Head & Shoulders read "1 properties",
                            and Giti Tire read "1 property" while three were
                            actually confirmed. Generic is still the draft's own
                            call — that one is a real drafting decision. */}
                        {propMode === 'generic'
                          ? 'Generic'
                          : `${propCount} ${propCount === 1 ? 'property' : 'properties'}`}
                      </span>
                      {/* "Formal" used to sit here. Every draft in the book is
                          the same house format, so the word appeared on all 260
                          rows and told you nothing. Whether the AI actually
                          wrote it does distinguish rows — 32 fell back to the
                          template because the AI was down, and those are the
                          ones worth regenerating. */}
                      {b.draft.source === 'template' ? (
                        <span className="pill" style={{ background: 'var(--card-alt)', color: 'var(--pending)', fontSize: 10.5 }}
                              title="The AI was unavailable when this was written, so the standard template was used. Regenerate for a bespoke draft.">
                          Template
                        </span>
                      ) : null}
                    </>
                  ) : (
                    <span className="pill" style={{ background: 'transparent', border: '1px solid var(--hairline-strong)', color: 'var(--pending)', fontSize: 10.5 }}>
                      No draft yet
                    </span>
                  )}
                  <BrandStatusChip brand={b} onNavigate={onNavigate} />
                </div>
                {/* When it went out. Relative ("2 days ago") because the team is
                    across three time zones; hover for the exact instant. */}
                {draftSent(b) && sentInstant(b) ? (
                  <div className="row gap-1 text-xs text-3" style={{ marginTop: 5 }}>
                    <window.I.mail size={11} stroke="var(--ink-4)" />
                    <span>Sent</span>
                    <TimeStamp iso={sentInstant(b)} className="mono" />
                  </div>
                ) : null}
              </div>
            );
          })}
          {sorted.length === 0 ? (
            <div className="empty" style={{ padding: '28px 16px' }}>
              <div>No brands match these filters.</div>
              <button className="btn btn-sm" style={{ marginTop: 10 }} onClick={f.clear}>Clear filters</button>
            </div>
          ) : null}
        </Card>

        <div className="col">
        {/* A rightsholder that refused this brand cannot be pitched on. Said
            here, before the work, rather than as a failed save afterwards. */}
        <RefusalNotice brand={selected} approvals={approvals} onNavigate={onNavigate} />
        {selected.draft ? (
          <DraftEditor
            brand={selected}
            onUpdateDraft={onUpdateDraft}
            onNavigate={onNavigate}
            onToast={onToast}
            onRegenerate={() => runGenerate(selected.id)}
            regenerating={generatingId === selected.id}
            onUpdateBrand={onUpdateBrand}
            confirm={confirm}
            currentUser={currentUser}
            onMoveToResearch={onMoveToResearch}
          />
        ) : (
          <Card lg>
            <div className="col gap-3" style={{ alignItems: 'center', textAlign: 'center', padding: '32px 16px' }}>
              {generatingId === selected.id ? (
                <>
                  <window.I.refresh size={26} className="spin" stroke="var(--accent)" />
                  <div className="h3">Writing outreach draft…</div>
                  <div className="text-2 text-sm">Short, professional, signed with your name. This takes a few seconds.</div>
                </>
              ) : (
                <>
                  <window.I.mail size={26} stroke="var(--ink-3)" />
                  <div className="h3">No draft yet for {selected.brand}</div>
                  <div className="text-2 text-sm" style={{ maxWidth: 420 }}>
                    Generate a partnership-proposal email pitching {selected.brand} as {selected.confirmedProperties.map((p) => p === 'generic' ? 'an IPSEM rightsholder' : propName(p)).join(', ')}'s Official Partner.
                    Warm, natural, UK English. Ends "Warm regards" for you to add your signature.
                  </div>
                  <button
                    className="btn btn-primary btn-lg"
                    onClick={() => runGenerate(selected.id)}
                    disabled={refusalState(selected, approvals).blocked}
                    title={refusalState(selected, approvals).blocked
                      ? 'Every property matched to this brand has refused it'
                      : undefined}
                  >
                    <window.I.sparkle size={15} />
                    Generate draft
                  </button>
                </>
              )}
            </div>
          </Card>
        )}
        </div>
      </div>
      {confirmEl}
    </div>
  );
}

function DraftEditor({ brand, onUpdateDraft, onNavigate, onToast, onRegenerate, regenerating, onUpdateBrand, confirm, currentUser, onMoveToResearch }) {
  const [subject, setSubject] = React.useState(brand.draft?.subject || '');
  const [body, setBody] = React.useState(brand.draft?.body || '');
  const [saved, setSaved] = React.useState(true);

  // Reset state when the brand OR its draft changes (e.g. after regenerate).
  React.useEffect(() => {
    setSubject(brand.draft?.subject || '');
    setBody(brand.draft?.body || '');
    setSaved(true);
  }, [brand.id, brand.draft?.generatedAt]);

  // Debounced save
  React.useEffect(() => {
    if (saved) return;
    const t = setTimeout(() => {
      onUpdateDraft(brand.id, { subject, body });
      setSaved(true);
    }, 600);
    return () => clearTimeout(t);
  }, [subject, body, saved, brand.id, onUpdateDraft]);

  const propMode = brand.draft?.propertyMode;
  const props = brand.confirmedProperties || [];

  // Picking recipients also syncs the "Dear …" salutation to their first name(s).
  const applyRecipients = (next) => {
    onUpdateDraft(brand.id, { recipients: next });
    const lines = body.split('\n');
    const idx = lines.findIndex((l) => l.trim().length > 0);
    if (idx >= 0 && /^dear\b/i.test(lines[idx].trim())) {
      lines[idx] = salutation(next);
      setBody(lines.join('\n'));
      setSaved(false);
    }
  };

  // Auto-resize textarea
  const bodyRef = React.useRef(null);
  React.useEffect(() => {
    const el = bodyRef.current;
    if (el) {
      el.style.height = 'auto';
      el.style.height = `${el.scrollHeight + 4}px`;
    }
  }, [body]);

  // ─── Outreach loop: send, follow-up, do-not-contact guards ────────────────
  const recipientNames = brand.draft?.recipients || [];
  const recipientEmails = (brand.contacts || [])
    .filter((c) => recipientNames.includes(c.name) && c.email)
    .map((c) => c.email);
  const mailtoHref = `mailto:${recipientEmails.join(',')}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;

  const dnc = !!brand.doNotContact;
  const already = brand.outreachStatus && brand.outreachStatus !== 'not_contacted';
  const isPartner = brand.contactStatus === 'established';
  const hasPlaceholders = body.includes('[YOUR NAME]') || body.includes('[YOUR POSITION]');

  const markSent = () => {
    const today = ipsemToday();
    const nowIso = new Date().toISOString();
    onUpdateBrand(brand.id, {
      outreachStatus: 'contacted',
      outreachSentDate: brand.outreachSentDate || today,
      // The exact instant, not just the office day — response times are measured
      // off this, and the team spans GMT+0, +1 and +8.
      outreachSentAt: brand.outreachSentAt || nowIso,
      outreachContact: recipientNames.join(', ') || brand.outreachContact || null,
      nextFollowUp: brand.nextFollowUp || addBusinessDays(today, 5),
      outreachHistory: [...(brand.outreachHistory || []), { action: 'sent', date: today, at: nowIso, note: `Emailed ${recipientNames.join(', ') || 'contact'}` }],
    });
  };

  // Opening the mail client is not sending. The app cannot see your outbox, so
  // it asks — otherwise a draft you opened and thought better of is recorded as
  // sent, with a timestamp that response-time reporting would then treat as real.
  const openInEmail = async () => {
    if (dnc) { onToast('This brand is marked do-not-contact.'); return; }
    if (!subject.trim()) { onToast('Add a subject line first.'); return; }
    if (!recipientEmails.length) { onToast('Pick a contact with an email in the To field first.'); return; }
    window.open(mailtoHref, '_blank');
    const sent = await confirm({
      title: `Did you send the email to ${brand.brand}?`,
      message: `Only confirm once it has actually left your outbox. Confirming records the exact send time, marks ${brand.brand} as contacted and sets a follow-up in 5 working days. If you closed the draft without sending, choose Not yet.`,
      confirmLabel: 'Yes, it is sent',
      cancelLabel: 'Not yet',
    });
    if (!sent) {
      onToast(`${brand.brand} left as not contacted — nothing recorded`);
      return;
    }
    markSent();
    onToast(`${brand.brand} marked as contacted — follow-up set for 5 working days`);
  };

  const toggleDnc = () => {
    if (dnc) { onUpdateBrand(brand.id, { doNotContact: false, dncReason: null }); onToast('Do-not-contact removed'); return; }
    const reason = window.prompt('Reason for do-not-contact (optional):', '');
    if (reason === null) return;  // cancelled
    onUpdateBrand(brand.id, { doNotContact: true, dncReason: reason.trim() || null });
    onToast(`${brand.brand} marked do-not-contact`);
  };

  return (
    <div className="col gap-3">
      {/* Context strip */}
      <Card>
        <div className="row gap-3">
          <BrandLogo brand={brand} size={38} radius={9} />
          <div className="grow">
            <div className="row gap-2">
              <span className="h3">{brand.brand}</span>
              <span className="text-3 text-sm">· {brand.category}</span>
            </div>
            <div className="text-2 text-sm" style={{ marginTop: 2 }}>
              Outreach for: {props.map((p) => p === 'generic' ? 'Generic portfolio' : propName(p)).join(', ')}
            </div>
          </div>
          <div className="col gap-2" style={{ alignItems: 'flex-end' }}>
            <div className="row gap-2">
              <button className="btn btn-sm btn-ghost" onClick={() => onNavigate('contacts', brand.id)}>
                <window.I.users size={13} />
                Contacts
              </button>
              {onUpdateBrand ? (
                <button className="btn btn-sm btn-ghost" onClick={toggleDnc} title={dnc ? 'Remove do-not-contact' : 'Mark do-not-contact'} style={{ color: dnc ? 'var(--negative)' : 'var(--ink-2)' }}>
                  <window.I.ban size={12} />
                  {dnc ? 'Undo DNC' : 'Do not contact'}
                </button>
              ) : null}
            </div>
            {onUpdateBrand ? (
              <div className="row gap-2" style={{ alignItems: 'center' }}>
                <span className="eyebrow text-xs">Follow-up</span>
                <input
                  type="date"
                  value={brand.nextFollowUp ? String(brand.nextFollowUp).slice(0, 10) : ''}
                  onChange={(e) => onUpdateBrand(brand.id, { nextFollowUp: e.target.value || null })}
                  className="field"
                  style={{ height: 28, padding: '0 6px', fontSize: 12 }}
                />
              </div>
            ) : null}
            {onUpdateBrand ? (
              <div className="row gap-2" style={{ alignItems: 'center' }}>
                <span className="eyebrow text-xs">Stage</span>
                <select
                  value={brand.outreachStatus || 'not_contacted'}
                  onChange={async (e) => {
                    const next = e.target.value;
                    if (await guardOutreachChange(brand, next, confirm)) {
                      onUpdateBrand(brand.id, { outreachStatus: next });
                    }
                  }}
                  className="field"
                  style={{ height: 28, padding: '0 6px', fontSize: 12, color: outreachMeta(brand.outreachStatus).color }}
                >
                  {OUTREACH_STAGES.map((s) => <option key={s.value} value={s.value}>{s.label}</option>)}
                </select>
              </div>
            ) : null}
          </div>
        </div>
      </Card>

      {/* Tier / status / relationship / outreach / assignee / actions — the
          same strip on every stage. */}
      <BrandControlBar
        brand={brand}
        onUpdateBrand={onUpdateBrand}
        onMoveToResearch={onMoveToResearch}
        onToast={onToast}
        currentUser={currentUser}
      />

      {/* Notes — same panel, same position as every other stage: directly under
          the brand header. Reads and writes the one shared list. */}
      {onUpdateBrand ? (
        <NotesPanel
          brand={brand}
          currentUser={currentUser}
          onUpdateBrand={onUpdateBrand}
          onToast={onToast}
        />
      ) : null}

      {/* Rules strip */}
      <div className="row gap-3" style={{ padding: '10px 16px', background: 'var(--card-alt)', borderRadius: 8, border: '1px solid var(--hairline)', flexWrap: 'wrap' }}>
        <Pill kind="muted">Tone: warm · natural · UK English</Pill>
        <Pill kind="accent">Official Partner proposal</Pill>
        <Pill kind="muted">~200-260 words</Pill>
        <Pill kind="muted">Ends "Warm regards" — add your own signature</Pill>
        <Pill kind={propMode === 'generic' ? 'accent' : 'muted'}>
          {/* Same reasoning as the list row: count from the live properties, so
              a selection changed after drafting cannot leave this contradicting
              the panel right below it. */}
          {propMode === 'generic' ? 'Generic mode: avoids property names' :
           props.length === 1 ? 'Single property' : `Multi-property: ${props.length} properties`}
        </Pill>
        {brand.draft?.source === 'template' ? (
          <Pill kind="pending" title="The AI was unavailable when this draft was written, so the standard template was used. Regenerate for a bespoke draft.">
            Template draft — regenerate for AI version
          </Pill>
        ) : null}
      </div>

      {brand.draft?.angle ? (
        <div className="row gap-2" style={{ padding: '8px 14px', alignItems: 'flex-start' }}>
          <window.I.sparkle size={12} stroke="var(--accent)" style={{ marginTop: 2, flexShrink: 0 }} />
          <span className="text-xs text-3"><strong style={{ color: 'var(--ink-2)' }}>Angle:</strong> {brand.draft.angle}</span>
        </div>
      ) : null}

      {/* Placeholder reminder */}
      {(body.includes('[YOUR NAME]') || body.includes('[YOUR POSITION]')) ? (
        <div className="row gap-2" style={{ padding: '10px 14px', background: 'var(--attention-soft)', border: '1px solid var(--attention)', borderRadius: 8, alignItems: 'center' }}>
          <window.I.warn size={14} stroke="var(--attention)" />
          <span className="text-sm" style={{ color: 'var(--ink-2)' }}>
            Before sending, replace <strong>[YOUR NAME]</strong> and <strong>[YOUR POSITION]</strong> in the introduction with your details.
          </span>
        </div>
      ) : null}

      {/* Do-not-contact / already-contacted / partner guard */}
      {dnc ? (
        <div className="row gap-2" style={{ padding: '10px 14px', background: 'var(--negative-soft)', border: '1px solid var(--negative)', borderRadius: 8, alignItems: 'center' }}>
          <window.I.ban size={14} stroke="var(--negative)" />
          <span className="text-sm" style={{ color: 'var(--ink-2)' }}>
            <strong>Do not contact.</strong>{brand.dncReason ? ` ${brand.dncReason}` : ''} Sending is disabled for this brand.
          </span>
        </div>
      ) : already ? (
        <div className="row gap-2" style={{ padding: '10px 14px', background: 'var(--attention-soft)', border: '1px solid var(--attention)', borderRadius: 8, alignItems: 'center' }}>
          <window.I.warn size={14} stroke="var(--attention)" />
          <span className="text-sm" style={{ color: 'var(--ink-2)' }}>
            Already <strong>{outreachMeta(brand.outreachStatus).label.toLowerCase()}</strong>
            {sentInstant(brand) ? (
              <> — sent <TimeStamp iso={sentInstant(brand)} className="mono" /></>
            ) : ''}
            {brand.outreachContact ? ` (${brand.outreachContact})` : ''}. Avoid duplicate outreach.
          </span>
        </div>
      ) : isPartner ? (
        <div className="row gap-2" style={{ padding: '10px 14px', background: 'var(--attention-soft)', border: '1px solid var(--attention)', borderRadius: 8, alignItems: 'center' }}>
          <window.I.warn size={14} stroke="var(--attention)" />
          <span className="text-sm" style={{ color: 'var(--ink-2)' }}>
            <strong>Existing partner.</strong> Coordinate internally before sending a cold proposal.
          </span>
        </div>
      ) : null}

      {/* Draft container */}
      <Card pad={false}>
        <div className="row" style={{ padding: '14px 18px', borderBottom: '1px solid var(--hairline)', justifyContent: 'space-between', flexWrap: 'wrap', gap: 8 }}>
          <div className="row gap-2">
            <window.I.mail size={15} stroke="var(--ink-3)" />
            <span className="h4">Email draft</span>
            <span className="text-xs text-3" style={{ marginLeft: 8 }}>
              {saved ? <span className="row gap-1"><window.I.check size={11} stroke="var(--positive)" />Saved</span> : 'Saving…'}
            </span>
          </div>
          <div className="row gap-2">
            {onRegenerate ? (
              <button className="btn btn-sm" onClick={onRegenerate} disabled={regenerating} title="Rewrite this draft from scratch">
                <window.I.refresh size={12} className={regenerating ? 'spin' : ''} />
                {regenerating ? 'Writing…' : 'Regenerate'}
              </button>
            ) : null}
            <CopyBtn text={subject} label="Subject" onToast={onToast} title="Copy the subject line" />
            <CopyBtn text={body} label="Body" onToast={onToast} title="Copy the email body" />
            <CopyBtn text={`Subject: ${subject}\n\n${body}`} label="Copy email" onToast={onToast} title="Copy subject + body together" />
            <button
              className="btn btn-sm btn-primary"
              onClick={openInEmail}
              disabled={dnc}
              title={dnc ? 'Do-not-contact — sending disabled' : 'Open in your email client (to the picked contacts) and mark as contacted'}
            >
              <window.I.mail size={12} />
              Open in email client
            </button>
          </div>
        </div>

        <div style={{ padding: '20px 28px 28px' }}>
          <div className="row gap-3" style={{ alignItems: 'center', paddingBottom: 12, borderBottom: '1px solid var(--hairline)', marginBottom: 16 }}>
            <span className="eyebrow" style={{ minWidth: 64 }}>To</span>
            <RecipientPicker
              contacts={brand.contacts || []}
              selected={brand.draft?.recipients || []}
              onChange={applyRecipients}
              onNavigate={() => onNavigate('contacts', brand.id)}
            />
          </div>

          <div className="row gap-3" style={{ alignItems: 'flex-start', paddingBottom: 16, borderBottom: '1px solid var(--hairline)', marginBottom: 20 }}>
            <span className="eyebrow" style={{ minWidth: 64, paddingTop: 6 }}>Subject</span>
            <div className="col" style={{ flex: 1, gap: 2 }}>
              <input
                value={subject}
                onChange={(e) => { setSubject(e.target.value); setSaved(false); }}
                placeholder="Subject line required before sending"
                style={{
                  fontSize: 18,
                  fontWeight: 500,
                  fontFamily: 'var(--f-display)',
                  border: 0,
                  outline: 0,
                  background: 'transparent',
                  color: 'var(--ink)',
                  padding: '4px 0',
                  lineHeight: 1.3,
                  letterSpacing: '-0.005em',
                }}
              />
              {!subject.trim() ? (
                <span className="text-xs row gap-1" style={{ color: 'var(--negative)' }}>
                  <window.I.warn size={11} />
                  Subject is empty — add one before sending.
                </span>
              ) : null}
            </div>
          </div>

          <textarea
            ref={bodyRef}
            value={body}
            onChange={(e) => { setBody(e.target.value); setSaved(false); }}
            style={{
              width: '100%',
              minHeight: 380,
              border: 0,
              outline: 0,
              background: 'transparent',
              color: 'var(--ink)',
              fontFamily: 'var(--f-sans)',
              fontSize: 15,
              lineHeight: 1.65,
              resize: 'none',
              padding: 0,
            }}
          />
        </div>
      </Card>

      {/* Outreach activity (touch history) */}
      {(brand.outreachHistory || []).length ? (
        <Card>
          <div className="eyebrow row gap-1" style={{ marginBottom: 10 }}>
            <window.I.check size={11} stroke="var(--positive)" />
            Outreach activity
            {brand.nextFollowUp ? (
              <span className="right text-xs text-3">Next follow-up {formatDate(brand.nextFollowUp)}</span>
            ) : null}
          </div>
          <div className="col gap-2">
            {[...brand.outreachHistory].reverse().map((h, i) => (
              <div key={i} className="row gap-2 text-sm" style={{ alignItems: 'baseline' }}>
                <span className="mono text-xs text-3" style={{ minWidth: 92 }}>{formatDate(h.date)}</span>
                <span className="text-2">{h.note || h.action}</span>
              </div>
            ))}
          </div>
        </Card>
      ) : null}

      {/* Help / rules */}
      <Card>
        <div className="eyebrow row gap-1" style={{ marginBottom: 8 }}>
          <window.I.info size={11} />
          Draft logic
        </div>
        <ul className="text-2 text-sm" style={{ paddingLeft: 22, margin: 0, lineHeight: 1.7 }}>
          {propMode === 'single' ? (
            <li>
              Single-property mode: explains why <strong>{propName(props[0])}</strong> is a strong fit, connecting the brand's markets, values and sponsorship behaviour to the property.
            </li>
          ) : null}
          {propMode === 'multiple' ? (
            <li>
              Multi-property mode: one combined email mentioning all selected properties — each with a clear, commercially interesting reason.
            </li>
          ) : null}
          {propMode === 'generic' ? (
            <li>
              Generic mode: avoids naming a specific property. Positions the IPSEM portfolio as broadly relevant.
            </li>
          ) : null}
          <li>Proposes the brand as the rightsholder's Official [Category] Partner, IPSEM's proven structure.</li>
          <li>Aligns the brand's real core values and geography with the rightsholder, then gives concrete activation ideas.</li>
          <li>Kept tight (~200-260 words), UK English, warm and natural, designed to entice a reply.</li>
          <li>Ends with "Warm regards" and no signature, so you add your own. No long dashes (they read as AI-written).</li>
        </ul>
      </Card>
    </div>
  );
}

// Build a salutation from the picked recipients' first names.
function salutation(names) {
  const firsts = (names || []).map((n) => (n || '').trim().split(/\s+/)[0]).filter(Boolean);
  if (!firsts.length) return 'Dear Sir or Madam,';
  if (firsts.length === 1) return `Dear ${firsts[0]},`;
  if (firsts.length === 2) return `Dear ${firsts[0]} and ${firsts[1]},`;
  return 'Dear all,';
}

// Multi-select dropdown for choosing which contact(s) to email.
function RecipientPicker({ contacts, selected, onChange, onNavigate }) {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', h);
    return () => document.removeEventListener('mousedown', h);
  }, []);
  const toggle = (name) => onChange(selected.includes(name) ? selected.filter((n) => n !== name) : [...selected, name]);
  const emailFor = (name) => (contacts.find((c) => c.name === name) || {}).email;

  return (
    <div ref={ref} style={{ position: 'relative', flex: 1, minWidth: 0 }}>
      <button
        onClick={() => setOpen((o) => !o)}
        className="field"
        style={{ width: '100%', minHeight: 36, height: 'auto', textAlign: 'left', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, padding: '6px 10px' }}
      >
        <span className="text-sm truncate" style={{ color: selected.length ? 'var(--ink)' : 'var(--ink-3)' }}>
          {selected.length ? selected.join(', ') : 'Select contact(s) to email…'}
        </span>
        <window.I.chevronDown size={14} stroke="var(--ink-3)" style={{ flexShrink: 0 }} />
      </button>
      {open ? (
        <div style={{ position: 'absolute', top: 'calc(100% + 4px)', left: 0, right: 0, zIndex: 30, background: 'var(--card)', border: '1px solid var(--hairline-strong)', borderRadius: 8, boxShadow: 'var(--shadow-lg)', maxHeight: 280, overflowY: 'auto', padding: 6 }}>
          {(contacts || []).length === 0 ? (
            <div className="col gap-2" style={{ padding: '10px 10px', alignItems: 'flex-start' }}>
              <span className="text-xs text-3">No contacts found for this brand yet.</span>
              {onNavigate ? <button className="btn btn-sm" onClick={() => { setOpen(false); onNavigate(); }}><window.I.users size={12} /> Find contacts</button> : null}
            </div>
          ) : contacts.map((c, i) => {
            const on = selected.includes(c.name);
            return (
              <div key={i} onClick={() => toggle(c.name)} className="row gap-2" style={{ padding: '7px 8px', borderRadius: 6, cursor: 'pointer', background: on ? 'var(--accent-soft-bg)' : 'transparent' }}>
                <span style={{ width: 16, height: 16, borderRadius: 4, border: '1px solid ' + (on ? 'var(--accent)' : 'var(--hairline-strong)'), background: on ? 'var(--accent)' : 'transparent', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                  {on ? <window.I.check size={11} stroke="#fff" /> : null}
                </span>
                <div className="col" style={{ gap: 0, minWidth: 0 }}>
                  <span className="text-sm" style={{ fontWeight: 500 }}>{c.name}</span>
                  <span className="text-xs text-3 truncate">{c.title}{c.email ? ` · ${c.email}` : ' · no email'}</span>
                </div>
              </div>
            );
          })}
        </div>
      ) : null}
    </div>
  );
}

window.DraftReview = DraftReview;
