// crm-marketing.jsx — Marketing: campaigns, lists, templates, suppressions.
// Admin-only (nav-gated + API-gated). The template designer lives in
// crm-marketing-builder.jsx (TemplateBuilder).

const MKT_STATUS_BADGE = {
  draft: 'badge-gray', scheduled: 'badge-blue', sending: 'badge-amber',
  paused: 'badge-amber', sent: 'badge-green', cancelled: 'badge-gray',
};

function MarketingView({ user, showToast }) {
  const { useState } = React;
  const [tab, setTab] = useState('campaigns');
  const tabs = [
    ['campaigns', '📣 Campaigns'], ['lists', '👥 Lists'],
    ['templates', '🧩 Templates'], ['suppressed', '🚫 Suppressed'], ['settings', '⚙️ Settings'],
  ];
  return (
    <div>
      <div className="tabs" style={{marginBottom:18}}>
        {tabs.map(([id, label]) => (
          <button key={id} className={'tab-btn' + (tab === id ? ' active' : '')} onClick={() => setTab(id)}>{label}</button>
        ))}
      </div>
      {tab === 'campaigns'  && <MktCampaignsTab user={user} showToast={showToast} />}
      {tab === 'lists'      && <MktListsTab showToast={showToast} />}
      {tab === 'templates'  && <MktTemplatesTab showToast={showToast} />}
      {tab === 'suppressed' && <MktSuppressedTab showToast={showToast} />}
      {tab === 'settings'   && <MktSettingsTab showToast={showToast} />}
    </div>
  );
}

// ════ CAMPAIGNS ════
function MktCampaignsTab({ user, showToast }) {
  const { useState, useEffect, useCallback } = React;
  const [campaigns, setCampaigns] = useState([]);
  const [editing, setEditing] = useState(null);      // campaign object or 'new'
  const [detailId, setDetailId] = useState(null);
  const load = useCallback(() => CRM.MarketingAPI.getCampaigns().then(setCampaigns).catch(()=>{}), []);
  useEffect(() => { load(); }, [load]);

  return (
    <div>
      <div style={{display:'flex',justifyContent:'flex-end',marginBottom:12}}>
        <button className="btn btn-primary btn-sm" onClick={() => setEditing('new')}>+ New Campaign</button>
      </div>
      {campaigns.length === 0
        ? <div className="card card-pad" style={{textAlign:'center',color:'var(--g400)',padding:40}}>
            No campaigns yet. Build a template, create a list, then launch your first campaign.
          </div>
        : <div className="card"><table className="tbl"><thead><tr>
            <th>Campaign</th><th>Status</th><th>Lists</th><th style={{textAlign:'right'}}>Sent</th>
            <th style={{textAlign:'right'}}>Opened</th><th>Created</th><th></th>
          </tr></thead><tbody>
            {campaigns.map(c => (
              <tr key={c.id} style={{cursor:'pointer'}}
                  onClick={() => c.status === 'draft' || c.status === 'scheduled' ? setEditing(c) : setDetailId(c.id)}>
                <td style={{fontWeight:600}}>{c.name}<div style={{fontWeight:400,fontSize:11,color:'var(--g400)'}}>{c.subject}</div></td>
                <td><span className={'badge ' + (MKT_STATUS_BADGE[c.status]||'badge-gray')}>{c.status}</span></td>
                <td style={{fontSize:12,color:'var(--g600)'}}>{(c.lists||[]).join(', ') || '—'}</td>
                <td style={{textAlign:'right'}}>{c.sent}{c.totalRecipients ? ' / ' + c.totalRecipients : ''}</td>
                <td style={{textAlign:'right'}}>{c.opened}</td>
                <td style={{fontSize:12,color:'var(--g400)'}}>{new Date(c.createdAt).toLocaleDateString()}</td>
                <td onClick={e => e.stopPropagation()}>
                  {(c.status === 'draft' || c.status === 'scheduled' || c.status === 'cancelled') && (
                    <button className="btn btn-ghost btn-sm" title="Delete" style={{color:'#DC2626'}}
                      onClick={async () => {
                        if (!confirm('Delete campaign "' + c.name + '"?')) return;
                        try { await CRM.MarketingAPI.deleteCampaign(c.id); load(); } catch (e) { showToast(e.message, 'error'); }
                      }}>🗑</button>
                  )}
                </td>
              </tr>
            ))}
          </tbody></table></div>}
      {editing && <MktCampaignEditor campaign={editing === 'new' ? null : editing} showToast={showToast}
        onClose={() => { setEditing(null); load(); }} onSent={id => { setEditing(null); setDetailId(id); load(); }} />}
      {detailId && <MktCampaignDetail id={detailId} showToast={showToast} onClose={() => { setDetailId(null); load(); }} />}
    </div>
  );
}

