// ════════════════════════════════════════════════════════════════════════
// PropMystro · G5 · pm-d-ingest.jsx  (mirror of pm-ingest.jsx)
// Import data — bring an existing portfolio in from a spreadsheet. A four-step
// wizard: source → paste / upload CSV → review & dedupe → done. Owners match
// by name or email, duplicates are flagged (same postcode + address stem) and
// default to skip, and the commit is property-cap-aware: it stops cleanly at
// the plan limit with an upgrade prompt. Other sources route to their own
// modules (expenses CSV, bank statements, document drop). → window.PMImportHub
// ════════════════════════════════════════════════════════════════════════
(function () {
  const { useState, useEffect, useCallback } = React;

  const SAMPLE_CSV = [
    'address,postcode,borough,owner,beds,baths,type,rent',
    '14 Eldon Road,HA1 5HU,Harrow,Alpa Desai,3,1,house,2450',
    '88B Station Approach,HA2 8LR,Harrow,Hemal Desai,2,1,flat,1675',
    '"Flat 4, Lyon Court",HA1 2EX,Harrow,Alpa Desai,1,1,studio,1190',
    '221 Pinner View,HA1 4QZ,Harrow,Isha Desai,5,2,hmo,3900',
  ].join('\n');

  const gbp = (n) => '£' + (Number(n) || 0).toLocaleString();
  function Spin() { return <span className="spin dark" />; }

  // CSV parser (handles quoted fields)
  function parseCSV(text) {
    const lines = String(text || '').split(/\r?\n/).filter(l => l.trim());
    if (lines.length < 2) return [];
    const parseLine = (line) => {
      const cells = []; let cur = '', inQ = false;
      for (let i = 0; i < line.length; i++) {
        const c = line[i];
        if (inQ) {
          if (c === '"' && line[i + 1] === '"') { cur += '"'; i++; }
          else if (c === '"') { inQ = false; }
          else cur += c;
        } else {
          if (c === ',') { cells.push(cur); cur = ''; }
          else if (c === '"' && cur === '') { inQ = true; }
          else cur += c;
        }
      }
      cells.push(cur);
      return cells;
    };
    const headers = parseLine(lines[0]).map(h => h.trim().toLowerCase().replace(/\s+/g, '_'));
    return lines.slice(1).map(l => {
      const cells = parseLine(l); const obj = {};
      headers.forEach((h, i) => obj[h] = (cells[i] || '').trim());
      return obj;
    });
  }

  const norm = (s) => (s || '').toLowerCase().replace(/[^a-z0-9]/g, '');
  function findDuplicate(existing, row) {
    for (const p of existing) {
      if (norm(p.postcode) === norm(row.postcode) && norm(p.address).slice(0, 8) === norm(row.address).slice(0, 8)) return p;
    }
    return null;
  }
  function normType(t) {
    const v = (t || '').toLowerCase();
    if (v.includes('hmo')) return 'hmo';
    if (v.includes('house') || v.includes('terrace') || v.includes('semi') || v.includes('detach')) return 'house';
    if (v.includes('studio')) return 'studio';
    return 'flat';
  }

  function Step({ n, cur, label }) {
    const cls = n === cur ? ' on' : n < cur ? ' done' : '';
    return <div className={'imp-step' + cls}>
      <span className="imp-step-n">{n < cur ? '✓' : n}</span><span>{label}</span>
    </div>;
  }

  function ImportHub({ sb, account, toast, openBilling, go }) {
    const [step, setStep] = useState(1);
    const [existing, setExisting] = useState(null);
    const [owners, setOwners] = useState([]);
    const [csv, setCsv] = useState('');
    const [parsed, setParsed] = useState([]);
    const [error, setError] = useState('');
    const [busy, setBusy] = useState(false);
    const [result, setResult] = useState(null);

    const load = useCallback(async () => {
      const [p, o] = await Promise.all([
        sb.from('properties').select('id,address,postcode'),
        sb.from('owners').select('id,name,email'),
      ]);
      setExisting(p.data || []); setOwners(o.data || []);
    }, [sb]);
    useEffect(() => { load(); }, [load]);

    const matchOwner = (row) => {
      const byEmail = row.owner_email && owners.find(o => (o.email || '').toLowerCase() === row.owner_email.toLowerCase());
      if (byEmail) return byEmail;
      const byName = row.owner && owners.find(o => norm(o.name) === norm(row.owner));
      if (byName) return byName;
      return null;
    };

    const onParse = () => {
      setError('');
      try {
        const rows = parseCSV(csv);
        if (rows.length === 0) { setError('No rows found — the first line should be headers (address, postcode, …).'); return; }
        if (!rows[0].address && !rows[0].postcode) { setError('Could not find address / postcode columns. Check the header row.'); return; }
        const draft = rows.map((r, i) => {
          const owner = matchOwner(r);
          const dup = findDuplicate(existing || [], r);
          return {
            _idx: i,
            address: r.address || '', postcode: (r.postcode || '').toUpperCase(), borough: r.borough || '',
            owner, ownerRaw: r.owner || r.owner_email || '',
            beds: parseInt(r.beds) || null, baths: parseInt(r.baths) || null,
            type: normType(r.type), rent: parseFloat(String(r.rent || '').replace(/[£,]/g, '')) || null,
            _duplicate: dup, _action: dup ? 'skip' : (r.address && r.postcode ? 'import' : 'skip'),
            _invalid: !r.address || !r.postcode,
          };
        });
        setParsed(draft); setStep(3);
      } catch (e) { setError('Could not parse the CSV: ' + e.message); }
    };

    const onCommit = async () => {
      const toImport = parsed.filter(r => r._action === 'import');
      setBusy(true);
      let done = 0, capHit = false, firstErr = '';
      for (const r of toImport) {
        const { error } = await sb.from('properties').insert({
          address: r.address, postcode: r.postcode, borough: r.borough || null,
          type: r.type, beds: r.beds, baths: r.baths, rent: r.rent,
          primary_owner_id: r.owner ? r.owner.id : null,
        });
        if (error) {
          if (/property_cap/.test(error.message)) { capHit = true; break; }
          firstErr = firstErr || error.message;
        } else done++;
      }
      if (done > 0) {
        await sb.from('activity_log').insert({ who: 'Landlord', action: 'Imported ' + done + ' propert' + (done === 1 ? 'y' : 'ies') + ' via CSV', entity_type: 'import', details: { rows: toImport.length, imported: done } });
      }
      setBusy(false);
      setResult({ done, skipped: parsed.length - toImport.length, capHit, err: firstErr, attempted: toImport.length });
      setStep(4);
      load();
    };

    const setAction = (idx, action) => setParsed(parsed.map(r => r._idx === idx ? { ...r, _action: action } : r));
    const importCount = parsed.filter(r => r._action === 'import').length;
    const cap = account.property_cap >= 100000 ? null : account.property_cap;
    const headroom = cap == null || existing === null ? null : Math.max(0, cap - existing.length);

    if (existing === null) return <div className="card card-pad"><Spin /></div>;

    return <React.Fragment>
      <ImportStyles />
      <div className="pagehead"><h1>Import data</h1><p>Bring your existing portfolio in from spreadsheets — properties here; expenses, bank statements and documents through their own modules.</p></div>

      <div className="imp-steps">
        <Step n={1} cur={step} label="Source" />
        <Step n={2} cur={step} label="Paste / upload" />
        <Step n={3} cur={step} label="Review & dedupe" />
        <Step n={4} cur={step} label="Done" />
      </div>

      {step === 1 && <div className="imp-sources">
        <div className="card imp-source" onClick={() => setStep(2)}>
          <div className="imp-source-ico">⌗</div>
          <h3>Properties from a spreadsheet</h3>
          <p>Copy rows out of Google Sheets, Excel or a CSV file. Owners match by name or email, duplicates are flagged before anything is written.</p>
          <span className="pmd-mono imp-go">Start →</span>
        </div>
        <div className="card imp-source" onClick={() => { try { sessionStorage.setItem('pm-intent-expense-capture', '1'); } catch (e) {} go && go('expenses'); }}>
          <div className="imp-source-ico">−</div>
          <h3>Expenses CSV</h3>
          <p>Bulk-load historic costs — each row lands tagged to a property and an SA105 box.</p>
          <span className="pmd-mono imp-go">Opens the capture wizard →</span>
        </div>
        <div className="card imp-source" onClick={() => go && go('bank')}>
          <div className="imp-source-ico">⇄</div>
          <h3>Bank statement</h3>
          <p>Paste statement CSV or drop a PDF/photo — lines flow into the reconciliation inbox for smart matching.</p>
          <span className="pmd-mono imp-go">Opens in Bank →</span>
        </div>
        <div className="card imp-source" onClick={() => go && go('documents')}>
          <div className="imp-source-ico">▤</div>
          <h3>Certificates &amp; documents</h3>
          <p>Drop PDFs and photos — Claude extracts the type, dates and reference, and files each under its property.</p>
          <span className="pmd-mono imp-go">Opens in Documents →</span>
        </div>
      </div>}

      {step === 2 && <div className="card">
        <div className="card-head">
          <div><h3>Paste your property rows</h3><div className="sub">First row should be headers — any of: <span className="pmd-mono">address, postcode, borough, owner, owner_email, beds, baths, type, rent</span></div></div>
          <label className="btn btn-ghost btn-sm" style={{ cursor: 'pointer' }}>
            Upload .csv
            <input type="file" accept=".csv,text/csv" style={{ display: 'none' }} onChange={e => { const f = e.target.files[0]; if (!f) return; const r = new FileReader(); r.onload = ev => setCsv(String(ev.target.result || '')); r.readAsText(f); e.target.value = ''; }} />
          </label>
        </div>
        <div className="card-pad">
          {headroom != null && <div className="alert alert-info"><span className="ic">ℹ</span><div>Your plan allows <b>{cap}</b> properties and you have <b>{existing.length}</b> — room for {headroom} more. {headroom === 0 && <button className="linkbtn" onClick={openBilling}>Upgrade for more →</button>}</div></div>}
          <textarea className="pm-textarea" rows={12} value={csv} onChange={e => setCsv(e.target.value)} placeholder="address,postcode,borough,owner,beds,baths,type,rent…"></textarea>
          {error && <div className="alert alert-err" style={{ marginTop: 10 }}><span className="ic">⚠</span><div>{error}</div></div>}
          <div className="imp-actions">
            <button className="btn btn-ghost btn-sm" onClick={() => setStep(1)}>← Back</button>
            <button className="btn btn-ghost btn-sm" onClick={() => setCsv(SAMPLE_CSV)}>Try a sample</button>
            <span className="spacer-grow" />
            <button className="btn btn-primary btn-sm" style={{ width: 'auto' }} disabled={!csv.trim()} onClick={onParse}>Parse {Math.max(0, csv.split('\n').filter(l => l.trim()).length - 1)} rows →</button>
          </div>
        </div>
      </div>}

      {step === 3 && <React.Fragment>
        <div className="summary">
          <div className="sumcard"><div className="n">{parsed.length}</div><div className="l">Rows parsed</div></div>
          <div className={'sumcard' + (parsed.filter(r => r._duplicate).length ? ' warn' : '')}><div className="n">{parsed.filter(r => r._duplicate).length}</div><div className="l">Possible duplicates</div></div>
          <div className="sumcard ok"><div className="n">{importCount}</div><div className="l">Set to import</div></div>
        </div>
        {headroom != null && importCount > headroom && <div className="alert alert-info"><span className="ic">ℹ</span><div>{importCount} rows are set to import but your plan has room for {headroom}. The import stops cleanly at the limit — or <button className="linkbtn" onClick={openBilling}>upgrade first</button>.</div></div>}
        <div className="card" style={{ overflow: 'hidden' }}>
          <div style={{ overflowX: 'auto' }}><table className="prop-table">
            <thead><tr><th></th><th>Address</th><th>Postcode</th><th>Owner</th><th>Type</th><th>Rent</th><th>Status</th><th>Action</th></tr></thead>
            <tbody>
              {parsed.map(r => <tr key={r._idx} style={{ opacity: r._action === 'skip' ? .55 : 1 }}>
                <td className="pmd-mono" style={{ fontSize: 11, color: 'var(--ink-faint)' }}>{r._idx + 1}</td>
                <td><span className="prop-addr">{r.address || '—'}</span>{r.borough && <div className="prop-meta">{r.borough}</div>}</td>
                <td className="pmd-mono" style={{ fontSize: 12 }}>{r.postcode || '—'}</td>
                <td>{r.owner ? r.owner.name : (r.ownerRaw ? <span className="prop-meta" title="No matching owner — imports unassigned">{r.ownerRaw} ?</span> : <span className="prop-meta">—</span>)}</td>
                <td className="pmd-mono" style={{ fontSize: 12 }}>{r.type.toUpperCase()}{r.beds ? ' · ' + r.beds + 'b' : ''}</td>
                <td>{r.rent ? gbp(r.rent) : '—'}</td>
                <td>{r._invalid ? <span className="badge bad">missing address</span>
                  : r._duplicate ? <span className="badge warn" title={'Matches ' + r._duplicate.address}>duplicate?</span>
                  : <span className="badge ok">new</span>}</td>
                <td>
                  <select className="pm-input" style={{ padding: '5px 8px', fontSize: 12.5 }} value={r._action} disabled={r._invalid} onChange={e => setAction(r._idx, e.target.value)}>
                    <option value="import">Import</option>
                    <option value="skip">Skip</option>
                  </select>
                </td>
              </tr>)}
            </tbody>
          </table></div>
        </div>
        <div className="imp-actions" style={{ marginTop: 14 }}>
          <button className="btn btn-ghost btn-sm" onClick={() => setStep(2)}>← Back</button>
          <span className="spacer-grow" />
          <button className="btn btn-primary btn-sm" style={{ width: 'auto' }} disabled={importCount === 0 || busy} onClick={onCommit}>{busy ? 'Importing…' : 'Import ' + importCount + ' propert' + (importCount === 1 ? 'y' : 'ies') + ' →'}</button>
        </div>
      </React.Fragment>}

      {step === 4 && result && <div className="card">
        <div className="empty">
          <div className="ico">{result.done > 0 ? '✓' : '!'}</div>
          <h3>{result.done > 0 ? 'Imported ' + result.done + ' propert' + (result.done === 1 ? 'y' : 'ies') : 'Nothing imported'}</h3>
          <p>
            {result.skipped > 0 ? result.skipped + ' row' + (result.skipped === 1 ? '' : 's') + ' skipped (duplicates / opt-outs). ' : ''}
            {result.capHit ? 'The import stopped at your plan\u2019s property limit — ' + (result.attempted - result.done) + ' row' + (result.attempted - result.done === 1 ? '' : 's') + ' still to bring in. ' : ''}
            {result.err ? 'Some rows failed: ' + result.err : ''}
            {!result.capHit && !result.err && result.done > 0 ? 'Certificates, tenancies and finances can now be tracked against them.' : ''}
          </p>
          <div style={{ display: 'flex', gap: 8, justifyContent: 'center', flexWrap: 'wrap' }}>
            {result.capHit && <button className="btn btn-primary btn-sm" style={{ width: 'auto' }} onClick={openBilling}>Upgrade to finish the import</button>}
            <button className={'btn btn-sm ' + (result.capHit ? 'btn-ghost' : 'btn-primary')} style={{ width: 'auto' }} onClick={() => go && go('properties')}>View properties →</button>
            <button className="btn btn-ghost btn-sm" onClick={() => { setStep(1); setCsv(''); setParsed([]); setResult(null); }}>Import another batch</button>
          </div>
        </div>
      </div>}
    </React.Fragment>;
  }

  function ImportStyles() {
    return <style>{`
      .imp-steps { display: flex; gap: 8px; margin-bottom: 18px; flex-wrap: wrap; }
      .imp-step { display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 600; color: var(--ink-faint); padding: 7px 13px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); white-space: nowrap; }
      .imp-step.on { border-color: var(--ink); color: var(--ink); }
      .imp-step.done { background: var(--ok-soft); border-color: transparent; color: var(--ok); }
      .imp-step-n { width: 18px; height: 18px; border-radius: 50%; background: var(--surface-2); display: inline-flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; }
      .imp-step.on .imp-step-n { background: var(--ink); color: #fff; }
      .imp-step.done .imp-step-n { background: var(--ok); color: #fff; }
      .imp-sources { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
      .imp-sources > .card { margin-top: 0; }
      .imp-source { padding: 18px 20px; cursor: pointer; transition: border-color .12s, transform .1s; display: flex; flex-direction: column; gap: 8px; }
      .imp-source:hover { border-color: var(--ink-faint); transform: translateY(-1px); }
      .imp-source-ico { width: 40px; height: 40px; border-radius: 11px; background: var(--brand-soft); color: var(--brand-deep); display: inline-flex; align-items: center; justify-content: center; font-size: 19px; font-weight: 700; }
      .imp-source h3 { font-size: 15px; }
      .imp-source p { margin: 0; font-size: 12.5px; color: var(--ink-faint); line-height: 1.5; flex: 1; }
      .imp-go { font-size: 11px; color: var(--brand-deep); }
      .imp-actions { display: flex; align-items: center; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
    `}</style>;
  }

  window.PMImportHub = ImportHub;
})();
