'use client'

import { useEffect, useState } from 'react'
import { useRouter } from 'next/navigation'
import { toast } from 'sonner'
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { CARRIER_LEAD_TYPES, CARRIER_LEAD_TYPE_LABELS, LEAD_STAGES, LEAD_STAGE_LABELS, describeSegment, filtersToParams, type SegmentFilters } from '@/lib/domain/broker-leads'
import type { BrokerageRollup, LeadDetail, LeadRow, LeadSegment, LeadTemplate, LeadsPage, LeadsSummary } from '@/lib/data/broker-leads'
import { BTN, BTN_DANGER, BTN_SOFT, CARD, INPUT, Pill, StagePill, call, fmtDate, fmtDateTime, reason } from './shared'
import { useLeadKind } from './kind-context'

/* ------------------------------------------------------------ filters */

function FilterBar({ filters, states, segments, rollups, summary, filteredSummary, total }: { filters: SegmentFilters; states: string[]; segments: LeadSegment[]; rollups: BrokerageRollup[]; summary: LeadsSummary; filteredSummary: LeadsSummary; total: number }) {
  const cfg = useLeadKind()
  const carrier = cfg.kind === 'carrier'
  const router = useRouter()
  const [f, setF] = useState<SegmentFilters>(filters)
  const [saveOpen, setSaveOpen] = useState(false)
  const [segName, setSegName] = useState('')
  const apply = (next: SegmentFilters) => { setF(next); router.push(`${cfg.path}?tab=leads&${filtersToParams(next)}`) }
  const toggle = <K extends keyof SegmentFilters>(key: K, value: string) => {
    const cur = (f[key] as string[] | undefined) ?? []
    const next = cur.includes(value) ? cur.filter((v) => v !== value) : [...cur, value]
    apply({ ...f, [key]: next.length ? next : undefined })
  }
  async function saveSegment() {
    try {
      await call(`${cfg.apiBase}/segments`, { op: 'save', name: segName, filters: f })
      toast.success(`Segment "${segName}" saved.`)
      setSaveOpen(false); setSegName('')
      router.refresh()
    } catch (e) { toast.error(e instanceof Error ? e.message : 'Could not save.') }
  }
  const active = Object.keys(f).length > 0
  return (
    <div className={CARD}>
      <div className="flex flex-wrap items-end gap-2">
        <label className="text-xs font-semibold text-neutral-600">Search<input className={`${INPUT} mt-1 block w-56`} placeholder={carrier ? 'name, email, company' : 'name, email, brokerage, MC'} defaultValue={f.q ?? ''} onKeyDown={(e) => { if (e.key === 'Enter') apply({ ...f, q: (e.target as HTMLInputElement).value.trim() || undefined }) }} /></label>
        <label className="text-xs font-semibold text-neutral-600">{carrier ? 'Company' : 'Brokerage'}<select className={`${INPUT} mt-1 block w-56`} value={f.brokerage_id ?? ''} onChange={(e) => apply({ ...f, brokerage_id: e.target.value || undefined })}><option value="">All</option>{rollups.filter((r) => r.total > 0).map((r) => <option key={r.id} value={r.id}>{r.name} ({r.total})</option>)}</select></label>
        {!carrier && <label className="text-xs font-semibold text-neutral-600">State<select className={`${INPUT} mt-1 block w-24`} value="" onChange={(e) => e.target.value && toggle('states', e.target.value)}><option value="">+ add</option>{states.map((s) => <option key={s} value={s}>{s}</option>)}</select></label>}
        {!carrier && <label className="text-xs font-semibold text-neutral-600">Active since<input type="date" className={`${INPUT} mt-1 block`} value={f.last_seen_after ?? ''} onChange={(e) => apply({ ...f, last_seen_after: e.target.value || undefined })} /></label>}
        <label className="text-xs font-semibold text-neutral-600">Saved segment<select className={`${INPUT} mt-1 block w-48`} value="" onChange={(e) => { const s = segments.find((x) => x.id === e.target.value); if (s) apply(s.filters) }}><option value="">Pick…</option>{segments.map((s) => <option key={s.id} value={s.id}>{s.name}</option>)}</select></label>
        {active && <button onClick={() => setSaveOpen(true)} className={BTN_SOFT}>Save as segment</button>}
        {active && <button onClick={() => apply({})} className={BTN_SOFT}>Clear</button>}
        <a href={`${cfg.apiBase}/leads?export=1&${filtersToParams(f)}`} className={`${BTN_SOFT} ml-auto`}>Export CSV ({total})</a>
      </div>
      <div className="mt-3 flex flex-wrap gap-1.5">
        {LEAD_STAGES.map((s) => (
          <button key={s} onClick={() => toggle('stages', s)} className={`rounded-full border px-2 py-0.5 text-[11px] font-semibold ${f.stages?.includes(s) ? 'border-[#0f1b2d] bg-[#0f1b2d] text-white' : 'bg-white text-neutral-600 hover:bg-neutral-50'}`}>{LEAD_STAGE_LABELS[s]} <span className="opacity-60">{summary.stages[s]}</span></button>
        ))}
      </div>
      <div className="mt-2 flex flex-wrap gap-1.5 text-[11px]">
        {carrier && CARRIER_LEAD_TYPES.map((t) => <button key={t} onClick={() => toggle('lead_type', t)} className={`rounded-full border px-2 py-0.5 font-semibold ${f.lead_type?.includes(t) ? 'border-[#0f1b2d] bg-[#0f1b2d] text-white' : 'bg-white text-neutral-600'}`}>{CARRIER_LEAD_TYPE_LABELS[t]}</button>)}
        {carrier && <button onClick={() => apply({ ...f, source_active: f.source_active ? undefined : true })} className={`rounded-full border px-2 py-0.5 font-semibold ${f.source_active ? 'border-[#0f1b2d] bg-[#0f1b2d] text-white' : 'bg-white text-neutral-600'}`}>Still active in Synchron</button>}
        {!carrier && (['matches_brokerage', 'differs_from_brokerage', 'brokerage_email_unknown'] as const).map((d) => <button key={d} onClick={() => toggle('domain_check', d)} className={`rounded-full border px-2 py-0.5 font-semibold ${f.domain_check?.includes(d) ? 'border-[#0f1b2d] bg-[#0f1b2d] text-white' : 'bg-white text-neutral-600'}`}>{{ matches_brokerage: 'Email matches brokerage', differs_from_brokerage: 'Email differs', brokerage_email_unknown: 'Brokerage email unknown' }[d]}</button>)}
        {(['person', 'role'] as const).map((m) => <button key={m} onClick={() => toggle('mailbox_type', m)} className={`rounded-full border px-2 py-0.5 font-semibold ${f.mailbox_type?.includes(m) ? 'border-[#0f1b2d] bg-[#0f1b2d] text-white' : 'bg-white text-neutral-600'}`}>{m === 'person' ? 'People' : 'Role mailboxes (info@…)'}</button>)}
        {!carrier && <button onClick={() => apply({ ...f, has_last_name: f.has_last_name ? undefined : true })} className={`rounded-full border px-2 py-0.5 font-semibold ${f.has_last_name ? 'border-[#0f1b2d] bg-[#0f1b2d] text-white' : 'bg-white text-neutral-600'}`}>Has last name</button>}
        <button onClick={() => apply({ ...f, never_emailed: f.never_emailed ? undefined : true })} className={`rounded-full border px-2 py-0.5 font-semibold ${f.never_emailed ? 'border-[#0f1b2d] bg-[#0f1b2d] text-white' : 'bg-white text-neutral-600'}`}>Never emailed</button>
        {(f.states ?? []).map((s) => <button key={s} onClick={() => toggle('states', s)} className="rounded-full border border-[#0f1b2d] bg-[#0f1b2d] px-2 py-0.5 font-semibold text-white">{s} ×</button>)}
        {(f.tags ?? []).map((t) => <button key={t} onClick={() => toggle('tags', t)} className="rounded-full border border-[#0f1b2d] bg-[#0f1b2d] px-2 py-0.5 font-semibold text-white">#{t} ×</button>)}
        {summary.tags.slice(0, 12).filter(([t]) => !(f.tags ?? []).includes(t)).map(([t, n]) => <button key={t} onClick={() => toggle('tags', t)} className="rounded-full border bg-white px-2 py-0.5 font-semibold text-neutral-600">#{t} <span className="opacity-60">{n}</span></button>)}
      </div>
      <p className="mt-2 text-xs text-neutral-500">Showing <span className="font-semibold">{total}</span> — {describeSegment(f)}{active ? ` · ${filteredSummary.stages.not_invited} not invited, ${filteredSummary.stages.converted} ${carrier ? 'active users' : 'confirmed'}` : ''}</p>
      <Dialog open={saveOpen} onOpenChange={setSaveOpen}>
        <DialogContent className="sm:max-w-md">
          <DialogHeader><DialogTitle>Save this segment</DialogTitle><DialogDescription>{describeSegment(f)} — {total} leads today; the segment re-evaluates every time it is used.</DialogDescription></DialogHeader>
          <input className={INPUT} placeholder="e.g. Recent, domain-matched, TX" value={segName} onChange={(e) => setSegName(e.target.value)} />
          <DialogFooter><button onClick={() => setSaveOpen(false)} className={BTN_SOFT}>Cancel</button><button onClick={saveSegment} disabled={!segName.trim()} className={BTN}>Save</button></DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  )
}

/* ------------------------------------------------------------- table */

export function LeadsTab({ leads, filters, sort, filteredSummary, summary, states, segments, templates, rollups }: { leads: LeadsPage; filters: SegmentFilters; sort: string; filteredSummary: LeadsSummary; summary: LeadsSummary; states: string[]; segments: LeadSegment[]; templates: LeadTemplate[]; rollups: BrokerageRollup[] }) {
  const cfg = useLeadKind()
  const carrier = cfg.kind === 'carrier'
  const router = useRouter()
  const [selected, setSelected] = useState<Set<string>>(new Set())
  const [open, setOpen] = useState<string | null>(null)
  const [invite, setInvite] = useState(false)
  const [tagOpen, setTagOpen] = useState(false)
  const [tag, setTag] = useState('')
  const [busy, setBusy] = useState(false)
  const allOnPage = leads.rows.every((r) => selected.has(r.id)) && leads.rows.length > 0
  const toggleAll = () => setSelected(allOnPage ? new Set([...selected].filter((id) => !leads.rows.some((r) => r.id === id))) : new Set([...selected, ...leads.rows.map((r) => r.id)]))
  const pageUrl = (p: number) => `${cfg.path}?tab=leads&${filtersToParams(filters)}&page=${p}&sort=${sort}`
  async function bulkTag(action: 'add' | 'remove') {
    setBusy(true)
    try { const r = await call<{ changed: number }>(`${cfg.apiBase}/leads`, { op: 'tag', ids: [...selected], tag, action }); toast.success(`${r.changed} lead${r.changed === 1 ? '' : 's'} ${action === 'add' ? 'tagged' : 'untagged'} #${tag.trim().toLowerCase()}.`); setTagOpen(false); router.refresh() } catch (e) { toast.error(e instanceof Error ? e.message : 'Failed.') } finally { setBusy(false) }
  }
  return (
    <div className="space-y-4">
      <FilterBar key={filtersToParams(filters)} filters={filters} states={states} segments={segments} rollups={rollups} summary={summary} filteredSummary={filteredSummary} total={leads.total} />
      <div className="flex flex-wrap items-center gap-2 text-xs">
        <span className="font-semibold">{selected.size} selected</span>
        <button disabled={!selected.size} onClick={() => setInvite(true)} className={BTN}>Invite now…</button>
        <button disabled={!selected.size} onClick={() => setTagOpen(true)} className={BTN_SOFT}>Tag…</button>
        <button disabled={!selected.size} onClick={() => setSelected(new Set())} className={BTN_SOFT}>Clear selection</button>
        <span className="ml-auto text-neutral-500">Sort</span>
        <select className={INPUT} value={sort} onChange={(e) => router.push(`${cfg.path}?tab=leads&${filtersToParams(filters)}&sort=${e.target.value}`)}><option value="brokerage">{carrier ? 'Company' : 'Brokerage'}</option><option value="name">Name</option><option value="activity">Last activity</option></select>
      </div>
      <div className="overflow-x-auto rounded-2xl border bg-white">
        <table className="w-full text-left text-sm">
          <thead className="bg-neutral-50 text-[11px] uppercase tracking-wide text-neutral-500">
            <tr>
              <th className="px-3 py-2"><input type="checkbox" checked={allOnPage} onChange={toggleAll} /></th>
              <th className="px-3 py-2">{carrier ? 'Person' : 'Freight broker'}</th><th className="px-3 py-2">{carrier ? 'Company' : 'Brokerage'}</th><th className="px-3 py-2">{carrier ? 'Type' : 'State'}</th><th className="px-3 py-2">Stage</th><th className="px-3 py-2">Emails</th><th className="px-3 py-2">Last activity</th><th className="px-3 py-2">Source</th>
            </tr>
          </thead>
          <tbody className="divide-y">
            {leads.rows.map((l) => (
              <tr key={l.id} className="hover:bg-neutral-50">
                <td className="px-3 py-2"><input type="checkbox" checked={selected.has(l.id)} onChange={() => { const n = new Set(selected); if (n.has(l.id)) n.delete(l.id); else n.add(l.id); setSelected(n) }} /></td>
                <td className="px-3 py-2"><button onClick={() => setOpen(l.id)} className="text-left"><span className="font-semibold">{[l.first_name, l.last_name].filter(Boolean).join(' ') || <span className="italic text-neutral-400">no name</span>}</span><br /><span className="text-xs text-neutral-500">{l.email}</span></button>{l.mailbox_type === 'role' && <span className="ml-1 text-[10px] text-neutral-400">role mailbox</span>}</td>
                <td className="px-3 py-2 text-xs">{l.brokerage_name ?? '—'}{l.mc_number && <span className="text-neutral-400"> · MC {l.mc_number}</span>}{l.email_domain_check === 'differs_from_brokerage' && <span className="ml-1 text-[10px] text-amber-700">email domain differs</span>}</td>
                <td className="px-3 py-2 text-xs">{carrier ? (l.lead_type ? CARRIER_LEAD_TYPE_LABELS[l.lead_type] : '—') : (l.state ?? '—')}</td>
                <td className="px-3 py-2"><StagePill stage={l.stage} /></td>
                <td className="px-3 py-2 text-xs">{l.emails_sent}</td>
                <td className="px-3 py-2 text-xs">{fmtDate(l.last_clicked_at ?? l.last_opened_at ?? l.last_emailed_at ?? l.signed_up_at)}</td>
                <td className="px-3 py-2 text-[11px] text-neutral-500">{l.source_system ?? l.import_batch ?? '—'}{l.source_last_seen_at ? ` · seen ${l.source_last_seen_at.slice(0, 7)}` : ''}{l.tags.length ? <><br />{l.tags.map((t) => `#${t}`).join(' ')}</> : null}</td>
              </tr>
            ))}
            {leads.rows.length === 0 && <tr><td colSpan={8} className="px-3 py-8 text-center text-sm text-neutral-500">No leads match.</td></tr>}
          </tbody>
        </table>
      </div>
      <div className="flex items-center justify-between text-xs text-neutral-500">
        <span>Page {leads.page} of {leads.pages} · {leads.total} leads</span>
        <span className="flex gap-2">{leads.page > 1 && <a className={BTN_SOFT} href={pageUrl(leads.page - 1)}>Previous</a>}{leads.page < leads.pages && <a className={BTN_SOFT} href={pageUrl(leads.page + 1)}>Next</a>}</span>
      </div>
      {open && <LeadDrawer id={open} templates={templates} onClose={() => setOpen(null)} />}
      <InviteNowDialog open={invite} ids={[...selected]} templates={templates} onClose={() => setInvite(false)} onDone={() => { setSelected(new Set()); router.refresh() }} />
      <Dialog open={tagOpen} onOpenChange={setTagOpen}>
        <DialogContent className="sm:max-w-sm">
          <DialogHeader><DialogTitle>Tag {selected.size} lead{selected.size === 1 ? '' : 's'}</DialogTitle><DialogDescription>Tags are free words: wave-1, priority, texas-push. Filter and build campaigns on them.</DialogDescription></DialogHeader>
          <input className={INPUT} placeholder="tag" value={tag} onChange={(e) => setTag(e.target.value)} />
          <DialogFooter><button onClick={() => bulkTag('remove')} disabled={busy || !tag.trim()} className={BTN_SOFT}>Remove tag</button><button onClick={() => bulkTag('add')} disabled={busy || !tag.trim()} className={BTN}>Add tag</button></DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  )
}

/* -------------------------------------------------------- invite now */

function InviteNowDialog({ open, ids, templates, onClose, onDone }: { open: boolean; ids: string[]; templates: LeadTemplate[]; onClose: () => void; onDone: () => void }) {
  const cfg = useLeadKind()
  const active = templates.filter((t) => t.active)
  const [template, setTemplate] = useState(active[0]?.key ?? '')
  const [limit, setLimit] = useState(50)
  const [busy, setBusy] = useState(false)
  async function send() {
    setBusy(true)
    try {
      const r = await call<{ sent: number; recorded: number; blocked: number; suppressed: number; failed: number; capped: number }>(`${cfg.apiBase}/leads`, { op: 'invite_now', ids, template_key: template, limit })
      toast.success(`${r.sent} sent${r.recorded ? `, ${r.recorded} recorded (demo addresses)` : ''}${r.blocked ? `, ${r.blocked} blocked` : ''}${r.suppressed ? `, ${r.suppressed} suppressed` : ''}${r.failed ? `, ${r.failed} failed` : ''}${r.capped ? `, ${r.capped} over the limit` : ''}.`)
      onClose(); onDone()
    } catch (e) { toast.error(e instanceof Error ? e.message : 'Could not send.') } finally { setBusy(false) }
  }
  return (
    <Dialog open={open} onOpenChange={(o) => !o && onClose()}>
      <DialogContent className="sm:max-w-md">
        <DialogHeader><DialogTitle>Invite {ids.length} lead{ids.length === 1 ? '' : 's'} now</DialogTitle><DialogDescription>Sends the chosen template immediately from the updates stream, with each lead&apos;s personal join link. Leads that are converted, unsubscribed, bounced, suppressed, in review, or emailed within the frequency cap are skipped. For anything bigger or staged, use a campaign.</DialogDescription></DialogHeader>
        <label className="text-xs font-semibold text-neutral-600">Template<select className={`${INPUT} mt-1 block w-full`} value={template} onChange={(e) => setTemplate(e.target.value)}>{active.map((t) => <option key={t.key} value={t.key}>{t.name}</option>)}</select></label>
        <label className="text-xs font-semibold text-neutral-600">Send at most<input type="number" min={1} max={500} className={`${INPUT} mt-1 block w-32`} value={limit} onChange={(e) => setLimit(Number(e.target.value))} /></label>
        <DialogFooter><button onClick={onClose} className={BTN_SOFT}>Cancel</button><button onClick={send} disabled={busy || !template} className={BTN}>{busy ? 'Sending…' : 'Send now'}</button></DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

/* ------------------------------------------------------------- drawer */

const EVENT_LABELS: Record<string, string> = {
  imported: 'Imported', edited: 'Edited', note: 'Note', tagged: 'Tagged', untagged: 'Tag removed', suppressed: 'Suppressed', unsuppressed: 'Suppression lifted', review_resolved: 'Review resolved',
  enrolled: 'Enrolled in campaign', email_sent: 'Email sent', email_skipped: 'Email skipped', email_failed: 'Email failed', delivered: 'Delivered', opened: 'Opened', clicked: 'Clicked', bounced: 'Bounced', complained: 'Spam complaint', unsubscribed: 'Unsubscribed',
  join_link_opened: 'Opened join link', signed_up: 'Signed up', confirmed: 'Relation confirmed', declined: 'Relation declined', stopped: 'Campaign stopped for this lead',
}

export function LeadDrawer({ id, templates, onClose }: { id: string; templates: LeadTemplate[]; onClose: () => void }) {
  const cfg = useLeadKind()
  const router = useRouter()
  const [d, setD] = useState<LeadDetail | null>(null)
  const [edit, setEdit] = useState<{ first_name: string; last_name: string; phone: string; state: string; notes: string; tags: string } | null>(null)
  const [busy, setBusy] = useState(false)
  const load = () => fetch(`${cfg.apiBase}/leads?id=${id}`).then((r) => (r.ok ? r.json() : null)).then((j) => { if (j) setD(j) })
  useEffect(() => { let on = true; fetch(`${cfg.apiBase}/leads?id=${id}`).then((r) => (r.ok ? r.json() : null)).then((j) => { if (on && j) setD(j) }); return () => { on = false } }, [id, cfg.apiBase])
  const act = async (body: Record<string, unknown>, msg: string) => {
    setBusy(true)
    try { await call(`${cfg.apiBase}/leads`, body); toast.success(msg); await load(); router.refresh() } catch (e) { toast.error(e instanceof Error ? e.message : 'Failed.') } finally { setBusy(false) }
  }
  const l = d?.lead as LeadRow | undefined
  return (
    <Dialog open onOpenChange={(o) => !o && onClose()}>
      <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-2xl">
        {!l ? <p className="text-sm text-neutral-500">Loading…</p> : (
          <>
            <DialogHeader>
              <DialogTitle className="flex flex-wrap items-center gap-2">{[l.first_name, l.last_name].filter(Boolean).join(' ') || l.email} <StagePill stage={l.stage} /></DialogTitle>
              <DialogDescription>{l.email}{l.phone ? ` · ${l.phone}` : ''} · {l.brokerage_name ?? (l.lead_kind === 'carrier' ? 'no company' : 'no brokerage')}{l.mc_number ? ` (MC ${l.mc_number})` : ''}{l.lead_type ? ` · ${CARRIER_LEAD_TYPE_LABELS[l.lead_type]}` : ''}{l.state ? ` · ${l.state}` : ''}{l.lead_kind === 'carrier' && l.source_status_active != null ? (l.source_status_active ? ' · active in Synchron' : ' · inactive in Synchron') : ''}</DialogDescription>
            </DialogHeader>
            <div className="grid gap-3 text-xs sm:grid-cols-2">
              <div className={CARD}><p className="font-bold uppercase tracking-wide text-neutral-400">Record</p>
                <dl className="mt-1 space-y-1">
                  <div className="flex justify-between"><dt>Source</dt><dd>{l.source_system ?? l.import_batch ?? '—'}{l.source_last_seen_at ? ` · last seen ${fmtDate(l.source_last_seen_at)}` : ''}</dd></div>
                  <div className="flex justify-between"><dt>Email domain</dt><dd>{reason(l.email_domain_check) || '—'} · {l.mailbox_type}</dd></div>
                  <div className="flex justify-between"><dt>Claim</dt><dd>{l.claim_status}{l.manual_review_reason ? ` — ${l.manual_review_reason}` : ''}</dd></div>
                  <div className="flex justify-between"><dt>Invitation</dt><dd>{l.invitation_status} · {l.emails_sent} email{l.emails_sent === 1 ? '' : 's'}{l.last_emailed_at ? ` · last ${fmtDate(l.last_emailed_at)}` : ''}</dd></div>
                  <div className="flex justify-between"><dt>Signed up</dt><dd>{fmtDate(l.signed_up_at)}</dd></div>
                  <div className="flex justify-between"><dt>Confirmed</dt><dd>{fmtDate(l.confirmed_at)}</dd></div>
                  {l.suppressed_at && <div className="flex justify-between text-red-700"><dt>Suppressed</dt><dd>{fmtDate(l.suppressed_at)} · {l.suppressed_reason} · {l.suppressed_by}</dd></div>}
                  {l.tags.length > 0 && <div className="flex justify-between"><dt>Tags</dt><dd>{l.tags.map((t) => `#${t}`).join(' ')}</dd></div>}
                  {l.notes && <div><dt>Notes</dt><dd className="whitespace-pre-wrap rounded bg-neutral-50 p-2">{l.notes}</dd></div>}
                </dl>
                <div className="mt-2 flex flex-wrap gap-1.5">
                  <button onClick={() => setEdit({ first_name: l.first_name ?? '', last_name: l.last_name ?? '', phone: l.phone ?? '', state: l.state ?? '', notes: l.notes ?? '', tags: l.tags.join(', ') })} className={BTN_SOFT}>Edit</button>
                  {l.claim_status === 'manual_review' && <><button disabled={busy} onClick={() => act({ op: 'resolve_review', id: l.id, action: 'accept' }, 'Accepted — back in the pool.')} className={BTN}>Accept</button><button disabled={busy} onClick={() => act({ op: 'resolve_review', id: l.id, action: 'drop' }, 'Dropped and suppressed.')} className={BTN_DANGER}>Drop</button></>}
                  {l.suppressed_at ? <button disabled={busy} onClick={() => act({ op: 'unsuppress', id: l.id }, 'Suppression lifted.')} className={BTN_SOFT}>Lift suppression</button> : <button disabled={busy} onClick={() => { const r = prompt('Why suppress this lead? (optional)') ?? ''; void act({ op: 'suppress', id: l.id, reason: r }, 'Suppressed — no campaign will email this lead.') }} className={BTN_DANGER}>Suppress</button>}
                  {!l.suppressed_at && l.stage !== 'converted' && l.stage !== 'signed_up' && <select className={INPUT} value="" disabled={busy} onChange={(e) => e.target.value && act({ op: 'invite_now', ids: [l.id], template_key: e.target.value, limit: 1 }, 'Sent.')}><option value="">Send email…</option>{templates.filter((t) => t.active).map((t) => <option key={t.key} value={t.key}>{t.name}</option>)}</select>}
                </div>
              </div>
              <div className={CARD}><p className="font-bold uppercase tracking-wide text-neutral-400">Campaigns</p>
                {d!.campaigns.length === 0 ? <p className="mt-1 text-neutral-500">Not in any campaign.</p> : d!.campaigns.map((c) => (
                  <p key={c.campaign_id} className="mt-1"><span className="font-semibold">{c.name}</span> <Pill tone="neutral">{c.status}</Pill> — step {c.step}, {c.recipient_status}{c.scheduled_for && (c.recipient_status === 'scheduled' || c.recipient_status === 'pending') ? `, due ${fmtDateTime(c.scheduled_for)}` : ''}{c.stop_reason ? ` (${reason(c.stop_reason)})` : ''}{c.skip_reason ? ` (${reason(c.skip_reason)})` : ''} · {c.sends} sent</p>
                ))}
                <p className="mt-3 font-bold uppercase tracking-wide text-neutral-400">Messages</p>
                {d!.messages.length === 0 ? <p className="mt-1 text-neutral-500">No emails yet.</p> : d!.messages.slice(0, 8).map((m) => (
                  <p key={m.id} className="mt-1">{fmtDateTime(m.sent_at ?? m.created_at)} · <span className="font-semibold">{m.template_key}</span> · {m.status}{m.opened_at ? ' · opened' : ''}{m.clicked_at ? ' · clicked' : ''}{m.suppressed_reason ? ` (${reason(m.suppressed_reason)})` : ''}{m.error ? ` — ${m.error}` : ''}</p>
                ))}
              </div>
            </div>
            <div className={CARD}><p className="text-xs font-bold uppercase tracking-wide text-neutral-400">Timeline</p>
              <ol className="mt-2 space-y-1.5 text-xs">
                {d!.events.length === 0 && <li className="text-neutral-500">Nothing yet.</li>}
                {d!.events.map((e) => (
                  <li key={e.id} className="flex gap-2"><span className="w-36 shrink-0 text-neutral-400">{fmtDateTime(e.created_at)}</span><span><span className="font-semibold">{EVENT_LABELS[e.event_type] ?? e.event_type}</span>{e.template_key ? ` · ${e.template_key}` : ''}{e.step ? ` · step ${e.step}` : ''}{e.actor_label ? ` · by ${e.actor_label}` : ''}{e.detail?.reason ? ` · ${reason(String(e.detail.reason))}` : ''}{e.detail?.campaign ? ` · ${String(e.detail.campaign)}` : ''}{e.detail?.notes ? <span className="block whitespace-pre-wrap text-neutral-600">{String(e.detail.notes)}</span> : null}{Array.isArray(e.detail?.tags) ? ` · ${(e.detail!.tags as string[]).map((t) => `#${t}`).join(' ')}` : ''}</span></li>
                ))}
              </ol>
            </div>
            {edit && (
              <div className={CARD}>
                <p className="text-xs font-bold uppercase tracking-wide text-neutral-400">Edit lead</p>
                <div className="mt-2 grid gap-2 sm:grid-cols-2">
                  <input className={INPUT} placeholder="First name" value={edit.first_name} onChange={(e) => setEdit({ ...edit, first_name: e.target.value })} />
                  <input className={INPUT} placeholder="Last name" value={edit.last_name} onChange={(e) => setEdit({ ...edit, last_name: e.target.value })} />
                  <input className={INPUT} placeholder="Phone" value={edit.phone} onChange={(e) => setEdit({ ...edit, phone: e.target.value })} />
                  <input className={INPUT} placeholder="State (2 letters)" maxLength={2} value={edit.state} onChange={(e) => setEdit({ ...edit, state: e.target.value })} />
                  <input className={`${INPUT} sm:col-span-2`} placeholder="Tags, comma separated" value={edit.tags} onChange={(e) => setEdit({ ...edit, tags: e.target.value })} />
                  <textarea className={`${INPUT} sm:col-span-2`} rows={3} placeholder="Notes" value={edit.notes} onChange={(e) => setEdit({ ...edit, notes: e.target.value })} />
                </div>
                <div className="mt-2 flex justify-end gap-2"><button onClick={() => setEdit(null)} className={BTN_SOFT}>Cancel</button><button disabled={busy} onClick={async () => { await act({ op: 'update', id: l.id, ...edit, tags: edit.tags.split(',').map((t) => t.trim()).filter(Boolean) }, 'Lead updated.'); setEdit(null) }} className={BTN}>Save</button></div>
              </div>
            )}
          </>
        )}
      </DialogContent>
    </Dialog>
  )
}
