// ════════════ IMPORT & MIGRATION · bring your data in ════════════
// Own secondary sidebar (like Marketing/Money). Covers connecting third-
// party sources (HubSpot, Mailchimp, QuickBooks, Xero), a manual CSV
// import flow with field mapping, a dedupe review step, and a history
// log of past runs. Everything here is mocked/local — no real files,
// no real OAuth — but the flows are stateful and connected: a CSV run's
// duplicate candidates feed straight into the dedupe view, and the OAuth
// handshake has both an approve and a deny path.
const { Icon, Spark, Pex, Avatar, Card, Btn, Pill, Label, Num, Toggle, Field, Tabs } = window;

const CONNECTOR_META = {
  hubspot:    { name: 'HubSpot',    icon: 'users',    tone: 'amber', brings: 'Contacts, companies, deals, and lifecycle stage' },
  mailchimp:  { name: 'Mailchimp',  icon: 'mail',     tone: 'rose',  brings: 'Subscribers, lists, tags, and campaign engagement' },
  quickbooks: { name: 'QuickBooks', icon: 'dollar',   tone: 'sky',   brings: 'Customers, invoices, and payment history' },
  xero:       { name: 'Xero',       icon: 'fileText', tone: 'sage',  brings: 'Contacts, invoices, and bills' },
};

// ── CSV data + dedupe helpers (module-level, shared) ─────────
const CSV_COLUMNS = ['Full Name', 'Email Address', 'Company Name', 'Phone Number', 'Lead Source'];
const TARGET_FIELDS = ['Name', 'Email', 'Company', 'Phone', 'Tags', 'Do not import'];
const DEFAULT_MAP = ['Name', 'Email', 'Company', 'Phone', 'Tags'];
const CSV_ROWS = [
  ['Maria Chen', 'maria@brewhouse.co', 'The Brew House', '(212) 555-0143', 'wholesale'],
  ['Daniel Ruiz', 'daniel.r@gmail.com', '', '(646) 555-0199', 'newsletter'],
  ['Priya Shah', 'priya@sunroom.design', 'Sunroom Design', '(917) 555-0122', 'class-interest'],
  ['Tom Okafor', 'tom@northwind.io', 'Northwind Coffee', '(415) 555-0177', 'referral'],
  ['Sam Rivera', '', 'Riverside Market', '(305) 555-0110', 'event'],
];
// Simulated existing CRM records — CSV rows are matched against these.
const EXISTING = [
  { name: 'Daniel Ruiz', email: 'daniel.ruiz@gmail.com', company: '—' },
  { name: 'Priya Shah', email: 'priya@sunroom.design', company: 'Sunroom Design' },
  { name: 'M. Chen', email: 'maria@brewhouse.co', company: 'The Brew House' },
];
// Seed dedupe pairs shown when you visit dedupe without a fresh import.
const DEDUPE_SEED = [
  { id: 'd1', existing: { name: 'Daniel Ruiz', email: 'daniel.ruiz@gmail.com', company: '—' }, incoming: { name: 'Daniel Ruiz', email: 'daniel.r@gmail.com', company: '—' }, why: 'Same name · similar email', resolved: null },
  { id: 'd2', existing: { name: 'Priya Shah', email: 'priya@sunroom.design', company: 'Sunroom Design' }, incoming: { name: 'Priya Shah', email: 'priya@sunroom.design', company: 'Sunroom Design' }, why: 'Exact email match', resolved: null },
  { id: 'd3', existing: { name: 'M. Chen', email: 'maria@brewhouse.co', company: 'The Brew House' }, incoming: { name: 'Maria Chen', email: 'maria@brewhouse.co', company: 'The Brew House LLC' }, why: 'Exact email · name variant', resolved: null },
];
const mapRow = (row, mapping) => {
  const get = (f) => { const i = mapping.indexOf(f); return i >= 0 ? (row[i] || '') : ''; };
  return { name: get('Name'), email: get('Email'), company: get('Company'), phone: get('Phone'), tags: get('Tags') };
};
const matchExisting = (m) => {
  const email = (m.email || '').toLowerCase().trim();
  if (!email) return null;
  const name = (m.name || '').toLowerCase().trim();
  let ex = EXISTING.find(e => e.email.toLowerCase() === email);
  if (ex) return { ex, why: ex.name.toLowerCase() === name ? 'Exact email match' : 'Exact email · name variant' };
  ex = EXISTING.find(e => e.name.toLowerCase() === name);
  if (ex) return { ex, why: 'Same name · similar email' };
  return null;
};