function MktCampaignEditor({ campaign, onClose, onSent, showToast }) {
  const { useState, useEffect } = React;
  const [form, setForm] = useState({
    name: campaign?.name || '', subject: campaign?.subject || '',
    fromName: campaign?.fromName || 'CTR/NY',
    templateId: campaign?.templateId || '', listIds: [],
  });
  const [id, setId] = useState(campaign?.id || null);
  const [templates, setTemplates] = useState([]);
  const [lists, setLists] = useState([]);
  const [previewHtml, setPreviewHtml] = useState(null);
  const [testTo, setTestTo] = useState('');
  const [busy, setBusy] = useState(false);
  const [scheduleAt, setScheduleAt] = useState('');
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  useEffect(() => {
    CRM.MarketingAPI.getTemplates().then(setTemplates).catch(()=>{});
    CRM.MarketingAPI.getLists().then(setLists).catch(()=>{});
    if (campaign?.id) CRM.MarketingAPI.getCampaign(campaign.id).then(c => {
      try { setForm(f => ({ ...f, listIds: JSON.parse(c.listIdsJson || '[]') })); } catch {}
    }).catch(()=>{});
  }, []);

  const persist = async () => {
    const payload = { name: form.name, subject: form.subject, fromName: form.fromName,
      templateId: form.templateId || null, listIds: form.listIds };
    if (!form.name.trim()) { showToast('Name is required.', 'error'); return null; }
    try {
      if (id) { await CRM.MarketingAPI.updateCampaign(id, payload); return id; }
      const c = await CRM.MarketingAPI.createCampaign(payload);
      setId(c.id);
      return c.id;
    } catch (e) { showToast('Save failed: ' + e.message, 'error'); return null; }
  };

  const preview = async () => {
    const cid = await persist(); if (!cid) return;
    try {
      const c = await CRM.MarketingAPI.getCampaign(cid);
      setPreviewHtml(await CRM.MarketingAPI.previewHtml(c.blocksJson || '{}'));
    } catch (e) { showToast('Preview failed: ' + e.message, 'error'); }
  };

  const testSend = async () => {
    if (!testTo.includes('@')) return showToast('Enter a valid test address.', 'error');
    const cid = await persist(); if (!cid) return;
    setBusy(true);
    try { await CRM.MarketingAPI.testSend(cid, testTo); showToast('Test sent to ' + testTo + '.', 'success'); }
    catch (e) { showToast(e.message, 'error'); }
    finally { setBusy(false); }
  };

  const send = async (schedule) => {
    const cid = await persist(); if (!cid) return;
    const totalMembers = lists.filter(l => form.listIds.includes(l.id)).reduce((s, l) => s + l.memberCount, 0);
    const when = schedule && scheduleAt ? new Date(scheduleAt) : null;
    const msg = when
      ? 'Schedule this campaign for ' + when.toLocaleString() + '? (~' + totalMembers + ' recipients before dedupe/suppression)'
      : 'Send this campaign NOW to ~' + totalMembers + ' recipients (before dedupe/suppression)?';
    if (!confirm(msg)) return;
    setBusy(true);
    try {
      const r = await CRM.MarketingAPI.sendCampaign(cid, when ? when.toISOString() : null);
      showToast(r.status === 'scheduled' ? 'Campaign scheduled.' : 'Campaign is sending.', 'success');
      onSent(cid);
    } catch (e) { showToast(e.message, 'error'); }
    finally { setBusy(false); }
  };

  const toggleList = (lid) => set('listIds', form.listIds.includes(lid)
    ? form.listIds.filter(x => x !== lid) : [...form.listIds, lid]);

  return (
    <div className="modal-overlay">
      <div className="modal-panel" style={{width:'min(820px,100%)'}} onClick={e=>e.stopPropagation()}>
        <div className="modal-hd">
          <div className="modal-title">{id ? 'Edit campaign' : 'New campaign'}</div>
          <button className="modal-close" onClick={onClose}>×</button>
        </div>
        <div style={{padding:'18px 24px'}}>
          <div className="fg fg-2">
            <div className="field"><label>Campaign name *</label>
              <input value={form.name} onChange={e=>set('name',e.target.value)} /></div>
            <div className="field"><label>From name</label>
              <input value={form.fromName} onChange={e=>set('fromName',e.target.value)} placeholder="CTR/NY" /></div>
          </div>
          <div className="fg fg-1"><div className="field"><label>Subject *</label>
            <input value={form.subject} onChange={e=>set('subject',e.target.value)} placeholder="Subject line recipients will see" /></div></div>
          <div className="fg fg-1"><div className="field"><label>Template *</label>
            <select value={form.templateId} onChange={e=>set('templateId',e.target.value)}>
              <option value="">— Pick a template —</option>
              {templates.map(t => <option key={t.id} value={t.id}>{t.name}</option>)}
            </select>
            <div style={{fontSize:11,color:'var(--g400)',marginTop:4}}>The template's blocks are snapshotted into the campaign when saved — later template edits don't change this campaign.</div>
          </div></div>

          <div className="field"><label>Send to lists *</label>
            {lists.length === 0 && <div style={{fontSize:12,color:'var(--g400)'}}>No lists yet — create one on the Lists tab.</div>}
            {lists.map(l => (
              <label key={l.id} style={{display:'flex',alignItems:'center',gap:8,padding:'5px 0',fontSize:13,cursor:'pointer'}}>
                <input type="checkbox" checked={form.listIds.includes(l.id)} onChange={() => toggleList(l.id)} />
                {l.name} <span style={{color:'var(--g400)',fontSize:11}}>({l.memberCount} members)</span>
              </label>
            ))}
          </div>

          <div style={{display:'flex',gap:8,flexWrap:'wrap',marginTop:14,alignItems:'center'}}>
            <button className="btn btn-ghost btn-sm" onClick={preview}>👁 Preview</button>
            <span style={{flex:1}} />
            <input className="search-input" style={{width:210}} placeholder="test@address.com"
              value={testTo} onChange={e=>setTestTo(e.target.value)} />
            <button className="btn btn-ghost btn-sm" onClick={testSend} disabled={busy}>✉️ Send test</button>
          </div>

          <div style={{borderTop:'1px solid var(--folio-border,#E8EDF2)',marginTop:16,paddingTop:16,display:'flex',gap:8,flexWrap:'wrap',alignItems:'center'}}>
            <button className="btn btn-ghost" onClick={async () => { if (await persist()) { showToast('Draft saved.', 'success'); onClose(); } }}>Save draft</button>
            <span style={{flex:1}} />
            <input type="datetime-local" className="search-input" value={scheduleAt} onChange={e=>setScheduleAt(e.target.value)} />
            <button className="btn btn-navy" onClick={() => send(true)} disabled={busy || !scheduleAt}>📅 Schedule</button>
            <button className="btn btn-primary" onClick={() => send(false)} disabled={busy}>🚀 Send now</button>
          </div>
        </div>
        {previewHtml && (
          <div className="modal-overlay" style={{zIndex:300}} onClick={() => setPreviewHtml(null)}>
            <div className="modal-panel" style={{width:'min(700px,100%)'}} onClick={e=>e.stopPropagation()}>
              <div className="modal-hd"><div className="modal-title">Preview</div>
                <button className="modal-close" onClick={()=>setPreviewHtml(null)}>×</button></div>
              <iframe title="preview" srcDoc={previewHtml} style={{width:'100%',height:'75vh',border:0,background:'#F1F5F9'}} />
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function MktCampaignDetail({ id, onClose, showToast }) {
  const { useState, useEffect, useCallback } = React;
  const [stats, setStats] = useState(null);
  const [recips, setRecips] = useState({ total: 0, rows: [] });
  const [statusFilter, setStatusFilter] = useState('');
  const [search, setSearch] = useState('');
  const load = useCallback(async () => {
    try {
      setStats(await CRM.MarketingAPI.getStats(id));
      setRecips(await CRM.MarketingAPI.getRecipients(id, statusFilter, search, 0));
    } catch {}
  }, [id, statusFilter, search]);
  useEffect(() => { load(); }, [load]);
  useEffect(() => {
    if (!stats || (stats.status !== 'sending' && stats.status !== 'scheduled')) return;
    const t = setInterval(load, 10000);
    return () => clearInterval(t);
  }, [stats?.status, load]);

  if (!stats) return null;
  const card = (label, val, color) => (
    <div className="stat-card" style={{padding:'12px 16px'}}>
      <div className="stat-label">{label}</div>
      <div className="stat-val" style={color ? {color} : null}>{val}</div>
    </div>
  );
  return (
    <div className="modal-overlay">
      <div className="modal-panel" style={{width:'min(900px,100%)'}} onClick={e=>e.stopPropagation()}>
        <div className="modal-hd" style={{display:'flex',alignItems:'center',gap:10}}>
          <div className="modal-title">Campaign results</div>
          <span className={'badge ' + (MKT_STATUS_BADGE[stats.status]||'badge-gray')}>{stats.status}</span>
          <span style={{flex:1}} />
          {stats.status === 'sending' && <button className="btn btn-ghost btn-sm" onClick={async () => {
            await CRM.MarketingAPI.cancelCampaign(id); load(); showToast('Campaign paused.'); }}>⏸ Pause</button>}
          {stats.status === 'paused' && <button className="btn btn-primary btn-sm" onClick={async () => {
            await CRM.MarketingAPI.resumeCampaign(id); load(); showToast('Campaign resumed.'); }}>▶ Resume</button>}
          <button className="modal-close" onClick={onClose}>×</button>
        </div>
        <div style={{padding:'16px 24px'}}>
          {stats.lastError && <div style={{background:'#FCEAEA',color:'#DC2626',borderRadius:8,padding:'8px 12px',fontSize:12,marginBottom:12}}>{stats.lastError}</div>}
          <div className="stat-grid" style={{marginBottom:8}}>
            {card('Queued', stats.queued)}
            {card('Sent', stats.sent, '#16A34A')}
            {card('Failed', stats.failed, stats.failed ? '#DC2626' : undefined)}
            {card('Suppressed', stats.suppressed)}
          </div>
          <div className="stat-grid" style={{marginBottom:6}}>
            {card('Opened', stats.opened)}
            {card('Open rate', stats.openRate + '%')}
            {card('Clicked', stats.clicked)}
            {card('Unsubscribed', stats.unsubscribed, stats.unsubscribed ? '#D97706' : undefined)}
          </div>
          <div style={{fontSize:11,color:'var(--g400)',marginBottom:16,lineHeight:1.5}}>
            Opens are undercounted when recipients block images; “not opened” includes emails deleted unread — email provides no delete signal.
            Clicks always count as opens.
          </div>

          {(stats.links||[]).length > 0 && (
            <div style={{marginBottom:16}}>
              <div style={{fontWeight:700,fontSize:13,color:'var(--navy)',marginBottom:6}}>Link clicks</div>
              {stats.links.map(l => (
                <div key={l.id} style={{display:'flex',justifyContent:'space-between',fontSize:12,padding:'4px 0',borderBottom:'1px solid var(--folio-divider,#EEF2F6)'}}>
                  <span style={{color:'var(--g600)',overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap',maxWidth:'80%'}}>{l.url}</span>
                  <b>{l.clicks}</b>
                </div>
              ))}
            </div>
          )}

          <div style={{display:'flex',gap:8,marginBottom:8}}>
            <select className="search-input" style={{width:140}} value={statusFilter} onChange={e=>setStatusFilter(e.target.value)}>
              <option value="">All statuses</option>
              {['queued','sent','failed','suppressed'].map(s => <option key={s} value={s}>{s}</option>)}
            </select>
            <input className="search-input" style={{flex:1}} placeholder="Search email / name…" value={search} onChange={e=>setSearch(e.target.value)} />
            <span style={{fontSize:12,color:'var(--g400)',alignSelf:'center'}}>{recips.total} recipients</span>
          </div>
          <div className="card"><table className="tbl"><thead><tr>
            <th>Email</th><th>Name</th><th>Status</th><th>Opened</th><th>Clicks</th><th>Unsub</th>
          </tr></thead><tbody>
            {recips.rows.map(r => (
              <tr key={r.id}>
                <td style={{fontSize:12}}>{r.email}</td>
                <td style={{fontSize:12,color:'var(--g600)'}}>{r.name || '—'}</td>
                <td><span className={'badge ' + (r.status === 'sent' ? 'badge-green' : r.status === 'failed' ? 'badge-red' : 'badge-gray')}
                     title={r.error || ''}>{r.status}</span></td>
                <td style={{fontSize:12}}>{r.openedAt ? '✓ ×' + r.openCount : '—'}</td>
                <td style={{fontSize:12}}>{r.clickCount || '—'}</td>
                <td style={{fontSize:12}}>{r.unsubscribedAt ? '🚫' : ''}</td>
              </tr>
            ))}
          </tbody></table></div>
        </div>
      </div>
    </div>
  );
}

// ════ LISTS ════
function MktListsTab({ showToast }) {
  const { useState, useEffect, useCallback } = React;
  const [lists, setLists] = useState([]);
  const [openList, setOpenList] = useState(null);
  const [newName, setNewName] = useState('');
  const load = useCallback(() => CRM.MarketingAPI.getLists().then(setLists).catch(()=>{}), []);
  useEffect(() => { load(); }, [load]);

  return (
    <div>
      <div style={{display:'flex',gap:8,marginBottom:12}}>
        <input className="search-input" style={{width:260}} placeholder="New list name…"
          value={newName} onChange={e=>setNewName(e.target.value)}
          onKeyDown={async e => { if (e.key === 'Enter' && newName.trim()) {
            try { await CRM.MarketingAPI.createList({ name: newName.trim() }); setNewName(''); load(); }
            catch (err) { showToast(err.message, 'error'); } } }} />
        <button className="btn btn-primary btn-sm" disabled={!newName.trim()} onClick={async () => {
          try { await CRM.MarketingAPI.createList({ name: newName.trim() }); setNewName(''); load(); }
          catch (err) { showToast(err.message, 'error'); } }}>+ Create list</button>
      </div>
      <div className="card"><table className="tbl"><thead><tr>
        <th>List</th><th style={{textAlign:'right'}}>Members</th><th>Updated</th><th></th>
      </tr></thead><tbody>
        {lists.map(l => (
          <tr key={l.id} style={{cursor:'pointer'}} onClick={() => setOpenList(l)}>
            <td style={{fontWeight:600}}>{l.name}{l.description && <div style={{fontWeight:400,fontSize:11,color:'var(--g400)'}}>{l.description}</div>}</td>
            <td style={{textAlign:'right'}}>{l.memberCount}</td>
            <td style={{fontSize:12,color:'var(--g400)'}}>{new Date(l.updatedAt).toLocaleDateString()}</td>
            <td onClick={e=>e.stopPropagation()}>
              <button className="btn btn-ghost btn-sm" style={{color:'#DC2626'}} title="Delete list" onClick={async () => {
                if (!confirm('Delete list "' + l.name + '" and its ' + l.memberCount + ' members?')) return;
                try { await CRM.MarketingAPI.deleteList(l.id); load(); } catch (e) { showToast(e.message, 'error'); }
              }}>🗑</button>
            </td>
          </tr>
        ))}
        {lists.length === 0 && <tr><td colSpan={4} style={{textAlign:'center',color:'var(--g400)',padding:30}}>No lists yet.</td></tr>}
      </tbody></table></div>
      {openList && <MktListDetail list={openList} showToast={showToast} onClose={() => { setOpenList(null); load(); }} />}
    </div>
  );
}

function MktListDetail({ list, onClose, showToast }) {
  const { useState, useEffect, useCallback } = React;
  const [data, setData] = useState({ total: 0, members: [] });
  const [search, setSearch] = useState('');
  const [page, setPage] = useState(0);
  const [addMode, setAddMode] = useState(null);   // contacts | leads | csv
  const load = useCallback(() => CRM.MarketingAPI.getMembers(list.id, search, page).then(setData).catch(()=>{}), [list.id, search, page]);
  useEffect(() => { load(); }, [load]);

  return (
    <div className="modal-overlay">
      <div className="modal-panel" style={{width:'min(860px,100%)'}} onClick={e=>e.stopPropagation()}>
        <div className="modal-hd">
          <div className="modal-title">👥 {list.name}</div>
          <button className="modal-close" onClick={onClose}>×</button>
        </div>
        <div style={{padding:'16px 24px'}}>
          <div style={{display:'flex',gap:8,marginBottom:12,flexWrap:'wrap'}}>
            <button className="btn btn-ghost btn-sm" onClick={() => setAddMode('contacts')}>+ From contacts</button>
            <button className="btn btn-ghost btn-sm" onClick={() => setAddMode('leads')}>+ From leads</button>
            <button className="btn btn-ghost btn-sm" onClick={() => setAddMode('csv')}>⬆ Import CSV/Excel</button>
            <span style={{flex:1}} />
            <input className="search-input" style={{width:220}} placeholder="Search members…"
              value={search} onChange={e => { setSearch(e.target.value); setPage(0); }} />
          </div>
          <div style={{fontSize:12,color:'var(--g400)',marginBottom:8}}>
            {data.total} members{data.total > 100 && <span> · page {page + 1} of {Math.ceil(data.total / 100)}
              <button className="btn btn-ghost btn-sm" disabled={page===0} onClick={()=>setPage(p=>p-1)}>‹</button>
              <button className="btn btn-ghost btn-sm" disabled={(page+1)*100>=data.total} onClick={()=>setPage(p=>p+1)}>›</button></span>}
          </div>
          <div className="card"><table className="tbl"><thead><tr>
            <th>Email</th><th>Name</th><th>Company</th><th>Source</th><th></th>
          </tr></thead><tbody>
            {data.members.map(m => (
              <tr key={m.id}>
                <td style={{fontSize:12.5}}>{m.email}
                  {m.suppressed && <span className="badge badge-red" style={{marginLeft:6}} title="Globally unsubscribed — will be skipped at send">unsubscribed</span>}</td>
                <td style={{fontSize:12.5,color:'var(--g600)'}}>{m.name || '—'}</td>
                <td style={{fontSize:12.5,color:'var(--g600)'}}>{m.company || '—'}</td>
                <td><span className="badge badge-gray">{m.source}</span></td>
                <td><button className="btn btn-ghost btn-sm" title="Remove from list" onClick={async () => {
                  try { await CRM.MarketingAPI.removeMember(list.id, m.id); load(); } catch (e) { showToast(e.message, 'error'); }
                }}>✕</button></td>
              </tr>
            ))}
            {data.members.length === 0 && <tr><td colSpan={5} style={{textAlign:'center',color:'var(--g400)',padding:26}}>No members{search ? ' match' : ' yet'}.</td></tr>}
          </tbody></table></div>
        </div>
        {addMode === 'contacts' && <MktAddFromContacts listId={list.id} showToast={showToast} onDone={() => { setAddMode(null); load(); }} />}
        {addMode === 'leads' && <MktAddFromLeads listId={list.id} showToast={showToast} onDone={() => { setAddMode(null); load(); }} />}
        {addMode === 'csv' && <MktImportCsv listId={list.id} showToast={showToast} onDone={() => { setAddMode(null); load(); }} />}
      </div>
    </div>
  );
}

function MktAddFromContacts({ listId, onDone, showToast }) {
  const { useState, useEffect } = React;
  const [accounts, setAccounts] = useState([]);
  const [accountId, setAccountId] = useState('');
  const [busy, setBusy] = useState(false);
  useEffect(() => { CRM.AccountsAPI.getAll({}).then(a => setAccounts(a || [])).catch(()=>{}); }, []);
  const add = async (all) => {
    setBusy(true);
    try {
      const r = await CRM.MarketingAPI.addFromContacts(listId, all ? { contactIds: null, accountId: null, allAccounts: true } : { accountId });
      showToast('Added ' + r.added + ' (skipped ' + r.duplicates + ' duplicates, ' + r.invalid + ' invalid).', 'success');
      onDone();
    } catch (e) { showToast(e.message, 'error'); }
    finally { setBusy(false); }
  };
  return (
    <div className="modal-overlay" style={{zIndex:300}} onClick={onDone}>
      <div className="modal-panel" style={{width:'min(480px,100%)'}} onClick={e=>e.stopPropagation()}>
        <div className="modal-hd"><div className="modal-title">Add from contacts</div>
          <button className="modal-close" onClick={onDone}>×</button></div>
        <div style={{padding:'16px 24px'}}>
          <div className="field"><label>Account</label>
            <select value={accountId} onChange={e=>setAccountId(e.target.value)}>
              <option value="">— Pick an account —</option>
              {accounts.map(a => <option key={a.id} value={a.id}>{a.companyName}</option>)}
            </select>
          </div>
          <div style={{fontSize:12,color:'var(--g400)',margin:'8px 0 14px'}}>Adds every contact with an email on the chosen account.</div>
          <button className="btn btn-primary" disabled={!accountId || busy} onClick={() => add(false)}>Add contacts</button>
        </div>
      </div>
    </div>
  );
}

function MktAddFromLeads({ listId, onDone, showToast }) {
  const { useState, useEffect } = React;
  const [f, setF] = useState({ stage: '', source: '', industry: '', activeOnly: true });
  const [count, setCount] = useState(null);
  const [busy, setBusy] = useState(false);
  const set = (k, v) => { setF(x => ({ ...x, [k]: v })); setCount(null); };
  useEffect(() => {
    const t = setTimeout(() => {
      CRM.MarketingAPI.addFromLeads(listId, { ...f, previewOnly: true }).then(r => setCount(r.count)).catch(()=>{});
    }, 300);
    return () => clearTimeout(t);
  }, [f]);
  const add = async () => {
    setBusy(true);
    try {
      const r = await CRM.MarketingAPI.addFromLeads(listId, { ...f, previewOnly: false });
      showToast('Added ' + r.added + ' (skipped ' + r.duplicates + ' duplicates, ' + r.invalid + ' invalid).', 'success');
      onDone();
    } catch (e) { showToast(e.message, 'error'); }
    finally { setBusy(false); }
  };
  return (
    <div className="modal-overlay" style={{zIndex:300}} onClick={onDone}>
      <div className="modal-panel" style={{width:'min(480px,100%)'}} onClick={e=>e.stopPropagation()}>
        <div className="modal-hd"><div className="modal-title">Add from leads</div>
          <button className="modal-close" onClick={onDone}>×</button></div>
        <div style={{padding:'16px 24px'}}>
          <div className="field"><label>Stage</label>
            <select value={f.stage} onChange={e=>set('stage',e.target.value)}>
              <option value="">Any stage</option>
              {(CRM.STAGES||[]).map(s => <option key={s.id||s} value={s.id||s}>{s.label||s}</option>)}
            </select></div>
          <div className="field"><label>Source</label>
            <select value={f.source} onChange={e=>set('source',e.target.value)}>
              <option value="">Any source</option>
              {(CRM.LEAD_SOURCES||[]).map(s => <option key={s}>{s}</option>)}
            </select></div>
          <div className="field"><label>Industry</label>
            <select value={f.industry} onChange={e=>set('industry',e.target.value)}>
              <option value="">Any industry</option>
              {(CRM.INDUSTRIES||[]).map(i => <option key={i}>{i}</option>)}
            </select></div>
          <label style={{display:'flex',gap:8,alignItems:'center',fontSize:13,margin:'6px 0 12px',cursor:'pointer'}}>
            <input type="checkbox" checked={f.activeOnly} onChange={e=>set('activeOnly',e.target.checked)} /> Active leads only
          </label>
          <div style={{fontSize:12,color:'var(--g600)',marginBottom:12}}>
            {count == null ? 'Counting…' : <b>{count} matching leads with an email</b>}
          </div>
          <button className="btn btn-primary" disabled={busy || !count} onClick={add}>Add leads</button>
        </div>
      </div>
    </div>
  );
}

function MktImportCsv({ listId, onDone, showToast }) {
  const { useState } = React;
  const [busy, setBusy] = useState(false);
  const [result, setResult] = useState(null);
  const upload = async (file) => {
    if (!file) return;
    setBusy(true);
    try { setResult(await CRM.MarketingAPI.importMembers(listId, file)); }
    catch (e) { showToast('Import failed: ' + e.message, 'error'); }
    finally { setBusy(false); }
  };
  return (
    <div className="modal-overlay" style={{zIndex:300}} onClick={onDone}>
      <div className="modal-panel" style={{width:'min(480px,100%)'}} onClick={e=>e.stopPropagation()}>
        <div className="modal-hd"><div className="modal-title">Import members</div>
          <button className="modal-close" onClick={onDone}>×</button></div>
        <div style={{padding:'16px 24px'}}>
          {!result ? (
            <div>
              <div style={{fontSize:13,color:'var(--g600)',marginBottom:10,lineHeight:1.6}}>
                Upload a CSV or Excel file with columns like <b>Email</b>, <b>Name</b>, <b>Company</b> (header names are matched loosely).
              </div>
              <input type="file" accept=".csv,.xlsx,.xls" disabled={busy} onChange={e => upload(e.target.files[0])} />
              {busy && <div style={{marginTop:10,fontSize:12,color:'var(--g400)'}}>Importing…</div>}
            </div>
          ) : (
            <div>
              <div style={{fontSize:14,marginBottom:8}}>✅ Imported <b>{result.added}</b> members.</div>
              <div style={{fontSize:12,color:'var(--g600)',lineHeight:1.7}}>
                Parsed rows: {result.parsed}<br/>Duplicates skipped: {result.duplicates}<br/>Invalid emails: {result.invalid}
              </div>
              <button className="btn btn-primary btn-sm" style={{marginTop:14}} onClick={onDone}>Done</button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ════ TEMPLATES ════
function MktTemplatesTab({ showToast }) {
  const { useState, useEffect, useCallback } = React;
  const [templates, setTemplates] = useState([]);
  const [editing, setEditing] = useState(null);   // 'new' | full template object
  const load = useCallback(() => CRM.MarketingAPI.getTemplates().then(setTemplates).catch(()=>{}), []);
  useEffect(() => { load(); }, [load]);
  const open = async (t) => setEditing(await CRM.MarketingAPI.getTemplate(t.id));
  return (
    <div>
      <div style={{display:'flex',justifyContent:'flex-end',marginBottom:12}}>
        <button className="btn btn-primary btn-sm" onClick={() => setEditing('new')}>+ New template</button>
      </div>
      <div className="card"><table className="tbl"><thead><tr><th>Template</th><th>Updated</th><th></th></tr></thead><tbody>
        {templates.map(t => (
          <tr key={t.id} style={{cursor:'pointer'}} onClick={() => open(t)}>
            <td style={{fontWeight:600}}>🧩 {t.name}</td>
            <td style={{fontSize:12,color:'var(--g400)'}}>{new Date(t.updatedAt).toLocaleString()}</td>
            <td onClick={e=>e.stopPropagation()}>
              <button className="btn btn-ghost btn-sm" style={{color:'#DC2626'}} title="Delete" onClick={async () => {
                if (!confirm('Delete template "' + t.name + '"? Campaigns keep their own snapshots.')) return;
                try { await CRM.MarketingAPI.deleteTemplate(t.id); load(); } catch (e) { showToast(e.message, 'error'); }
              }}>🗑</button>
            </td>
          </tr>
        ))}
        {templates.length === 0 && <tr><td colSpan={3} style={{textAlign:'center',color:'var(--g400)',padding:30}}>No templates yet — design your first email.</td></tr>}
      </tbody></table></div>
      {editing && <TemplateBuilder template={editing === 'new' ? null : editing} showToast={showToast}
        onClose={() => { setEditing(null); load(); }}
        onSave={async (data) => {
          try {
            if (editing !== 'new' && editing.id) await CRM.MarketingAPI.updateTemplate(editing.id, data);
            else await CRM.MarketingAPI.createTemplate(data);
            showToast('Template saved.', 'success');
            setEditing(null); load();
          } catch (e) { showToast('Save failed: ' + e.message, 'error'); }
        }} />}
    </div>
  );
}

// ════ SUPPRESSED ════
function MktSuppressedTab({ showToast }) {
  const { useState, useEffect, useCallback } = React;
  const [data, setData] = useState({ total: 0, rows: [] });
  const [search, setSearch] = useState('');
  const [addEmail, setAddEmail] = useState('');
  const load = useCallback(() => CRM.MarketingAPI.getSuppressions(search, 0).then(setData).catch(()=>{}), [search]);
  useEffect(() => { load(); }, [load]);
  return (
    <div>
      <div style={{display:'flex',gap:8,marginBottom:12}}>
        <input className="search-input" style={{width:240}} placeholder="Search…" value={search} onChange={e=>setSearch(e.target.value)} />
        <span style={{flex:1}} />
        <input className="search-input" style={{width:240}} placeholder="Add email to suppress…" value={addEmail} onChange={e=>setAddEmail(e.target.value)} />
        <button className="btn btn-ghost btn-sm" disabled={!addEmail.includes('@')} onClick={async () => {
          try { await CRM.MarketingAPI.addSuppression(addEmail); setAddEmail(''); load(); showToast('Suppressed.'); }
          catch (e) { showToast(e.message, 'error'); } }}>🚫 Suppress</button>
      </div>
      <div style={{fontSize:12,color:'var(--g400)',marginBottom:8}}>{data.total} suppressed addresses — these are skipped by every campaign.</div>
      <div className="card"><table className="tbl"><thead><tr><th>Email</th><th>Reason</th><th>When</th><th></th></tr></thead><tbody>
        {data.rows.map(s => (
          <tr key={s.id}>
            <td style={{fontSize:12.5}}>{s.email}</td>
            <td><span className="badge badge-gray">{s.reason}</span></td>
            <td style={{fontSize:12,color:'var(--g400)'}}>{new Date(s.createdAt).toLocaleString()}</td>
            <td><button className="btn btn-ghost btn-sm" title="Remove (re-allow sending)" onClick={async () => {
              if (!confirm('Allow marketing email to ' + s.email + ' again? Only do this with their consent.')) return;
              try { await CRM.MarketingAPI.removeSuppression(s.id); load(); } catch (e) { showToast(e.message, 'error'); }
            }}>✕</button></td>
          </tr>
        ))}
        {data.rows.length === 0 && <tr><td colSpan={4} style={{textAlign:'center',color:'var(--g400)',padding:26}}>No suppressed addresses.</td></tr>}
      </tbody></table></div>
    </div>
  );
}

// ════ SETTINGS ════
function MktSettingsTab({ showToast }) {
  const { useState, useEffect } = React;
  const [cfg, setCfg] = useState(null);
  const [status, setStatus] = useState({});
  const [busy, setBusy] = useState(false);
  const load = () => CRM.MarketingAPI.getStatus().then(s => {
    setStatus(s);
    setCfg({
      enabled: s['marketing.enabled'] === 'true',
      mailbox: s['marketing.mailbox'] || '',
      ratePerMin: s['marketing.ratePerMin'] || '20',
      dailyCap: s['marketing.dailyCap'] || '8000',
      publicBaseUrl: s['marketing.publicBaseUrl'] || 'https://crm.perigeecloud.com',
    });
  }).catch(()=>{});
  useEffect(() => { load(); }, []);
  if (!cfg) return <div style={{color:'var(--g400)',padding:30,textAlign:'center'}}>Loading…</div>;
  const set = (k, v) => setCfg(c => ({ ...c, [k]: v }));
  const save = async () => {
    setBusy(true);
    try {
      await CRM.ConfigAPI.set('marketing.enabled', cfg.enabled ? 'true' : 'false');
      await CRM.ConfigAPI.set('marketing.mailbox', cfg.mailbox.trim());
      await CRM.ConfigAPI.set('marketing.ratePerMin', cfg.ratePerMin);
      await CRM.ConfigAPI.set('marketing.dailyCap', cfg.dailyCap);
      await CRM.ConfigAPI.set('marketing.publicBaseUrl', cfg.publicBaseUrl.trim());
      showToast('Marketing settings saved.', 'success');
      load();
    } catch (e) { showToast('Save failed: ' + e.message, 'error'); }
    finally { setBusy(false); }
  };
  return (
    <div className="card card-pad" style={{maxWidth:640}}>
      <label style={{display:'flex',gap:10,alignItems:'center',fontSize:14,fontWeight:600,marginBottom:14,cursor:'pointer'}}>
        <input type="checkbox" checked={cfg.enabled} onChange={e=>set('enabled',e.target.checked)} />
        Enable campaign sending
      </label>
      <div className="field"><label>Sending mailbox (shared mailbox in the Graph access-policy group)</label>
        <input value={cfg.mailbox} onChange={e=>set('mailbox',e.target.value)} placeholder="marketing@ctrny.com" /></div>
      <div className="fg fg-2">
        <div className="field"><label>Rate (emails/min, max 30)</label>
          <input type="number" min={1} max={30} value={cfg.ratePerMin} onChange={e=>set('ratePerMin',e.target.value)} /></div>
        <div className="field"><label>Daily cap</label>
          <input type="number" min={100} max={9500} value={cfg.dailyCap} onChange={e=>set('dailyCap',e.target.value)} /></div>
      </div>
      <div className="field"><label>Public base URL (tracking, unsubscribe, images)</label>
        <input value={cfg.publicBaseUrl} onChange={e=>set('publicBaseUrl',e.target.value)} /></div>
      <div style={{display:'flex',gap:8,alignItems:'center',marginTop:6}}>
        <button className="btn btn-primary btn-sm" onClick={save} disabled={busy}>Save settings</button>
        <button className="btn btn-ghost btn-sm" onClick={async () => {
          const r = await CRM.MarketingAPI.runNow(); showToast(r.summary || 'Ran.'); load(); }}>▶ Run send cycle now</button>
      </div>
      <div style={{marginTop:16,fontSize:12,color:'var(--g600)',lineHeight:1.8,borderTop:'1px solid var(--folio-divider,#EEF2F6)',paddingTop:12}}>
        <b>Service status</b><br/>
        Last run: {status['marketing.lastRun'] ? new Date(status['marketing.lastRun']).toLocaleString() : '—'}<br/>
        Sent today: {(status['marketing.sentToday'] || '|0').split('|')[1] || '0'}<br/>
        {status['marketing.lastError'] && <span style={{color:'#DC2626'}}>Last error: {status['marketing.lastError']}</span>}
      </div>
    </div>
  );
}

Object.assign(window, { MarketingView });
