// Tempo — Import & Sync modal (CSV / brokers / manual)
// Real CSV parser with MT5 / Tradovate / generic detection + manual trade form.

// ─── CSV parsing ─────────────────────────────────────────────────
// Simple CSV/TSV parser supporting quoted fields and either commas/semicolons/tabs.
function parseCSV(text) {
  if (!text) return { headers: [], rows: [] };
  // Detect delimiter from first line
  const firstLine = text.slice(0, text.indexOf('\n') >= 0 ? text.indexOf('\n') : text.length);
  let delim = ',';
  const counts = { ',': (firstLine.match(/,/g) || []).length, ';': (firstLine.match(/;/g) || []).length, '\t': (firstLine.match(/\t/g) || []).length };
  if (counts['\t'] > counts[','] && counts['\t'] > counts[';']) delim = '\t';
  else if (counts[';'] > counts[',']) delim = ';';

  const rows = [];
  let cur = [], field = '', inQ = false;
  for (let i = 0; i < text.length; i++) {
    const c = text[i];
    if (inQ) {
      if (c === '"') {
        if (text[i + 1] === '"') { field += '"'; i++; }
        else { inQ = false; }
      } else { field += c; }
    } else {
      if (c === '"') { inQ = true; }
      else if (c === delim) { cur.push(field); field = ''; }
      else if (c === '\n') { cur.push(field); rows.push(cur); cur = []; field = ''; }
      else if (c === '\r') { /* skip */ }
      else { field += c; }
    }
  }
  if (field.length > 0 || cur.length > 0) { cur.push(field); rows.push(cur); }
  // Trim & drop empty rows
  const cleaned = rows.map(r => r.map(c => (c || '').trim())).filter(r => r.some(c => c !== ''));
  if (cleaned.length === 0) return { headers: [], rows: [] };
  return { headers: cleaned[0], rows: cleaned.slice(1) };
}

// MT5 HTML report parser (extracts deals from <table>)
function parseMT5Html(text) {
  // Find each <tr> ... </tr> block and split TD/TH
  const trs = text.match(/<tr[^>]*>([\s\S]*?)<\/tr>/gi) || [];
  const rows = trs.map(tr => {
    const tds = (tr.match(/<t[dh][^>]*>([\s\S]*?)<\/t[dh]>/gi) || [])
      .map(td => td.replace(/<[^>]+>/g, '').replace(/&nbsp;/g, ' ').trim());
    return tds;
  }).filter(r => r.length > 0);
  if (rows.length === 0) return { headers: [], rows: [] };
  // Locate the "deals" or "orders" header row (look for a row containing Time AND Price AND Profit)
  let headerIdx = -1;
  for (let i = 0; i < rows.length; i++) {
    const joined = rows[i].join('|').toLowerCase();
    if (joined.includes('time') && (joined.includes('price') || joined.includes('profit') || joined.includes('volume'))) {
      headerIdx = i; break;
    }
  }
  if (headerIdx === -1) return { headers: rows[0] || [], rows: rows.slice(1) };
  const headers = rows[headerIdx];
  // Data rows are those after, with same column count and numeric values
  const data = [];
  for (let i = headerIdx + 1; i < rows.length; i++) {
    if (rows[i].length < headers.length - 1) break;
    data.push(rows[i]);
  }
  return { headers, rows: data };
}

function detectFormat(headers, fileName, rawText) {
  const h = headers.map(x => x.toLowerCase());
  const name = (fileName || '').toLowerCase();
  const raw = (rawText || '').slice(0, 4000).toLowerCase();
  if (name.endsWith('.htm') || name.endsWith('.html') || raw.includes('metatrader') || raw.includes('<table')) return 'mt5_html';
  if (h.some(x => /position/.test(x)) && h.some(x => /symbol/.test(x)) && h.some(x => /(profit|p\/l)/.test(x))) return 'mt5_csv';
  if (h.some(x => /tradedate|filltime|fillprice/.test(x))) return 'tradovate';
  return 'generic';
}

function findIndex(headers, ...candidates) {
  const low = headers.map(h => h.toLowerCase().replace(/\s+/g, ''));
  for (const cand of candidates) {
    const c = cand.toLowerCase().replace(/\s+/g, '');
    const idx = low.indexOf(c);
    if (idx >= 0) return idx;
    const fuzzy = low.findIndex(h => h.includes(c));
    if (fuzzy >= 0) return fuzzy;
  }
  return -1;
}

function parseNumber(v) {
  if (v === null || v === undefined || v === '') return null;
  const s = String(v).replace(/\s/g, '').replace(/[^\d\.\-,eE]/g, '').replace(',', '.');
  const n = parseFloat(s);
  return Number.isFinite(n) ? n : null;
}