window.SCREENS['import'] = function Import({ sub }) {
  const P = window.PX; const { go } = window.useApp();
  const seg = (sub || '').split('/');
  const active = seg[0] || 'overview';

  const [conns, setConns] = React.useState({ hubspot: false, mailchimp: true, quickbooks: false, xero: false });
  const [dedupePairs, setDedupePairs] = React.useState(DEDUPE_SEED);
  const [historyLog, setHistoryLog] = React.useState([
    { id: 'h1', src: 'Mailchimp', icon: 'mail', tone: 'rose', kind: 'Sync', recs: 1284, when: '2h ago', st: 'success' },
    { id: 'h2', src: 'CSV file', icon: 'upload', tone: 'neutral', kind: 'Import', recs: 142, when: 'Yesterday, 4:12pm', st: 'partial', detail: '138 imported · 3 flagged as duplicates · 1 skipped (missing email)' },
    { id: 'h3', src: 'QuickBooks', icon: 'dollar', tone: 'sky', kind: 'Sync attempt', recs: 0, when: '3 days ago', st: 'failed', detail: 'Auth token expired mid-sync — reconnect and try again.' },
    { id: 'h4', src: 'CSV file', icon: 'upload', tone: 'neutral', kind: 'Import', recs: 68, when: 'Last week', st: 'success' },
  ]);
  const addHistory = (entry) => setHistoryLog(l => [{ id: window.pxid('h'), when: 'Just now', ...entry }, ...l]);
  const pendingDedupe = dedupePairs.filter(p => !p.resolved).length;

  const nav = [
    { items: [{ k: 'overview', icon: 'home', label: 'Overview' }] },
    { label: 'Bring data in', items: [
      { k: 'connectors', icon: 'link', label: 'Connectors', badge: Object.values(conns).filter(Boolean).length || undefined, tone: 'sage' },
      { k: 'csv', icon: 'upload', label: 'CSV import' },
    ]},
    { label: 'Review', items: [
      { k: 'dedupe', icon: 'users', label: 'Dedupe review', badge: pendingDedupe || undefined, tone: 'amber' },
      { k: 'history', icon: 'clock', label: 'Import history' },
    ]},
  ];
  const onNav = (k) => go('import' + (k === 'overview' ? '' : '/' + k));

  return (
    <window.SubLayout title="Import" nav={nav} active={active} onNav={onNav}
      foot={<div style={{ background: P.sparkWash, border: `1px solid ${P.sparkTint}`, borderRadius: 10, padding: 11 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}><Pex size={18}/><span style={{ fontSize: 12, fontWeight: 600, color: P.ink }}>Pex watches your imports</span></div>
        <div style={{ fontSize: 11, color: P.ink3, marginTop: 4 }}>It flags likely duplicates before they hit your CRM.</div>
      </div>}>
      {active === 'overview' && <ImpOverview conns={conns} pending={pendingDedupe}/>}
      {active === 'connectors' && (seg[1] ? <ConnectorDetail id={seg[1]} conns={conns} setConns={setConns} addHistory={addHistory}/> : <Connectors conns={conns}/>)}
      {active === 'csv' && <CsvImport addHistory={addHistory} setDedupe={setDedupePairs}/>}
      {active === 'dedupe' && <Dedupe pairs={dedupePairs} setPairs={setDedupePairs}/>}
      {active === 'history' && <ImportHistory log={historyLog}/>}
    </window.SubLayout>
  );
};

const IHead = ({ title, sub, children }) => {
  const P = window.PX;
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start', marginBottom: 18, gap: 12 }}>
      <div style={{ flex: 1 }}>
        <div style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 26, color: P.ink, letterSpacing: -0.4 }}>{title}</div>
        {sub && <div style={{ fontSize: 12.5, color: P.ink3, marginTop: 2 }}>{sub}</div>}
      </div>
      {children && <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexShrink: 0 }}>{children}</div>}
    </div>
  );
};

