/**
 * src/csv-import.jsx — Importar transacciones desde CSV de bancos peruanos.
 *
 * Soporta heuristicas para BCP, BBVA, Interbank, Scotiabank.
 * El usuario arrastra el archivo CSV (descargado del banco), la app:
 * 1. Detecta el banco por columnas
 * 2. Parsea las transacciones
 * 3. Auto-categoriza con AutoCat
 * 4. Detecta duplicados (mismo monto + fecha + descripcion)
 * 5. Muestra preview, el usuario confirma/edita y se importan
 *
 * NO requiere librerias externas — parser CSV escrito a mano.
 */
(() => {
  /** Parser CSV simple. Soporta comillas dobles y comas en campos. */
  function parseCSV(text) {
    const rows = [];
    let current = [];
    let field = "";
    let inQuote = false;

    for (let i = 0; i < text.length; i++) {
      const c = text[i];
      const next = text[i + 1];
      if (inQuote) {
        if (c === '"' && next === '"') { field += '"'; i++; }
        else if (c === '"') { inQuote = false; }
        else { field += c; }
      } else {
        if (c === '"') { inQuote = true; }
        else if (c === ',') { current.push(field); field = ""; }
        else if (c === '\n') { current.push(field); rows.push(current); current = []; field = ""; }
        else if (c === '\r') { /* skip */ }
        else { field += c; }
      }
    }
    if (field.length > 0 || current.length > 0) {
      current.push(field);
      rows.push(current);
    }
    return rows.filter(r => r.length > 0 && r.some(c => c.trim().length > 0));
  }

  /** Detecta el banco según los headers. */
  function detectBank(headers) {
    const h = headers.map(x => x.toLowerCase().trim()).join("|");
    if (h.includes("fecha") && h.includes("monto") && h.includes("descripcion")) {
      if (h.includes("operacion")) return "bcp";
      if (h.includes("oficina") || h.includes("comercio")) return "bbva";
      if (h.includes("referencia")) return "interbank";
    }
    if (h.includes("date") && h.includes("amount")) return "generic-en";
    return "generic";
  }

  /** Parsea una fecha en formato peruano DD/MM/YYYY o DD-MM-YYYY o YYYY-MM-DD. */
  function parseDate(s) {
    if (!s) return null;
    s = s.trim();
    // YYYY-MM-DD
    if (/^\d{4}-\d{2}-\d{2}/.test(s)) return s.slice(0, 10);
    // DD/MM/YYYY o DD-MM-YYYY
    const m = s.match(/^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2,4})/);
    if (m) {
      let [, d, mo, y] = m;
      if (y.length === 2) y = "20" + y;
      return `${y}-${mo.padStart(2,"0")}-${d.padStart(2,"0")}`;
    }
    return null;
  }

  /** Parsea un monto peruano "1,234.56" o "-345.20". */
  function parseAmount(s) {
    if (!s) return null;
    s = String(s).replace(/[^\d.,-]/g, "").trim();
    if (!s) return null;
    // Si tiene coma y punto, asumir coma=miles, punto=decimal (formato peruano normal)
    if (s.includes(",") && s.includes(".")) {
      s = s.replace(/,/g, "");
    } else if (s.includes(",") && !s.includes(".")) {
      // Solo comas: asumir decimal
      s = s.replace(",", ".");
    }
    const n = parseFloat(s);
    return isNaN(n) ? null : n;
  }

  /** Convierte filas parseadas en objetos de transaccion candidatos. */
  function rowsToTransactions(rows, bank) {
    if (rows.length < 2) return [];
    const headers = rows[0].map(h => h.toLowerCase().trim());
    const dataRows = rows.slice(1);

    // Indices comunes
    const idx = {
      date: headers.findIndex(h => h.includes("fecha") || h.includes("date")),
      amount: headers.findIndex(h => h.includes("monto") || h.includes("importe") || h.includes("amount")),
      description: headers.findIndex(h => h.includes("descripcion") || h.includes("description") || h.includes("operacion") || h.includes("concepto")),
      type: headers.findIndex(h => h.includes("tipo") || h.includes("type")),
    };

    return dataRows.map(row => {
      const date = idx.date >= 0 ? parseDate(row[idx.date]) : null;
      const amount = idx.amount >= 0 ? parseAmount(row[idx.amount]) : null;
      const description = idx.description >= 0 ? (row[idx.description] || "").trim() : "";
      if (!date || amount === null) return null;
      return {
        date, amt: amount, merchant_es: description, merchant_en: description,
        method: "import", currency: "PEN",
        cat: window.AutoCat ? window.AutoCat.suggest(description) : "cat_other",
      };
    }).filter(Boolean);
  }

  /** Detecta duplicados contra Storage existente. */
  function isDuplicate(tx, existing) {
    return existing.some(e =>
      e.date === tx.date &&
      Math.abs(e.amt - tx.amt) < 0.01 &&
      (e.merchant_es || "").trim().toLowerCase() === (tx.merchant_es || "").trim().toLowerCase()
    );
  }

  function CsvImportModal({ onClose }) {
    const { lang } = window.useApp();
    const [step, setStep] = React.useState("upload"); // upload | preview | done
    const [parsed, setParsed] = React.useState([]);
    const [dupCount, setDupCount] = React.useState(0);
    const [bankDetected, setBankDetected] = React.useState(null);
    const [error, setError] = React.useState(null);
    const [selected, setSelected] = React.useState(new Set());
    const [importedCount, setImportedCount] = React.useState(0);

    function handleFile(file) {
      setError(null);
      if (!file) return;
      if (!/\.csv$/i.test(file.name)) {
        setError(lang === "es" ? "Solo archivos CSV" : "Only CSV files");
        return;
      }
      const reader = new FileReader();
      reader.onload = (e) => {
        try {
          const text = e.target.result;
          const rows = parseCSV(text);
          if (rows.length < 2) {
            setError(lang === "es" ? "CSV vacio o sin datos" : "Empty CSV");
            return;
          }
          const bank = detectBank(rows[0]);
          setBankDetected(bank);
          const txs = rowsToTransactions(rows, bank);
          const existing = window.Storage.get("transactions") || [];
          let dups = 0;
          const flagged = txs.map(t => {
            const dup = isDuplicate(t, existing);
            if (dup) dups++;
            return Object.assign({}, t, { _dup: dup });
          });
          setParsed(flagged);
          setDupCount(dups);
          // Pre-seleccionar todos los NO duplicados
          setSelected(new Set(flagged.map((t, i) => i).filter(i => !flagged[i]._dup)));
          setStep("preview");
        } catch (err) {
          setError(`Error parseando CSV: ${err.message}`);
        }
      };
      reader.readAsText(file, "utf-8");
    }

    function handleImport() {
      let count = 0;
      parsed.forEach((tx, i) => {
        if (!selected.has(i)) return;
        const { _dup, ...clean } = tx;
        window.Storage.add("transactions", clean);
        count++;
      });
      setImportedCount(count);
      setStep("done");
    }

    function toggleRow(i) {
      const s = new Set(selected);
      if (s.has(i)) s.delete(i); else s.add(i);
      setSelected(s);
    }

    return (
      <div className="modal-scrim" onClick={onClose}>
        <div className="modal-card" style={{ maxWidth: 720, padding: 24 }} onClick={(e) => e.stopPropagation()}>
          <button className="ob-close" onClick={onClose}>
            <window.Icon name="x" size={14} />
          </button>
          <div className="kicker">{lang === "es" ? "IMPORTAR CSV" : "IMPORT CSV"}</div>
          <div className="h2" style={{ marginBottom: 18 }}>
            {lang === "es" ? "Trae tus transacciones del banco" : "Bring your bank transactions"}
          </div>

          {step === "upload" && (
            <div>
              <div className="csv-drop" onDragOver={(e) => e.preventDefault()} onDrop={(e) => { e.preventDefault(); handleFile(e.dataTransfer.files[0]); }}>
                <div style={{ fontSize: 36 }}>📁</div>
                <div className="serif" style={{ fontSize: 18, marginTop: 8 }}>
                  {lang === "es" ? "Arrastra tu CSV aqui" : "Drag your CSV here"}
                </div>
                <div className="caption" style={{ marginTop: 6 }}>
                  {lang === "es" ? "o" : "or"}
                </div>
                <label className="btn warm" style={{ marginTop: 10, display: "inline-block", cursor: "pointer" }}>
                  {lang === "es" ? "Selecciona archivo" : "Pick file"}
                  <input type="file" accept=".csv" onChange={(e) => handleFile(e.target.files[0])} style={{ display: "none" }} />
                </label>
              </div>
              {error && <div className="form-error" style={{ marginTop: 14 }}>{error}</div>}
              <div className="caption" style={{ marginTop: 20, lineHeight: 1.5 }}>
                {lang === "es"
                  ? "Compatible con CSVs de BCP, BBVA, Interbank, Scotiabank. La app detecta el formato automaticamente."
                  : "Compatible with BCP, BBVA, Interbank, Scotiabank CSVs."}
              </div>
            </div>
          )}

          {step === "preview" && (
            <div>
              <div className="caption" style={{ marginBottom: 14 }}>
                {lang === "es"
                  ? `Detectado: ${bankDetected} · ${parsed.length} transacciones (${dupCount} duplicados omitidos)`
                  : `Detected: ${bankDetected} · ${parsed.length} transactions (${dupCount} duplicates skipped)`}
              </div>
              <div style={{ maxHeight: 380, overflowY: "auto", border: "1px solid var(--line)", borderRadius: "var(--radius-sm)" }}>
                {parsed.map((tx, i) => (
                  <label key={i} style={{ display: "flex", alignItems: "center", gap: 10, padding: "8px 12px", borderBottom: "1px solid var(--line-soft)", cursor: "pointer", opacity: tx._dup ? 0.4 : 1, background: selected.has(i) ? "var(--paper-2)" : "transparent" }}>
                    <input type="checkbox" checked={selected.has(i)} onChange={() => toggleRow(i)} />
                    <span className="meta" style={{ width: 80 }}>{window.fmtDateShort(tx.date, lang)}</span>
                    <span style={{ flex: 1, fontSize: 13, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{tx.merchant_es}</span>
                    <span className="caption" style={{ width: 100 }}>{(window.I18N[lang] || {})[tx.cat] || tx.cat}</span>
                    <span className="num" style={{ width: 90, textAlign: "right", color: tx.amt > 0 ? "var(--sage)" : "var(--ink)" }}>{window.fmtMoney(tx.amt)}</span>
                    {tx._dup && <span className="badge-auto" style={{ background: "var(--terracotta-soft)", color: "var(--rust)" }}>DUP</span>}
                  </label>
                ))}
              </div>
              <div className="form-actions">
                <button className="btn" onClick={() => setStep("upload")}>{lang === "es" ? "Atras" : "Back"}</button>
                <div style={{ marginLeft: "auto", display: "flex", gap: 8 }}>
                  <button className="btn" onClick={onClose}>{lang === "es" ? "Cancelar" : "Cancel"}</button>
                  <button className="btn warm" onClick={handleImport}>
                    {lang === "es" ? `Importar ${selected.size}` : `Import ${selected.size}`}
                  </button>
                </div>
              </div>
            </div>
          )}

          {step === "done" && (
            <div style={{ textAlign: "center", padding: 24 }}>
              <div style={{ fontSize: 48 }}>✓</div>
              <div className="serif" style={{ fontSize: 24, marginTop: 12 }}>
                {lang === "es" ? `${importedCount} transacciones importadas` : `${importedCount} transactions imported`}
              </div>
              <button className="btn warm" style={{ marginTop: 20 }} onClick={onClose}>
                {lang === "es" ? "Listo" : "Done"}
              </button>
            </div>
          )}
        </div>
      </div>
    );
  }

  window.CsvImportModal = CsvImportModal;
})();