function parseDateLoose(s) {
  if (!s) return null;
  s = String(s).trim();
  // ISO-ish "2024-05-21 14:32:00"
  if (/^\d{4}-\d{2}-\d{2}/.test(s)) {
    const d = new Date(s.replace(' ', 'T'));
    if (!isNaN(d.getTime())) return d.toISOString();
  }
  // "2024.05.21 14:32:00" (MT5)
  const mt5 = s.match(/^(\d{4})\.(\d{2})\.(\d{2})\s+(\d{2}):(\d{2})(?::(\d{2}))?/);
  if (mt5) {
    const d = new Date(Date.UTC(+mt5[1], +mt5[2] - 1, +mt5[3], +mt5[4], +mt5[5], +(mt5[6] || 0)));
    if (!isNaN(d.getTime())) return d.toISOString();
  }
  // "DD/MM/YYYY HH:MM" or "MM/DD/YYYY HH:MM"
  const slash = s.match(/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})(?:\s+(\d{1,2}):(\d{2})(?::(\d{2}))?)?/);
  if (slash) {
    let [_, a, b, y, hh, mm, ss] = slash;
    if (y.length === 2) y = '20' + y;
    // Assume DD/MM/YYYY (FR) if a > 12
    let dd, mo;
    if (+a > 12) { dd = +a; mo = +b; }
    else { dd = +b; mo = +a; }
    const d = new Date(Date.UTC(+y, mo - 1, dd, +(hh || 0), +(mm || 0), +(ss || 0)));
    if (!isNaN(d.getTime())) return d.toISOString();
  }
  const fallback = new Date(s);
  if (!isNaN(fallback.getTime())) return fallback.toISOString();
  return null;
}

function rowsToTrades(headers, rows, format) {
  if (format === 'mt5_csv' || format === 'mt5_html') {
    const ci = {
      time:     findIndex(headers, 'Time', 'Close Time', 'CloseTime'),
      symbol:   findIndex(headers, 'Symbol'),
      type:     findIndex(headers, 'Type', 'Direction', 'Side'),
      volume:   findIndex(headers, 'Volume', 'Lots', 'Size'),
      price:    findIndex(headers, 'Price', 'Close Price', 'ClosePrice'),
      entry:    findIndex(headers, 'Open Price', 'Entry', 'Price', 'OpenPrice'),
      profit:   findIndex(headers, 'Profit', 'P/L', 'Net Profit', 'NetProfit', 'PnL'),
      comm:     findIndex(headers, 'Commission', 'Fees'),
      swap:     findIndex(headers, 'Swap', 'Rollover'),
      pos:      findIndex(headers, 'Position', 'Order', 'Deal', 'Ticket'),
    };
    return rows.map(r => {
      const profit = parseNumber(r[ci.profit]) || 0;
      const comm   = parseNumber(r[ci.comm])   || 0;
      const swap   = parseNumber(r[ci.swap])   || 0;
      const type   = String(r[ci.type] || '').toLowerCase();
      const dir    = /sell|short/.test(type) ? 'short' : 'long';
      return {
        symbol: r[ci.symbol] || '',
        direction: dir,
        entry: parseNumber(r[ci.entry]),
        exit_price: parseNumber(r[ci.price]),
        lots: parseNumber(r[ci.volume]) ?? 1,
        pnl: profit + comm + swap,
        r_multiple: null,
        executed_at: parseDateLoose(r[ci.time]) || new Date().toISOString(),
        external_id: r[ci.pos] || null,
        imported_from: 'mt5',
        setup: null,
        notes: null,
      };
    }).filter(t => t.symbol);
  }
  if (format === 'tradovate') {
    const ci = {
      time:    findIndex(headers, 'FillTime', 'TradeDate', 'Time'),
      symbol:  findIndex(headers, 'Symbol', 'Contract'),
      side:    findIndex(headers, 'BuySell', 'Side', 'Direction'),
      qty:     findIndex(headers, 'Qty', 'Quantity', 'FillQty'),
      price:   findIndex(headers, 'FillPrice', 'Price', 'AvgPrice'),
      pnl:     findIndex(headers, 'PnL', 'P&L', 'Profit', 'NetProfit'),
      ticket:  findIndex(headers, 'OrderId', 'TradeId', 'Id'),
    };
    return rows.map(r => ({
      symbol: r[ci.symbol] || '',
      direction: /sell|short|s$/i.test(r[ci.side] || '') ? 'short' : 'long',
      entry: null,
      exit_price: parseNumber(r[ci.price]),
      lots: parseNumber(r[ci.qty]) ?? 1,
      pnl: parseNumber(r[ci.pnl]) || 0,
      r_multiple: null,
      executed_at: parseDateLoose(r[ci.time]) || new Date().toISOString(),
      external_id: r[ci.ticket] || null,
      imported_from: 'tradovate',
      setup: null, notes: null,
    })).filter(t => t.symbol);
  }
  // Generic mapping
  const ci = {
    date:    findIndex(headers, 'Date', 'Time', 'ExecutedAt', 'CloseTime', 'TradeDate'),
    symbol:  findIndex(headers, 'Symbol', 'Ticker', 'Pair', 'Instrument'),
    side:    findIndex(headers, 'Direction', 'Side', 'Type', 'BuySell'),
    entry:   findIndex(headers, 'EntryPrice', 'Open', 'OpenPrice', 'Entry'),
    exit:    findIndex(headers, 'ExitPrice', 'Close', 'ClosePrice', 'Exit', 'Price'),
    qty:     findIndex(headers, 'Qty', 'Quantity', 'Lots', 'Size', 'Volume'),
    pnl:     findIndex(headers, 'P&L', 'PnL', 'Profit', 'NetProfit'),
    r:       findIndex(headers, 'R', 'R-Multiple', 'RMultiple'),
    setup:   findIndex(headers, 'Setup', 'Strategy', 'Playbook'),
    notes:   findIndex(headers, 'Notes', 'Comment', 'Comments'),
    id:      findIndex(headers, 'Id', 'TradeId', 'OrderId', 'Ticket'),
  };
  return rows.map(r => ({
    symbol: r[ci.symbol] || '',
    direction: /sell|short|s$/i.test(r[ci.side] || '') ? 'short' : 'long',
    entry: parseNumber(r[ci.entry]),
    exit_price: parseNumber(r[ci.exit]),
    lots: parseNumber(r[ci.qty]) ?? 1,
    pnl: parseNumber(r[ci.pnl]) || 0,
    r_multiple: parseNumber(r[ci.r]),
    setup: ci.setup >= 0 ? r[ci.setup] : null,
    notes: ci.notes >= 0 ? r[ci.notes] : null,
    executed_at: parseDateLoose(r[ci.date]) || new Date().toISOString(),
    external_id: ci.id >= 0 ? r[ci.id] : null,
    imported_from: 'generic',
  })).filter(t => t.symbol);
}