// ── shared connector + CSV card grid ──────────────────────────
function SourceGrid({ conns }) {
  const P = window.PX; const { go } = window.useApp();
  const ids = Object.keys(CONNECTOR_META);
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3,1fr)', gap: 14 }}>
      {ids.map(id => {
        const m = CONNECTOR_META[id]; const on = !!conns[id];
        return (
          <Card key={id} pad={16} hover onClick={() => go('import/connectors/' + id)} style={{ cursor: 'pointer' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
              <div style={{ width: 36, height: 36, borderRadius: 10, background: P[m.tone + 'Tint'], color: P[m.tone], display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name={m.icon} size={17}/></div>
              <div style={{ flex: 1 }}><div style={{ fontSize: 14, fontWeight: 600, color: P.ink }}>{m.name}</div></div>
              <Pill tone={on ? 'sage' : 'neutral'} dot>{on ? 'Connected' : 'Not connected'}</Pill>
            </div>
            <div style={{ fontSize: 12, color: P.ink3, lineHeight: 1.5, marginBottom: 12, minHeight: 32 }}>{m.brings}</div>
            <Btn kind={on ? 'default' : 'spark'} size="sm" full onClick={(e) => { e.stopPropagation(); go('import/connectors/' + id); }}>{on ? 'Manage' : 'Connect'}</Btn>
          </Card>
        );
      })}
      <Card pad={16} hover onClick={() => go('import/csv')} style={{ cursor: 'pointer', border: `1.5px dashed ${P.lineStrong}`, background: P.sunk }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
          <div style={{ width: 36, height: 36, borderRadius: 10, background: P.card, color: P.ink3, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, border: `1px solid ${P.line}` }}><Icon name="upload" size={17}/></div>
          <div style={{ flex: 1 }}><div style={{ fontSize: 14, fontWeight: 600, color: P.ink }}>CSV file</div></div>
        </div>
        <div style={{ fontSize: 12, color: P.ink3, lineHeight: 1.5, marginBottom: 12, minHeight: 32 }}>Any spreadsheet export — you map the columns yourself.</div>
        <Btn kind="default" size="sm" full onClick={(e) => { e.stopPropagation(); go('import/csv'); }}>Upload a file</Btn>
      </Card>
    </div>
  );
}

// ── OVERVIEW ─────────────────────────────────────────────────
function ImpOverview({ conns, pending = 0 }) {
  const P = window.PX; const { go } = window.useApp();
  const connectedCount = Object.values(conns).filter(Boolean).length;
  return (
    <div style={{ fontFamily: P.sans, padding: 22 }}>
      <IHead title="Import & migration" sub="Bring your contacts, deals, and books over — connect a source or upload a CSV.">
        <Btn kind="default" size="sm" icon="clock" onClick={() => go('import/history')}>History</Btn>
        <Btn kind="spark" size="sm" icon="upload" onClick={() => go('import/csv')}>Import a CSV</Btn>
      </IHead>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 14, marginBottom: 18 }}>
        {[['Sources connected', connectedCount, 'of ' + Object.keys(CONNECTOR_META).length + ' available', 'link'], ['Records imported', '1,494', 'all-time', 'database'], ['Needs review', String(pending), 'possible duplicates', 'users'], ['Last activity', '2h ago', 'Mailchimp sync', 'clock']].map((c, i) => (
          <Card key={i} pad={16}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}><Label>{c[0]}</Label><Icon name={c[3]} size={15} color={P.ink3}/></div>
            <Num size={24} style={{ marginTop: 6 }}>{c[1]}</Num><div style={{ fontSize: 11.5, color: P.ink3, marginTop: 3 }}>{c[2]}</div>
          </Card>
        ))}
      </div>

      <div style={{ fontSize: 14, fontWeight: 600, color: P.ink, marginBottom: 12 }}>Connect a source</div>
      <SourceGrid conns={conns}/>

      {pending > 0 && (
        <Card pad={0} style={{ marginTop: 18 }}>
          <div style={{ padding: '14px 18px', borderBottom: `1px solid ${P.line}`, display: 'flex', alignItems: 'center', gap: 9 }}>
            <Icon name="alert" size={16} color={P.amber}/><span style={{ fontSize: 13.5, fontWeight: 600, color: P.ink, flex: 1 }}>{pending} record{pending === 1 ? ' is' : 's are'} waiting on a dedupe decision</span>
            <span onClick={() => go('import/dedupe')} style={{ fontSize: 11.5, color: P.spark, cursor: 'pointer', fontWeight: 500 }}>Review →</span>
          </div>
          <div style={{ padding: '13px 18px', fontSize: 12.5, color: P.ink3 }}>A recent import matched a few rows to existing contacts. Nothing merges automatically — you decide.</div>
        </Card>
      )}
    </div>
  );
}

// ── CONNECTORS (list) ───────────────────────────────────────
function Connectors({ conns }) {
  const P = window.PX;
  return (
    <div style={{ fontFamily: P.sans, padding: 22 }}>
      <IHead title="Connectors" sub="Live, ongoing syncs — connect once and Pexxie keeps them up to date."/>
      <SourceGrid conns={conns}/>
    </div>
  );
}

// ── CONNECTOR DETAIL · mocked OAuth w/ approve + deny ────────
function ConnectorDetail({ id, conns, setConns, addHistory }) {
  const P = window.PX; const { go, toast } = window.useApp();
  const m = CONNECTOR_META[id];
  const [phase, setPhase] = React.useState('idle'); // idle | consent | connecting
  const [syncing, setSyncing] = React.useState(false);
  const [lastSync, setLastSync] = React.useState('2h ago');
  const tRef = React.useRef(null);
  React.useEffect(() => () => clearTimeout(tRef.current), []);
  const on = !!(conns && conns[id]);

  if (!m) {
    return (
      <div style={{ fontFamily: P.sans, padding: 22 }}>
        <IHead title="Connector not found"/>
        <Btn kind="default" size="sm" onClick={() => go('import/connectors')}>Back to connectors</Btn>
      </div>
    );
  }

  const approve = () => {
    setPhase('connecting');
    tRef.current = setTimeout(() => {
      setPhase('idle');
      setConns(s => ({ ...s, [id]: true }));
      setLastSync('Just now');
      toast(`${m.name} connected — first sync running in the background.`, { tone: 'sage', icon: 'check' });
      addHistory({ src: m.name, icon: m.icon, tone: m.tone, kind: 'Initial sync', recs: 320 + id.length * 40, st: 'success' });
    }, 1100);
  };
  const deny = () => {
    setPhase('idle');
    toast(`${m.name} authorization denied — nothing was connected.`, { tone: 'rose', icon: 'x' });
    addHistory({ src: m.name, icon: m.icon, tone: m.tone, kind: 'Connect attempt', recs: 0, st: 'failed', detail: 'Authorization was denied on the consent screen — no data was imported.' });
  };
  const cancelConnecting = () => { clearTimeout(tRef.current); setPhase('idle'); toast(`${m.name} connection canceled.`, { icon: 'x' }); };
  const doSync = () => {
    setSyncing(true);
    tRef.current = setTimeout(() => {
      setSyncing(false);
      setLastSync('Just now');
      toast(`${m.name} sync complete.`, { tone: 'sage', icon: 'check' });
      addHistory({ src: m.name, icon: m.icon, tone: m.tone, kind: 'Sync', recs: 12 + id.length * 3, st: 'success' });
    }, 1300);
  };
  const doDisconnect = () => {
    setConns(s => ({ ...s, [id]: false }));
    setPhase('idle');
    toast(`${m.name} disconnected.`, { icon: 'x' });
  };

  const syncedData = {
    hubspot: ['Contacts · 842', 'Companies · 96', 'Deals · 58 (open)'],
    mailchimp: ['Subscribers · 1,284', 'Lists · 6', 'Tags · 22'],
    quickbooks: ['Customers · 214', 'Invoices · 618', 'Payments · 590'],
    xero: ['Contacts · 178', 'Invoices · 402', 'Bills · 133'],
  }[id] || [];

  return (
    <div style={{ fontFamily: P.sans, padding: 22 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 18 }}>
        <Btn kind="ghost" size="sm" icon="chevL" onClick={() => go('import/connectors')}>Connectors</Btn>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 20 }}>
        <div style={{ width: 52, height: 52, borderRadius: 14, background: P[m.tone + 'Tint'], color: P[m.tone], display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name={m.icon} size={24}/></div>
        <div style={{ flex: 1 }}>
          <div style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 26, color: P.ink }}>{m.name}</div>
          <div style={{ fontSize: 12.5, color: P.ink3, marginTop: 2 }}>{m.brings}</div>
        </div>
        <Pill tone={on ? 'sage' : 'neutral'} dot>{on ? 'Connected' : 'Not connected'}</Pill>
      </div>

      {!on ? (
        <Card pad={26} style={{ textAlign: 'center' }}>
          <div style={{ width: 52, height: 52, borderRadius: 26, background: P.sunk, display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 14px' }}>
            <Icon name="lock" size={22} color={P.ink3}/>
          </div>
          {phase === 'consent' ? (
            <React.Fragment>
              <div style={{ fontSize: 15, fontWeight: 600, color: P.ink, marginBottom: 6 }}>Authorize Pexxie to access {m.name}</div>
              <div style={{ fontSize: 12.5, color: P.ink3, maxWidth: 400, margin: '0 auto 10px', lineHeight: 1.55 }}>Pexxie is requesting <strong>read-only</strong> access to your {m.name} account.</div>
              <div style={{ display: 'inline-flex', alignItems: 'center', gap: 7, fontSize: 12, color: P.ink2, background: P.sunk, borderRadius: 8, padding: '7px 12px', marginBottom: 18 }}>
                <Icon name="check" size={13} color={P.sage}/><span>{m.brings}</span>
              </div>
              <div style={{ display: 'flex', gap: 8, justifyContent: 'center' }}>
                <Btn kind="ghost" size="md" onClick={deny}>Deny</Btn>
                <Btn kind="spark" size="md" icon="check" onClick={approve}>Approve access</Btn>
              </div>
              <div style={{ fontSize: 11, color: P.ink4, marginTop: 12 }}>This is a mocked consent screen — approve to connect, deny to cancel.</div>
            </React.Fragment>
          ) : phase === 'connecting' ? (
            <React.Fragment>
              <div style={{ fontSize: 15, fontWeight: 600, color: P.ink, marginBottom: 6 }}>Connecting to {m.name}…</div>
              <div style={{ fontSize: 12.5, color: P.ink3, maxWidth: 380, margin: '0 auto 18px', lineHeight: 1.55 }}>Finishing the handshake and starting your first sync.</div>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8, marginBottom: 14 }}>
                <Icon name="refresh" size={16} color={P.spark} style={{ animation: 'pxspin 1s linear infinite' }}/><span style={{ fontSize: 12.5, color: P.spark }}>Authorizing…</span>
              </div>
              <Btn kind="ghost" size="sm" onClick={cancelConnecting}>Cancel</Btn>
            </React.Fragment>
          ) : (
            <React.Fragment>
              <div style={{ fontSize: 15, fontWeight: 600, color: P.ink, marginBottom: 6 }}>Connect your {m.name} account</div>
              <div style={{ fontSize: 12.5, color: P.ink3, maxWidth: 380, margin: '0 auto 18px', lineHeight: 1.55 }}>Pexxie opens a secure {m.name} login window. We only request read access to sync data in.</div>
              <Btn kind="spark" size="md" icon="link" onClick={() => setPhase('consent')}>Connect {m.name}</Btn>
            </React.Fragment>
          )}
        </Card>
      ) : (
        <div style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: 14 }}>
          <Card pad={18}>
            <div style={{ fontSize: 14, fontWeight: 600, color: P.ink, marginBottom: 12 }}>What's synced</div>
            {syncedData.map((d, i) => (
              <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 0', borderBottom: i < syncedData.length - 1 ? `1px solid ${P.line}` : 'none' }}>
                <Icon name="check" size={14} color={P.sage}/><span style={{ fontSize: 13, color: P.ink2 }}>{d}</span>
              </div>
            ))}
          </Card>
          <Card pad={18}>
            <Label>Sync status</Label>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 }}>
              {syncing ? <Icon name="refresh" size={16} color={P.spark} style={{ animation: 'pxspin 1s linear infinite' }}/> : <Icon name="check" size={16} color={P.sage}/>}
              <span style={{ fontSize: 13, color: P.ink }}>{syncing ? 'Syncing now…' : 'Up to date'}</span>
            </div>
            <div style={{ fontSize: 11.5, color: P.ink3, marginTop: 4 }}>Last sync · {lastSync}</div>
            <Btn kind="default" size="sm" full icon="refresh" style={{ marginTop: 14 }} disabled={syncing} onClick={doSync}>{syncing ? 'Syncing…' : 'Sync now'}</Btn>
            <Btn kind="ghost" size="sm" full style={{ marginTop: 8, color: P.rose }} onClick={doDisconnect}>Disconnect</Btn>
          </Card>
        </div>
      )}
    </div>
  );
}