// ─── Manual form ─────────────────────────────────────────────────
// Sentinel returned by the form's number parser for non-empty, non-numeric input.
const INVALID_NUM = Symbol('invalid-num');

function ManualTradeForm({ onSubmit, submitting, defaultDate }) {
  // Jour local "YYYY-MM-DD" pour un Date donné (sert de défaut au champ date).
  const localDay = (d) => {
    const y = d.getFullYear(), m = String(d.getMonth() + 1).padStart(2, '0'), dd = String(d.getDate()).padStart(2, '0');
    return `${y}-${m}-${dd}`;
  };
  // Heure locale "HH:MM" pour un Date donné.
  const localTime = (d) => {
    const hh = String(d.getHours()).padStart(2, '0'), mm = String(d.getMinutes()).padStart(2, '0');
    return `${hh}:${mm}`;
  };
  // Jour de départ : si un defaultDate (jour "YYYY-MM-DD" ou ISO complet) est fourni — p. ex.
  // depuis un jour cliqué du calendrier — on l'utilise ; sinon aujourd'hui en heure locale.
  const seedDay = () => {
    if (defaultDate && typeof defaultDate === 'string') {
      const dayPart = defaultDate.slice(0, 10);
      if (/^\d{4}-\d{2}-\d{2}$/.test(dayPart)) return dayPart;
    }
    return localDay(new Date());
  };
  const [form, setForm] = React.useState(() => ({
    symbol: '', direction: 'long',
    entry: '', exit_price: '',
    lots: '1', pnl: '', r_multiple: '',
    trade_date: seedDay(),         // jour explicite, défaut = aujourd'hui (local)
    trade_time: localTime(new Date()), // heure optionnelle, défaut = maintenant (local)
    setup: '', notes: '',
  }));
  // Quand defaultDate change (modal rouvert depuis un autre jour), on resème le jour.
  // Ne doit pas écraser le symbole/notes déjà saisis.
  React.useEffect(() => {
    setForm(f => ({ ...f, trade_date: seedDay() }));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [defaultDate]);
  // Libellé lisible du jour ciblé ("22 juin 2026"), affiché sans ambiguïté au-dessus du formulaire.
  const dateLabel = (() => {
    const dp = form.trade_date;
    if (!/^\d{4}-\d{2}-\d{2}$/.test(dp || '')) return '';
    const [y, m, d] = dp.split('-').map(Number);
    const dt = new Date(y, m - 1, d); // construit en local → pas de décalage
    if (isNaN(dt.getTime())) return '';
    try {
      return dt.toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' });
    } catch (_) { return dp; }
  })();
  // Décale le jour ciblé de ±1 via les flèches de la bannière (comme dans l'agenda),
  // sans jamais dépasser aujourd'hui (pas de trade dans le futur).
  const shiftTradeDate = (delta) => {
    // On dérive depuis l'état précédent (f) pour rester exact même sur clics rapides successifs.
    setForm(f => {
      const dp = /^\d{4}-\d{2}-\d{2}$/.test(f.trade_date || '') ? f.trade_date : localDay(new Date());
      const [y, m, d] = dp.split('-').map(Number);
      let next = localDay(new Date(y, m - 1, d + delta));
      const today = localDay(new Date());
      if (next > today) next = today;
      return { ...f, trade_date: next };
    });
  };
  const [formErr, setFormErr] = React.useState('');
  const upd = (k) => (e) => { setForm(f => ({ ...f, [k]: e.target.value })); if (formErr) setFormErr(''); };

  // Parse a French/EN decimal string ("1 234,5" / "1234.5") → number, or null if blank.
  // Returns the sentinel INVALID_NUM for non-empty, non-numeric input so we can warn.
  const parseNum = (raw) => {
    if (raw == null || String(raw).trim() === '') return null;
    const n = parseFloat(String(raw).replace(/\s/g, '').replace(',', '.'));
    return Number.isFinite(n) ? n : INVALID_NUM;
  };

  const submit = (e) => {
    e.preventDefault();
    // Garde anti double-soumission : ignore si un envoi est déjà en cours.
    if (submitting) return;
    // 1) Symbole obligatoire
    const symbol = form.symbol.trim();
    if (!symbol) { setFormErr('Le symbole est obligatoire (ex. ES, NQ, EURUSD).'); return; }

    // 2) Champs numériques : refuse les valeurs non numériques au lieu de les enregistrer à 0/null.
    const numeric = [
      { key: 'entry', label: "Prix d'entrée" },
      { key: 'exit_price', label: 'Prix de sortie' },
      { key: 'lots', label: 'Quantité / Lots' },
      { key: 'pnl', label: 'P&L' },
      { key: 'r_multiple', label: 'R-multiple' },
    ];
    const parsed = {};
    for (const f of numeric) {
      const v = parseNum(form[f.key]);
      if (v === INVALID_NUM) { setFormErr(`« ${f.label} » doit être un nombre valide.`); return; }
      parsed[f.key] = v;
    }
    // Lots, si renseigné, doit être strictement positif.
    if (parsed.lots != null && parsed.lots <= 0) { setFormErr('La quantité / lots doit être supérieure à 0.'); return; }

    // 3) Date valide — le jour est obligatoire et explicite ; l'heure est optionnelle.
    const dayStr = (form.trade_date || '').trim();
    if (!/^\d{4}-\d{2}-\d{2}$/.test(dayStr)) { setFormErr('La date du trade est invalide.'); return; }
    const timeStr = /^\d{1,2}:\d{2}$/.test((form.trade_time || '').trim())
      ? form.trade_time.trim()
      : '00:00';
    const [yy, mo, dd] = dayStr.split('-').map(Number);
    const [hh, mi] = timeStr.split(':').map(Number);
    // localDate = vrai instant en heure locale du navigateur ; .toISOString() donne
    // l'instant UTC réel, que localDayInTz reprojette ensuite sur le bon jour local.
    // (Cohérent avec l'import CSV et le formulaire d'édition qui font déjà .toISOString().)
    const localDate = new Date(yy, mo - 1, dd, hh || 0, mi || 0, 0, 0);
    if (isNaN(localDate.getTime())) { setFormErr('La date du trade est invalide.'); return; }
    const executedAt = localDate.toISOString();

    setFormErr('');
    onSubmit({
      symbol,
      direction: form.direction,
      entry: parsed.entry,
      exit_price: parsed.exit_price,
      lots: parsed.lots,
      pnl: parsed.pnl,
      r_multiple: parsed.r_multiple,
      executed_at: executedAt,
      setup: form.setup.trim() || null,
      notes: form.notes.trim() || null,
    });
  };

  return (
    <form onSubmit={submit}>
      <div style={{ fontSize: 12.5, color: 'var(--fg-2)', marginBottom: 14 }}>
        Ajoute un trade à la main — utile pour les trades hors broker connecté.
      </div>
      {dateLabel && (
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8,
          marginBottom: 14, padding: '7px 9px 7px 12px', borderRadius: 8,
          background: 'var(--blue-soft)', border: '1px solid var(--blue-border)',
          color: 'var(--blue)', fontSize: 12.5, fontWeight: 600,
        }}>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
            {React.cloneElement(Ico.daily || Ico.data, { width: 15, height: 15 })}
            <span style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>Trade ajouté au&nbsp;: {dateLabel}</span>
          </span>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, flexShrink: 0 }}>
            <button type="button" onClick={() => shiftTradeDate(-1)} title="Jour précédent" className="tap" style={{ width: 26, height: 26, borderRadius: 7, border: '1px solid var(--blue-border)', background: 'var(--bg-card)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', color: 'var(--blue)' }}>{Ico.arrL}</button>
            <button type="button" onClick={() => shiftTradeDate(1)} title="Jour suivant" className="tap" style={{ width: 26, height: 26, borderRadius: 7, border: '1px solid var(--blue-border)', background: 'var(--bg-card)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', color: 'var(--blue)' }}>{Ico.arrR}</button>
          </span>
        </div>
      )}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        <div>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Symbole *</label>
          <input className="input" value={form.symbol} onChange={upd('symbol')} placeholder="ES, NQ, EURUSD…" required/>
        </div>
        <div>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Direction</label>
          <select className="input" value={form.direction} onChange={upd('direction')} style={{ fontFamily: 'inherit' }}>
            <option value="long">LONG</option>
            <option value="short">SHORT</option>
          </select>
        </div>
        <div>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Prix d'entrée</label>
          <input className="input" value={form.entry} onChange={upd('entry')} placeholder="5278.50" inputMode="decimal"/>
        </div>
        <div>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Prix de sortie</label>
          <input className="input" value={form.exit_price} onChange={upd('exit_price')} placeholder="5284.00" inputMode="decimal"/>
        </div>
        <div>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Quantité / Lots</label>
          <input className="input" value={form.lots} onChange={upd('lots')} placeholder="1" inputMode="decimal"/>
        </div>
        <div>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Date du trade *</label>
          <input className="input" type="date" value={form.trade_date} onChange={upd('trade_date')} max={localDay(new Date())} required/>
        </div>
        <div>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Heure (optionnel)</label>
          <input className="input" type="time" value={form.trade_time} onChange={upd('trade_time')}/>
        </div>
        <div>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>P&L ($)</label>
          <input className="input" value={form.pnl} onChange={upd('pnl')} placeholder="+120 ou -50" inputMode="decimal"/>
        </div>
        <div>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>R-multiple</label>
          <input className="input" value={form.r_multiple} onChange={upd('r_multiple')} placeholder="+1.5 ou -1" inputMode="decimal"/>
        </div>
        <div style={{ gridColumn: '1 / -1' }}>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Setup</label>
          <input className="input" value={form.setup} onChange={upd('setup')} placeholder="Breakout VWAP, Range Asie…"/>
        </div>
        <div style={{ gridColumn: '1 / -1' }}>
          <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Notes</label>
          <textarea className="input" value={form.notes} onChange={upd('notes')} style={{ minHeight: 80, resize: 'vertical', fontFamily: 'inherit' }} placeholder="Pourquoi ce trade ? Setup, contexte…"/>
        </div>
      </div>
      {formErr && (
        <div style={{ marginTop: 14, padding: '9px 12px', borderRadius: 8, background: 'var(--red-soft)', border: '1px solid var(--red)', color: 'var(--red-text)', fontSize: 12.5 }}>
          {formErr}
        </div>
      )}
      <div style={{ marginTop: 16, display: 'flex', justifyContent: 'flex-end' }}>
        <button type="submit" disabled={submitting || !form.symbol.trim()} className="btn btn-blue tap" style={{ opacity: submitting || !form.symbol.trim() ? .6 : 1 }}>
          {submitting ? 'Enregistrement…' : <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>{Ico.plus} Ajouter le trade</span>}
        </button>
      </div>
    </form>
  );
}