// ── CSV IMPORT FLOW ──────────────────────────────────────────
function MapSelect({ value, onChange }) {
  const P = window.PX;
  return (
    <select value={value} onChange={e => onChange(e.target.value)} style={{ width: '100%', border: `1px solid ${P.lineStrong}`, borderRadius: P.rCtl, padding: '8px 10px', fontSize: 12.5, color: P.ink, fontFamily: P.sans, background: P.card, outline: 'none' }}>
      {TARGET_FIELDS.map(f => <option key={f} value={f}>{f}</option>)}
    </select>
  );
}

function CsvImport({ addHistory, setDedupe }) {
  const P = window.PX; const { go, toast } = window.useApp();
  const [step, setStep] = React.useState('upload'); // upload | map | preview | done
  const [fileName, setFileName] = React.useState('');
  const [reading, setReading] = React.useState(false);
  const [importing, setImporting] = React.useState(false);
  const [mapping, setMapping] = React.useState(DEFAULT_MAP.slice());
  const [result, setResult] = React.useState(null);

  const steps = [['upload', 'Upload'], ['map', 'Map fields'], ['preview', 'Preview'], ['done', 'Done']];
  const stepIdx = steps.findIndex(s => s[0] === step);
  const emailMapped = mapping.includes('Email');
  const shownIdx = mapping.map((f, i) => f === 'Do not import' ? -1 : i).filter(i => i >= 0);

  // Simulated capture — no real file is read (contents are mocked); the
  // dropzone click sets a captured filename then "parses" into the mapper.
  const doUpload = () => {
    setFileName('contacts_export.csv');
    setReading(true);
    setTimeout(() => { setReading(false); setStep('map'); }, 800);
  };
  const goPreview = () => {
    if (!emailMapped) { toast('Map a column to Email before continuing.', { tone: 'rose', icon: 'alert' }); return; }
    const active = mapping.filter(f => f !== 'Do not import');
    const dup = active.find((f, i) => active.indexOf(f) !== i);
    if (dup) { toast(`"${dup}" is mapped to more than one column — each field maps once.`, { tone: 'rose', icon: 'alert' }); return; }
    setStep('preview');
  };
  const runImport = () => {
    setImporting(true);
    setTimeout(() => {
      let imported = 0, skipped = 0; const cands = [];
      CSV_ROWS.forEach(row => {
        const m = mapRow(row, mapping);
        if (!m.email.trim()) { skipped++; return; }
        imported++;
        const match = matchExisting(m);
        if (match) cands.push({
          id: window.pxid('dp'), why: match.why, resolved: null,
          existing: { name: match.ex.name, email: match.ex.email, company: match.ex.company || '—' },
          incoming: { name: m.name || '—', email: m.email, company: m.company || '—' },
        });
      });
      const dupes = cands.length;
      setResult({ total: CSV_ROWS.length, imported, dupes, skipped });
      if (dupes) setDedupe(cands);
      setImporting(false);
      setStep('done');
      toast(`Imported ${imported} of ${CSV_ROWS.length} rows — ${dupes} flagged, ${skipped} skipped.`, { tone: 'sage', icon: 'check' });
      addHistory({ src: 'CSV file', icon: 'upload', tone: 'neutral', kind: 'Import', recs: imported, st: (dupes || skipped) ? 'partial' : 'success', detail: `${imported} imported · ${dupes} flagged as duplicates · ${skipped} skipped (missing email)` });
    }, 1100);
  };
  const reset = () => { setStep('upload'); setFileName(''); setResult(null); setImporting(false); setReading(false); setMapping(DEFAULT_MAP.slice()); };

  return (
    <div style={{ fontFamily: P.sans, padding: 22 }}>
      <IHead title="CSV import" sub="Upload a spreadsheet export, map the columns, and preview before it lands.">
        {step !== 'upload' && <Btn kind="ghost" size="sm" onClick={reset}>Start over</Btn>}
      </IHead>

      <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 20 }}>
        {steps.map((s, i) => (
          <React.Fragment key={s[0]}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
              <div style={{ width: 22, height: 22, borderRadius: 11, background: i <= stepIdx ? P.spark : P.sunk, color: i <= stepIdx ? '#fff' : P.ink3, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, fontWeight: 700 }}>{i < stepIdx ? '✓' : i + 1}</div>
              <span style={{ fontSize: 12.5, color: i <= stepIdx ? P.ink : P.ink3, fontWeight: i === stepIdx ? 600 : 500 }}>{s[1]}</span>
            </div>
            {i < steps.length - 1 && <div style={{ flex: 1, height: 1, background: i < stepIdx ? P.spark : P.line, minWidth: 20 }}/>}
          </React.Fragment>
        ))}
      </div>

      {step === 'upload' && (
        <Card pad={0}>
          <div onClick={() => !reading && doUpload()} style={{ margin: 20, padding: '48px 20px', border: `2px dashed ${P.lineStrong}`, borderRadius: 12, textAlign: 'center', cursor: reading ? 'default' : 'pointer', background: P.sunk }}>
            <div style={{ width: 46, height: 46, borderRadius: 23, background: P.card, border: `1px solid ${P.line}`, display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 14px' }}>
              <Icon name={reading ? 'refresh' : 'upload'} size={20} color={P.spark} style={reading ? { animation: 'pxspin 1s linear infinite' } : undefined}/>
            </div>
            {reading ? (
              <React.Fragment>
                <div style={{ fontSize: 14, fontWeight: 600, color: P.ink, marginBottom: 4 }}>Reading {fileName}…</div>
                <div style={{ fontSize: 12, color: P.ink3 }}>Detecting columns and row count</div>
              </React.Fragment>
            ) : (
              <React.Fragment>
                <div style={{ fontSize: 14, fontWeight: 600, color: P.ink, marginBottom: 4 }}>Drag & drop a CSV, or click to browse</div>
                <div style={{ fontSize: 12, color: P.ink3 }}>Contacts, leads, or deals — we read the file name; a sample layout is used for this mock</div>
              </React.Fragment>
            )}
          </div>
        </Card>
      )}

      {step === 'map' && (
        <React.Fragment>
          <Card pad={16} style={{ marginBottom: 14, display: 'flex', alignItems: 'center', gap: 10 }}>
            <Icon name="fileText" size={16} color={P.ink3}/><span style={{ fontSize: 13, color: P.ink, fontWeight: 500, flex: 1 }}>{fileName}</span><Pill tone="sage">{CSV_ROWS.length} rows detected</Pill>
          </Card>
          {!emailMapped && (
            <Card pad={12} style={{ marginBottom: 14, background: P.amberWash, border: `1px solid ${P.amberTint}`, display: 'flex', alignItems: 'center', gap: 8 }}>
              <Icon name="alert" size={15} color={P.amber}/><span style={{ fontSize: 12.5, color: P.ink2 }}>Map one column to <strong>Email</strong> — it's required to match and dedupe contacts.</span>
            </Card>
          )}
          <Card pad={0}>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 24px 1fr', gap: 12, padding: '12px 18px', borderBottom: `1px solid ${P.line}` }}>
              <Label>CSV column</Label><span/><Label>Pexxie field</Label>
            </div>
            {CSV_COLUMNS.map((c, i) => (
              <div key={c} style={{ display: 'grid', gridTemplateColumns: '1fr 24px 1fr', gap: 12, padding: '11px 18px', alignItems: 'center', borderBottom: i < CSV_COLUMNS.length - 1 ? `1px solid ${P.line}` : 'none' }}>
                <span style={{ fontSize: 13, color: P.ink2, fontFamily: P.mono }}>{c}</span>
                <Icon name="arrowRight" size={14} color={P.ink4}/>
                <MapSelect value={mapping[i]} onChange={v => setMapping(m => m.map((x, j) => j === i ? v : x))}/>
              </div>
            ))}
          </Card>
          <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 16 }}>
            <Btn kind="spark" size="sm" iconR="chevR" disabled={!emailMapped} onClick={goPreview}>Continue to preview</Btn>
          </div>
        </React.Fragment>
      )}

      {step === 'preview' && !importing && (
        <React.Fragment>
          <div style={{ fontSize: 13, color: P.ink3, marginBottom: 10 }}>Showing {CSV_ROWS.length} of {CSV_ROWS.length} rows, mapped to {shownIdx.length} Pexxie field{shownIdx.length === 1 ? '' : 's'} (columns set to "Do not import" are hidden).</div>
          <Card pad={0}>
            <div style={{ display: 'grid', gridTemplateColumns: `repeat(${shownIdx.length},1fr)`, gap: 10, padding: '12px 18px', borderBottom: `1px solid ${P.line}` }}>
              {shownIdx.map(i => <Label key={i}>{mapping[i]}</Label>)}
            </div>
            {CSV_ROWS.map((row, ri) => {
              const missingEmail = !(mapRow(row, mapping).email || '').trim();
              return (
                <div key={ri} style={{ display: 'grid', gridTemplateColumns: `repeat(${shownIdx.length},1fr)`, gap: 10, padding: '11px 18px', borderBottom: ri < CSV_ROWS.length - 1 ? `1px solid ${P.line}` : 'none', alignItems: 'center', background: missingEmail ? P.roseWash : 'transparent' }}>
                  {shownIdx.map(ci => <span key={ci} style={{ fontSize: 12.5, color: row[ci] ? P.ink2 : P.ink4 }}>{row[ci] || (mapping[ci] === 'Email' ? 'missing — will skip' : '—')}</span>)}
                </div>
              );
            })}
          </Card>
          <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 16 }}>
            <Btn kind="ghost" size="sm" icon="chevL" onClick={() => setStep('map')}>Back to mapping</Btn>
            <Btn kind="spark" size="sm" icon="upload" onClick={runImport}>Import {CSV_ROWS.length} rows</Btn>
          </div>
        </React.Fragment>
      )}

      {step === 'preview' && importing && (
        <Card pad={30} style={{ textAlign: 'center' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10, marginBottom: 14 }}>
            <Icon name="refresh" size={18} color={P.spark} style={{ animation: 'pxspin 1s linear infinite' }}/>
            <span style={{ fontSize: 14, fontWeight: 600, color: P.ink }}>Importing {CSV_ROWS.length} rows…</span>
          </div>
          <div style={{ height: 8, background: P.sunk, borderRadius: 6, overflow: 'hidden', maxWidth: 360, margin: '0 auto' }}>
            <div style={{ width: '70%', height: '100%', background: P.spark, borderRadius: 6 }}/>
          </div>
          <div style={{ fontSize: 12, color: P.ink3, marginTop: 12 }}>Matching against existing contacts and flagging possible duplicates.</div>
        </Card>
      )}

      {step === 'done' && result && (() => {
        const clean = result.dupes === 0 && result.skipped === 0;
        return (
          <Card pad={26} style={{ textAlign: 'center' }}>
            <div style={{ width: 52, height: 52, borderRadius: 26, background: clean ? P.sageTint : P.amberTint, display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 14px' }}>
              <Icon name={clean ? 'check' : 'alert'} size={24} color={clean ? P.sage : P.amber}/>
            </div>
            <div style={{ fontSize: 16, fontWeight: 600, color: P.ink, marginBottom: 6 }}>{clean ? 'Import complete' : 'Import complete — needs review'}</div>
            <div style={{ fontSize: 12.5, color: P.ink3, marginBottom: 18 }}>{fileName}</div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3,1fr)', gap: 12, maxWidth: 420, margin: '0 auto 18px' }}>
              <div><Num size={22} color={P.sage}>{result.imported}</Num><div style={{ fontSize: 11, color: P.ink3, marginTop: 3 }}>Imported</div></div>
              <div><Num size={22} color={P.amber}>{result.dupes}</Num><div style={{ fontSize: 11, color: P.ink3, marginTop: 3 }}>Possible duplicates</div></div>
              <div><Num size={22} color={P.ink3}>{result.skipped}</Num><div style={{ fontSize: 11, color: P.ink3, marginTop: 3 }}>Skipped (no email)</div></div>
            </div>
            <div style={{ display: 'flex', gap: 8, justifyContent: 'center' }}>
              <Btn kind="default" size="sm" onClick={reset}>Import another file</Btn>
              {result.dupes > 0 && <Btn kind="spark" size="sm" iconR="chevR" onClick={() => go('import/dedupe')}>Review {result.dupes} duplicate{result.dupes > 1 ? 's' : ''}</Btn>}
            </div>
          </Card>
        );
      })()}
    </div>
  );
}

// ── DEDUPE PREVIEW ───────────────────────────────────────────
function Dedupe({ pairs, setPairs }) {
  const P = window.PX; const { toast } = window.useApp();
  const resolve = (id, action) => {
    setPairs(ps => ps.map(p => p.id === id ? { ...p, resolved: action } : p));
    const msgs = { merge: 'Records merged.', keep: 'Kept both records.', skip: 'Skipped — left as-is.' };
    toast(msgs[action], { tone: action === 'merge' ? 'sage' : undefined, icon: action === 'merge' ? 'check' : 'info' });
  };
  const pending = pairs.filter(p => !p.resolved).length;
  const actionTone = { merge: 'sage', keep: 'sky', skip: 'neutral' };
  const actionLabel = { merge: 'Merged', keep: 'Kept both', skip: 'Skipped' };

  return (
    <div style={{ fontFamily: P.sans, padding: 22 }}>
      <IHead title="Dedupe review" sub="Records that look like matches to what's already in Pexxie — nothing merges without you.">
        <Pill tone={pending ? 'amber' : 'sage'} dot>{pending ? `${pending} pending` : 'All resolved'}</Pill>
      </IHead>
      {pairs.length === 0 && (
        <Card pad={30} style={{ textAlign: 'center' }}>
          <div style={{ width: 46, height: 46, borderRadius: 23, background: P.sageTint, display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 12px' }}><Icon name="check" size={20} color={P.sage}/></div>
          <div style={{ fontSize: 14, fontWeight: 600, color: P.ink }}>Nothing to review</div>
          <div style={{ fontSize: 12.5, color: P.ink3, marginTop: 4 }}>Run a CSV import and any likely duplicates will show up here.</div>
        </Card>
      )}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        {pairs.map(p => (
          <Card key={p.id} pad={16} style={{ border: `1px solid ${p.resolved ? P.line : P.amberTint}` }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
              <Icon name="alert" size={14} color={P.amber}/><span style={{ fontSize: 12, color: P.ink3 }}>{p.why}</span>
              {p.resolved && <span style={{ marginLeft: 'auto' }}><Pill tone={actionTone[p.resolved]}>{actionLabel[p.resolved]}</Pill></span>}
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
              {[['Existing record', p.existing], ['Incoming record', p.incoming]].map(([lbl, r], i) => (
                <div key={i} style={{ padding: 12, background: P.sunk, borderRadius: 10 }}>
                  <Label style={{ marginBottom: 6 }}>{lbl}</Label>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}><Avatar name={r.name} size={26}/><span style={{ fontSize: 13, color: P.ink, fontWeight: 600 }}>{r.name}</span></div>
                  <div style={{ fontSize: 12, color: P.ink3 }}>{r.email}</div>
                  <div style={{ fontSize: 12, color: P.ink3 }}>{r.company}</div>
                </div>
              ))}
            </div>
            {!p.resolved && (
              <div style={{ display: 'flex', gap: 8, marginTop: 12, justifyContent: 'flex-end' }}>
                <Btn kind="ghost" size="sm" onClick={() => resolve(p.id, 'skip')}>Skip</Btn>
                <Btn kind="default" size="sm" onClick={() => resolve(p.id, 'keep')}>Keep both</Btn>
                <Btn kind="spark" size="sm" icon="check" onClick={() => resolve(p.id, 'merge')}>Merge</Btn>
              </div>
            )}
          </Card>
        ))}
      </div>
    </div>
  );
}

// ── IMPORT HISTORY ────────────────────────────────────────────
function ImportHistory({ log }) {
  const P = window.PX;
  const [sel, setSel] = React.useState(null);
  const stTone = { success: 'sage', partial: 'amber', failed: 'rose' };
  const sel_ = log.find(l => l.id === sel);
  return (
    <div style={{ fontFamily: P.sans, padding: 22 }}>
      <IHead title="Import history" sub="Every import and sync run, with the details behind each result."/>
      <Card pad={0}>
        <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr 90px 1fr 100px 30px', gap: 12, padding: '12px 18px', borderBottom: `1px solid ${P.line}` }}>
          {['Source', 'Type', 'Records', 'When', 'Status', ''].map((h, i) => <Label key={i} style={{ textAlign: i === 2 ? 'right' : 'left' }}>{h}</Label>)}
        </div>
        {log.map((r, i) => (
          <div key={r.id} onClick={() => setSel(r.id)} style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr 90px 1fr 100px 30px', gap: 12, padding: '13px 18px', borderBottom: i < log.length - 1 ? `1px solid ${P.line}` : 'none', alignItems: 'center', cursor: 'pointer' }}
            onMouseEnter={e => e.currentTarget.style.background = P.hover} onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
              <div style={{ width: 26, height: 26, borderRadius: 8, background: P[(r.tone || 'neutral') + 'Tint'] || P.sunk, color: P[r.tone] || P.ink2, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name={r.icon} size={13}/></div>
              <span style={{ fontSize: 13.5, color: P.ink, fontWeight: 500 }}>{r.src}</span>
            </div>
            <span style={{ fontSize: 12.5, color: P.ink3 }}>{r.kind}</span>
            <span style={{ fontSize: 12.5, color: P.ink2, textAlign: 'right', fontFamily: P.mono }}>{r.recs.toLocaleString()}</span>
            <span style={{ fontSize: 12.5, color: P.ink3 }}>{r.when}</span>
            <span><Pill tone={stTone[r.st]} style={{ fontSize: 10 }}>{r.st}</Pill></span>
            <Icon name="chevR" size={15} color={P.ink4}/>
          </div>
        ))}
      </Card>

      {sel_ && (
        <window.Modal title={sel_.src} sub={`${sel_.kind} · ${sel_.when}`} onClose={() => setSel(null)}
          foot={<Btn kind="default" size="sm" onClick={() => setSel(null)}>Close</Btn>}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16 }}>
            <Pill tone={stTone[sel_.st]} dot style={{ fontSize: 11 }}>{sel_.st}</Pill>
            <span style={{ fontSize: 12.5, color: P.ink3 }}>{sel_.recs.toLocaleString()} records processed</span>
          </div>
          <Card pad={14} style={{ background: P.sunk }}>
            <div style={{ fontSize: 12.5, color: P.ink2, lineHeight: 1.6 }}>
              {sel_.detail || (sel_.st === 'success' ? 'All records processed cleanly — no errors, no duplicates flagged.' : 'No further detail recorded for this run.')}
            </div>
          </Card>
        </window.Modal>
      )}
    </div>
  );
}