// ─── Modal ───────────────────────────────────────────────────────
function ImportModal({ open, onClose, state, defaultDate }) {
  const [tab, setTab] = React.useState('csv'); // 'csv' | 'broker' | 'manual'
  const [dragOver, setDragOver] = React.useState(false);
  const [files, setFiles] = React.useState([]); // { id, name, size, status, parsed: [], error?, format }
  const [submitting, setSubmitting] = React.useState(false);
  const [importMsg, setImportMsg] = React.useState('');
  const [manualMsg, setManualMsg] = React.useState('');
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    if (!open) {
      setFiles([]); setImportMsg(''); setManualMsg(''); setDragOver(false);
    }
  }, [open]);

  if (!open) return null;

  const handleFiles = async (fileList) => {
    const arr = Array.from(fileList);
    for (const f of arr) {
      const id = Math.random().toString(36).slice(2);
      setFiles(prev => [...prev, { id, name: f.name, size: f.size, status: 'parsing', parsed: [] }]);
      try {
        const text = await readFileAsText(f);
        const isHtml = /\.(html?|htm)$/i.test(f.name) || /<table/i.test(text.slice(0, 500));
        let headers, rows, format;
        if (isHtml) {
          const r = parseMT5Html(text);
          headers = r.headers; rows = r.rows;
          format = 'mt5_html';
        } else {
          const r = parseCSV(text);
          headers = r.headers; rows = r.rows;
          format = detectFormat(headers, f.name, text);
        }
        const parsed = rowsToTrades(headers, rows, format);
        setFiles(prev => prev.map(x => x.id === id ? { ...x, status: 'ready', parsed, format } : x));
      } catch (err) {
        console.error('[Tempo] parse', err);
        setFiles(prev => prev.map(x => x.id === id ? { ...x, status: 'error', error: err.message || 'Parse error' } : x));
      }
    }
  };

  const startImport = async () => {
    if (!window.sb) return;
    const allTrades = files.flatMap(f => f.parsed || []);
    if (allTrades.length === 0) { setImportMsg('Aucun trade détecté dans les fichiers.'); return; }
    setSubmitting(true);
    setImportMsg('Import en cours…');
    const { data, error, skipped } = await bulkInsertTrades(allTrades);
    setSubmitting(false);
    if (error) {
      setImportMsg('Erreur: ' + (error.message || 'Import échoué'));
      return;
    }
    const inserted = data?.length || 0;
    const dup = skipped || 0;
    setImportMsg(`Import terminé : ${inserted} trade${inserted > 1 ? 's' : ''} ajouté${inserted > 1 ? 's' : ''}${dup ? `, ${dup} doublon${dup > 1 ? 's' : ''} ignoré${dup > 1 ? 's' : ''}` : ''}.`);
    setFiles(prev => prev.map(f => ({ ...f, status: 'done' })));
    if (state?.refreshTrades) state.refreshTrades();
    setTimeout(() => { onClose && onClose(true); }, 1200);
  };

  const submitManual = async (payload) => {
    setSubmitting(true);
    setManualMsg('');
    const { data, error } = await addTrade(payload);
    setSubmitting(false);
    if (error) { setManualMsg('Erreur: ' + (error.message || 'Échec de l\'enregistrement')); return; }
    setManualMsg('Trade ajouté avec succès.');
    if (state?.refreshTrades) await state.refreshTrades();
    setTimeout(() => { onClose && onClose(true); }, 700);
  };

  const removeFile = (id) => setFiles(prev => prev.filter(f => f.id !== id));
  const totalParsed = files.reduce((s, f) => s + (f.parsed?.length || 0), 0);
  const allReady    = files.length > 0 && files.every(f => f.status === 'ready' || f.status === 'done');

  // Brokers list — UI only (read-only)
  const brokers = [
    { id: 'mt5',         name: 'MetaTrader 5',  sub: 'CFD, Forex, Futures',     status: 'available' },
    { id: 'tradovate',   name: 'Tradovate',     sub: 'Futures CME, ES, NQ',     status: 'available' },
    { id: 'topstep',     name: 'TopStep',       sub: 'Prop firm · 50K combine', status: 'available' },
    { id: 'ninjatrader', name: 'NinjaTrader',   sub: 'Futures, Forex',          status: 'available' },
    { id: 'tradingview', name: 'TradingView',   sub: 'Paper & live trading',    status: 'available' },
    { id: 'mt4',         name: 'MetaTrader 4',  sub: 'Forex traditionnel',      status: 'available' },
  ];

  return (
    <div onClick={() => onClose && onClose(false)} style={{
      position: 'fixed', inset: 0, zIndex: 200,
      background: 'rgba(15,23,42,0.40)',
      backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 24, animation: 'fade-in .25s var(--ease)',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 760, maxHeight: '92%',
        background: 'var(--bg-card)', borderRadius: 16,
        overflow: 'hidden', display: 'flex', flexDirection: 'column',
        boxShadow: '0 28px 56px rgba(0,0,0,.24)',
        animation: 'fade-up .35s var(--ease)',
      }}>
        {/* Header */}
        <div style={{ padding: '20px 24px 14px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div>
            <div style={{ fontSize: 17, fontWeight: 700, letterSpacing: '-.015em', color: 'var(--fg)' }}>Importer mes trades</div>
            <div style={{ fontSize: 12, color: 'var(--fg-2)', marginTop: 4 }}>Dépose un CSV/HTML d'export broker ou saisis un trade à la main — Tempo détecte le format automatiquement.</div>
          </div>
          <button onClick={() => onClose && onClose(false)} className="tap" style={{ width: 30, height: 30, borderRadius: 8, border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--fg-2)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{Ico.x}</button>
        </div>

        {/* Tabs */}
        <div style={{ padding: '12px 24px 0' }}>
          <div style={{ display: 'inline-flex', gap: 4, padding: 4, background: 'var(--bg-elev)', borderRadius: 10 }}>
            {[
              { id: 'csv',    l: 'Fichier CSV',      ico: Ico.upload },
              { id: 'manual', l: 'Saisie manuelle',  ico: Ico.plus },
              { id: 'broker', l: 'Connecter broker', ico: Ico.sync },
            ].map(t => (
              <button key={t.id} onClick={() => setTab(t.id)} className="tap" style={{
                background: tab === t.id ? 'var(--bg-card)' : 'transparent',
                color: tab === t.id ? 'var(--blue-600)' : 'var(--fg-2)',
                border: tab === t.id ? '1.5px solid var(--blue)' : '1.5px solid transparent',
                borderRadius: 7, padding: '6px 14px', fontSize: 12.5, fontWeight: tab === t.id ? 600 : 500,
                cursor: 'pointer', fontFamily: 'inherit',
                display: 'inline-flex', alignItems: 'center', gap: 8,
              }}>{t.ico} {t.l}</button>
            ))}
          </div>
        </div>

        {/* Body */}
        <div className="scroll" style={{ flex: 1, overflow: 'auto', padding: '18px 24px 22px' }}>
          {tab === 'csv' && (
            <div>
              <div
                onDragOver={e => { e.preventDefault(); setDragOver(true); }}
                onDragLeave={() => setDragOver(false)}
                onDrop={e => {
                  e.preventDefault(); setDragOver(false);
                  if (e.dataTransfer.files) handleFiles(e.dataTransfer.files);
                }}
                onClick={() => inputRef.current && inputRef.current.click()}
                style={{
                  border: '1.5px dashed ' + (dragOver ? 'var(--blue)' : 'var(--line-2)'),
                  background: dragOver ? 'var(--blue-soft)' : 'var(--bg-soft)',
                  borderRadius: 12, padding: '40px 20px', textAlign: 'center',
                  cursor: 'pointer', transition: 'all .15s var(--ease)',
                }}>
                <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 12, color: dragOver ? 'var(--blue)' : 'var(--fg-2)' }}>
                  {React.cloneElement(Ico.upload, { width: 32, height: 32 })}
                </div>
                <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--fg)', marginBottom: 4 }}>
                  {dragOver ? 'Relâche pour ajouter' : 'Glisse tes fichiers ici'}
                </div>
                <div style={{ fontSize: 12, color: 'var(--fg-2)' }}>ou clique pour parcourir · CSV, HTML, TSV</div>
                <input ref={inputRef} type="file" accept=".csv,.tsv,.htm,.html,.txt" multiple style={{ display: 'none' }}
                  onChange={e => e.target.files && handleFiles(e.target.files)}/>
              </div>

              <div style={{ display: 'flex', gap: 8, marginTop: 14, flexWrap: 'wrap' }}>
                {['MetaTrader 5 (CSV/HTML)', 'Tradovate', 'Format générique'].map(f => (
                  <span key={f} style={{ padding: '4px 10px', borderRadius: 999, background: 'var(--bg-elev)', color: 'var(--fg-2)', fontSize: 11, fontWeight: 500, border: '1px solid var(--line)' }}>{f}</span>
                ))}
              </div>

              {files.length > 0 && (
                <div style={{ marginTop: 18 }}>
                  <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--fg-2)', marginBottom: 8 }}>
                    {files.length} fichier{files.length > 1 ? 's' : ''} · {totalParsed} trade{totalParsed > 1 ? 's' : ''} détecté{totalParsed > 1 ? 's' : ''}
                  </div>
                  <div style={{ border: '1px solid var(--line)', borderRadius: 10, overflow: 'hidden' }}>
                    {files.map((f, i) => (
                      <div key={f.id} style={{
                        padding: '11px 14px', display: 'grid', gridTemplateColumns: '24px 1fr 100px 90px 28px', gap: 10, alignItems: 'center',
                        borderTop: i ? '1px solid var(--line)' : 'none',
                        background: f.status === 'done' ? 'var(--green-soft)' : f.status === 'error' ? 'var(--red-soft)' : 'var(--bg-card)',
                      }}>
                        <div style={{ color: f.status === 'done' ? 'var(--green)' : f.status === 'error' ? 'var(--red)' : 'var(--fg-2)' }}>
                          {f.status === 'done' ? (
                            <span style={{ display: 'inline-flex', width: 18, height: 18, borderRadius: 999, background: 'var(--green)', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>{Ico.check}</span>
                          ) : f.status === 'error' ? (
                            React.cloneElement(Ico.x, { width: 18, height: 18 })
                          ) : (
                            React.cloneElement(Ico.data, { width: 16, height: 16 })
                          )}
                        </div>
                        <div>
                          <div style={{ fontSize: 13, fontWeight: 500, color: 'var(--fg)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{f.name}</div>
                          <div style={{ fontSize: 10.5, color: 'var(--fg-3)', marginTop: 2 }}>
                            {f.status === 'parsing' ? 'Analyse…' :
                             f.status === 'error' ? `Erreur: ${f.error}` :
                             `Format ${f.format || '—'}`}
                          </div>
                        </div>
                        <span className="mono" style={{ fontSize: 11, color: 'var(--fg-3)' }}>{(f.size / 1024).toFixed(0)} ko</span>
                        <span style={{ fontSize: 11, fontWeight: 600, color: f.parsed?.length ? 'var(--blue-600)' : 'var(--fg-3)' }}>
                          {f.parsed?.length ? `${f.parsed.length} trades` : '—'}
                        </span>
                        <button onClick={() => removeFile(f.id)} className="tap" style={{ background: 'transparent', border: 'none', cursor: 'pointer', color: 'var(--fg-3)', padding: 4, display: 'flex' }}>{Ico.x}</button>
                      </div>
                    ))}
                  </div>

                  {/* Preview first parsed file */}
                  {files[0]?.parsed?.length > 0 && (
                    <div style={{ marginTop: 14 }}>
                      <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--fg-3)', letterSpacing: '.06em', textTransform: 'uppercase', marginBottom: 6 }}>Aperçu (premières lignes)</div>
                      <div style={{ border: '1px solid var(--line)', borderRadius: 8, overflow: 'hidden', fontSize: 11 }}>
                        <div style={{ display: 'grid', gridTemplateColumns: '60px 60px 50px 80px 80px 1fr 90px', padding: '8px 10px', background: 'var(--bg-soft)', borderBottom: '1px solid var(--line)', fontWeight: 600, color: 'var(--fg-3)', letterSpacing: '.04em' }}>
                          <span>DATE</span><span>SYM</span><span>DIR</span><span>ENTRY</span><span>EXIT</span><span>SETUP</span><span style={{ textAlign: 'right' }}>P&L</span>
                        </div>
                        {files[0].parsed.slice(0, 6).map((t, i) => (
                          <div key={i} style={{ display: 'grid', gridTemplateColumns: '60px 60px 50px 80px 80px 1fr 90px', padding: '8px 10px', borderTop: i ? '1px solid var(--line)' : 'none', alignItems: 'center' }}>
                            <span style={{ color: 'var(--fg-3)' }}>{(t.executed_at || '').slice(5, 10)}</span>
                            <span style={{ fontWeight: 600 }}>{t.symbol}</span>
                            <span style={{ color: t.direction === 'long' ? 'var(--green)' : 'var(--red)', fontWeight: 600 }}>{t.direction === 'long' ? 'L' : 'S'}</span>
                            <span className="mono">{t.entry ?? '—'}</span>
                            <span className="mono">{t.exit_price ?? '—'}</span>
                            <span style={{ color: 'var(--fg-3)' }}>{t.setup || '—'}</span>
                            <span className="mono" style={{ textAlign: 'right', color: t.pnl >= 0 ? 'var(--green)' : 'var(--red)', fontWeight: 600 }}>
                              {t.pnl >= 0 ? '+$' : '−$'}{Math.abs(t.pnl).toFixed(2)}
                            </span>
                          </div>
                        ))}
                      </div>
                    </div>
                  )}

                  {importMsg && (
                    <div style={{ marginTop: 12, padding: '8px 10px', borderRadius: 8, background: 'var(--bg-soft)', fontSize: 12, color: 'var(--fg-2)' }}>{importMsg}</div>
                  )}
                </div>
              )}
            </div>
          )}

          {tab === 'broker' && (
            <div>
              <div style={{ fontSize: 12.5, color: 'var(--fg-2)', marginBottom: 14 }}>
                La sync directe avec les brokers arrive bientôt. Pour l'instant, exporte un CSV depuis ta plateforme et importe-le dans l'onglet "Fichier CSV".
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {brokers.map(b => (
                  <div key={b.id} style={{
                    display: 'flex', alignItems: 'center', gap: 14,
                    padding: '14px 16px', borderRadius: 10,
                    border: '1px solid var(--line)', background: 'var(--bg-card)',
                  }}>
                    <div style={{ width: 36, height: 36, borderRadius: 8, background: 'var(--bg-elev)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--fg-2)' }}>
                      {React.cloneElement(Ico.sync, { width: 16, height: 16 })}
                    </div>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--fg)', letterSpacing: '-.005em' }}>{b.name}</div>
                      <div style={{ fontSize: 12, color: 'var(--fg-2)', marginTop: 2 }}>{b.sub}</div>
                    </div>
                    <button onClick={() => setTab('csv')} className="btn btn-outline-blue tap" style={{ fontSize: 12 }}>Importer via CSV</button>
                  </div>
                ))}
              </div>
            </div>
          )}

          {tab === 'manual' && (
            <div>
              <ManualTradeForm onSubmit={submitManual} submitting={submitting} defaultDate={defaultDate}/>
              {manualMsg && (
                <div style={{ marginTop: 12, padding: '8px 10px', borderRadius: 8, background: manualMsg.startsWith('Erreur') ? 'var(--red-soft)' : 'var(--green-soft)', color: manualMsg.startsWith('Erreur') ? 'var(--red-text)' : 'var(--green-text)', fontSize: 12 }}>{manualMsg}</div>
              )}
            </div>
          )}
        </div>

        {/* Footer */}
        <div style={{ padding: '14px 24px', borderTop: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', background: 'var(--bg-soft)' }}>
          <span style={{ fontSize: 11, color: 'var(--fg-3)' }}>
            {tab === 'csv' && totalParsed > 0
              ? `${totalParsed} trade${totalParsed > 1 ? 's' : ''} prêt${totalParsed > 1 ? 's' : ''} à importer`
              : 'Tes données restent privées et sont stockées de manière sécurisée.'}
          </span>
          <div style={{ display: 'flex', gap: 10 }}>
            <button onClick={() => onClose && onClose(false)} className="btn tap">Fermer</button>
            {tab === 'csv' && (
              <button
                onClick={startImport}
                className="btn btn-blue tap"
                disabled={!allReady || totalParsed === 0 || submitting}
                style={{ opacity: (!allReady || totalParsed === 0 || submitting) ? .5 : 1 }}>
                {submitting ? 'Import…' : (totalParsed === 0 ? 'Aucun trade détecté' : `Importer ${totalParsed} trade${totalParsed > 1 ? 's' : ''}`)}
              </button>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

function readFileAsText(file) {
  return new Promise((resolve, reject) => {
    const r = new FileReader();
    r.onload = () => resolve(String(r.result || ''));
    r.onerror = () => reject(r.error || new Error('Lecture du fichier échouée'));
    r.readAsText(file);
  });
}

Object.assign(window, { ImportModal, parseCSV, parseMT5Html, detectFormat, rowsToTrades });
