/* ============================================================
   Quiniela Mundial 2026 — Importador / Exportador de datos
   CSV (o JSON) → JSON normalizado → QStore.actions.importBatch
   ============================================================ */

/* ---------- CSV parser (comillas, comas internas, CRLF, "" escapado) ---------- */
function parseCSV(text) {
  text = String(text).replace(/^\uFEFF/, ""); // strip BOM
  const rows = [];
  let row = [], field = "", i = 0, inQ = false;
  const n = text.length;
  while (i < n) {
    const c = text[i];
    if (inQ) {
      if (c === '"') {
        if (text[i + 1] === '"') { field += '"'; i += 2; continue; }
        inQ = false; i++; continue;
      }
      field += c; i++; continue;
    }
    if (c === '"') { inQ = true; i++; continue; }
    if (c === ",") { row.push(field); field = ""; i++; continue; }
    if (c === "\r") { i++; continue; }
    if (c === "\n") { row.push(field); rows.push(row); row = []; field = ""; i++; continue; }
    field += c; i++;
  }
  if (field.length || row.length) { row.push(field); rows.push(row); }
  // drop fully empty trailing rows
  const clean = rows.filter((r) => r.some((v) => String(v).trim() !== ""));
  if (!clean.length) return { headers: [], rows: [] };
  const headers = clean[0].map((h) => h.trim());
  const objs = clean.slice(1).map((r) => {
    const o = {};
    headers.forEach((h, idx) => { o[h] = (r[idx] != null ? r[idx] : "").trim(); });
    return o;
  });
  return { headers, rows: objs };
}

/* ---------- header alias → canonical key ---------- */
const HEADER_ALIAS = {
  id: "id", "id partido": "id",
  local: "home", home: "home", visitante: "away", away: "away",
  grupo: "group", group: "group", fase: "phase", phase: "phase",
  inicio: "kickoff", kickoff: "kickoff", "fecha y hora": "kickoff", fecha: "kickoff",
  nombre: "name", name: "name", email: "email", correo: "email",
  area: "area", "área": "area",
  matchid: "matchId", "id partido (matchid)": "matchId",
  goleslocal: "homeGoals", "goles local": "homeGoals", homegoals: "homeGoals",
  golesvisitante: "awayGoals", "goles visitante": "awayGoals", awaygoals: "awayGoals",
  tipo: "type", type: "type", valor: "value", value: "value",
  codigo: "code", "código": "code", code: "code", bandera: "flag", flag: "flag",
  userid: "userId",
};
function canon(h) { return HEADER_ALIAS[h.trim().toLowerCase()] || h.trim().toLowerCase(); }
function mapRow(o) {
  const out = {};
  Object.keys(o).forEach((k) => { out[canon(k)] = o[k]; });
  return out;
}

/* ---------- detect which collection a CSV is ---------- */
function detectCollection(headers) {
  const set = new Set(headers.map((h) => canon(h)));
  const has = (...k) => k.every((x) => set.has(x));
  if (has("type", "value")) return "whitelist";
  if (set.has("code")) return "teams";
  if (has("matchId", "homeGoals") && (set.has("email") || set.has("userId"))) return "predictions";
  if (has("matchId", "homeGoals")) return "results";
  if (has("home", "away")) return "matches";
  if (set.has("email") && (set.has("name") || set.has("area"))) return "users";
  return null;
}

/* ---------- one CSV file → a partial payload fragment ---------- */
function csvToFragment(collection, rows) {
  const r = rows.map(mapRow);
  switch (collection) {
    case "teams":
      return { teams: r.map((x) => ({ code: x.code, name: x.name, flag: x.flag })) };
    case "matches":
      return { matches: r.map((x) => ({ id: x.id, home: x.home, away: x.away, group: x.group, phase: x.phase, kickoff: x.kickoff })) };
    case "users":
      return { users: r.map((x) => ({ name: x.name, email: x.email, area: x.area })) };
    case "results":
      return { results: r.map((x) => ({ matchId: x.matchId, homeGoals: x.homeGoals, awayGoals: x.awayGoals })) };
    case "predictions":
      return { predictions: r.map((x) => ({ email: x.email, userId: x.userId, matchId: x.matchId, homeGoals: x.homeGoals, awayGoals: x.awayGoals })) };
    case "whitelist": {
      const emails = [], domains = [];
      r.forEach((x) => {
        const t = String(x.type || "").toLowerCase();
        if (!x.value) return;
        if (t.startsWith("dom")) domains.push(x.value);
        else emails.push(x.value);
      });
      return { whitelist: { emails, domains } };
    }
    default:
      return {};
  }
}

/* ---------- normalize an uploaded JSON (accepts import-shape OR raw db) ---------- */
function normalizeJSON(p) {
  const out = {};
  if (Array.isArray(p.teams)) out.teams = p.teams;
  else if (p.teams && typeof p.teams === "object") out.teams = Object.values(p.teams);
  if (Array.isArray(p.matches)) out.matches = p.matches;
  if (Array.isArray(p.users)) out.users = p.users;
  if (p.whitelist) out.whitelist = p.whitelist;
  if (Array.isArray(p.results)) out.results = p.results;
  else if (p.results && typeof p.results === "object")
    out.results = Object.keys(p.results).map((id) => ({ matchId: id, homeGoals: p.results[id].homeGoals, awayGoals: p.results[id].awayGoals }));
  if (Array.isArray(p.predictions)) out.predictions = p.predictions;
  else if (p.predictions && typeof p.predictions === "object")
    out.predictions = Object.keys(p.predictions).map((k) => {
      const cut = k.lastIndexOf("_");
      return { userId: k.slice(0, cut), matchId: k.slice(cut + 1), homeGoals: p.predictions[k].homeGoals, awayGoals: p.predictions[k].awayGoals };
    });
  return out;
}

/* ---------- merge fragments into one payload ---------- */
function mergePayload(base, frag) {
  ["teams", "matches", "users", "results", "predictions"].forEach((k) => {
    if (frag[k]) base[k] = (base[k] || []).concat(frag[k]);
  });
  if (frag.whitelist) {
    base.whitelist = base.whitelist || { emails: [], domains: [] };
    base.whitelist.emails = (base.whitelist.emails || []).concat(frag.whitelist.emails || []);
    base.whitelist.domains = (base.whitelist.domains || []).concat(frag.whitelist.domains || []);
  }
  return base;
}

/* ---------- download helpers ---------- */
function download(filename, text, mime) {
  const blob = new Blob(["\uFEFF" + text], { type: (mime || "text/plain") + ";charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url; a.download = filename;
  document.body.appendChild(a); a.click();
  setTimeout(() => { a.remove(); URL.revokeObjectURL(url); }, 0);
}
function csvCell(v) {
  const s = v == null ? "" : String(v);
  return /[",\n\r]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s;
}
function toCSV(headers, rows) {
  return [headers.join(","), ...rows.map((r) => r.map(csvCell).join(","))].join("\r\n");
}
function isoMin(ts) { return ts == null ? "" : new Date(ts).toISOString().slice(0, 16); }

/* ---------- CSV templates (headers + ejemplos con equipos reales) ---------- */
const TEMPLATES = {
  calendario: {
    file: "calendario.csv",
    headers: ["id", "local", "visitante", "grupo", "fase", "inicio"],
    rows: [
      ["m001", "MEX", "ECU", "A", "Fase de grupos", "2026-06-11T18:00"],
      ["m002", "NED", "SEN", "A", "Fase de grupos", "2026-06-11T21:00"],
      ["m003", "ARG", "AUS", "B", "Fase de grupos", "2026-06-12T16:00"],
    ],
  },
  usuarios: {
    file: "usuarios.csv",
    headers: ["nombre", "email", "area"],
    rows: [
      ["Carla Ríos", "carla.rios@quantia.pe", "Fábrica de Software"],
      ["Diego Salas", "diego.salas@quantia.pe", "Contact Center"],
    ],
  },
  resultados: {
    file: "resultados.csv",
    headers: ["matchId", "golesLocal", "golesVisitante"],
    rows: [
      ["m001", "2", "1"],
      ["m002", "1", "1"],
    ],
  },
  lista_blanca: {
    file: "lista_blanca.csv",
    headers: ["tipo", "valor"],
    rows: [
      ["dominio", "quantia.pe"],
      ["correo", "invitado.externo@gmail.com"],
    ],
  },
  equipos: {
    file: "equipos.csv",
    headers: ["codigo", "nombre", "bandera"],
    rows: [
      ["MEX", "México", "🇲🇽"],
      ["BRA", "Brasil", "🇧🇷"],
    ],
  },
  pronosticos: {
    file: "pronosticos.csv",
    headers: ["email", "matchId", "golesLocal", "golesVisitante"],
    rows: [
      ["carla.rios@quantia.pe", "m001", "2", "1"],
      ["diego.salas@quantia.pe", "m001", "1", "0"],
    ],
  },
};
function downloadTemplate(key) {
  const t = TEMPLATES[key];
  download(t.file, toCSV(t.headers, t.rows), "text/csv");
}
function downloadJSONTemplate() {
  const obj = {
    teams: [{ code: "MEX", name: "México", flag: "🇲🇽" }, { code: "ECU", name: "Ecuador", flag: "🇪🇨" }],
    matches: [{ id: "m001", home: "MEX", away: "ECU", group: "A", phase: "Fase de grupos", kickoff: "2026-06-11T18:00" }],
    users: [{ name: "Carla Ríos", email: "carla.rios@quantia.pe", area: "Fábrica de Software" }],
    whitelist: { emails: ["invitado.externo@gmail.com"], domains: ["quantia.pe"] },
    results: [{ matchId: "m001", homeGoals: 2, awayGoals: 1 }],
    predictions: [{ email: "carla.rios@quantia.pe", matchId: "m001", homeGoals: 2, awayGoals: 1 }],
  };
  download("quiniela_plantilla.json", JSON.stringify(obj, null, 2), "application/json");
}

/* ---------- export current DB (in import shape) ---------- */
function buildExport() {
  const Q = window.QStore, d = Q.db;
  return {
    teams: Object.values(d.teams).map((t) => ({ code: t.code, name: t.name, flag: t.flag })),
    matches: d.matches.map((m) => ({ id: m.id, home: m.home, away: m.away, group: m.group, phase: m.phase, kickoff: isoMin(m.kickoff) })),
    users: d.users.map((u) => ({ name: u.name, email: u.email, area: u.area })),
    whitelist: { emails: d.whitelist.emails.slice(), domains: d.whitelist.domains.slice() },
    results: Object.keys(d.results).map((id) => ({ matchId: id, homeGoals: d.results[id].homeGoals, awayGoals: d.results[id].awayGoals })),
    predictions: Object.keys(d.predictions).map((k) => {
      const cut = k.lastIndexOf("_");
      const uid = k.slice(0, cut);
      const u = d.users.find((x) => x.userId === uid);
      return { email: u ? u.email : uid, matchId: k.slice(cut + 1), homeGoals: d.predictions[k].homeGoals, awayGoals: d.predictions[k].awayGoals };
    }),
  };
}
function exportJSON() { download("quiniela_export.json", JSON.stringify(buildExport(), null, 2), "application/json"); }
function exportCSV(key) {
  const e = buildExport();
  const t = TEMPLATES[key];
  let rows = [];
  if (key === "calendario") rows = e.matches.map((m) => [m.id, m.home, m.away, m.group, m.phase, m.kickoff]);
  else if (key === "usuarios") rows = e.users.map((u) => [u.name, u.email, u.area]);
  else if (key === "resultados") rows = e.results.map((r) => [r.matchId, r.homeGoals, r.awayGoals]);
  else if (key === "lista_blanca") rows = [...e.whitelist.domains.map((d) => ["dominio", d]), ...e.whitelist.emails.map((m) => ["correo", m])];
  else if (key === "equipos") rows = e.teams.map((t2) => [t2.code, t2.name, t2.flag]);
  else if (key === "pronosticos") rows = e.predictions.map((p) => [p.email, p.matchId, p.homeGoals, p.awayGoals]);
  download(t.file, toCSV(t.headers, rows), "text/csv");
}

/* ---------- read a File → text ---------- */
function readFileText(file) {
  return new Promise((resolve, reject) => {
    const fr = new FileReader();
    fr.onload = () => resolve(String(fr.result));
    fr.onerror = () => reject(fr.error);
    fr.readAsText(file);
  });
}

const COLL_LABEL = {
  teams: "Equipos", matches: "Calendario", users: "Participantes",
  whitelist: "Lista blanca", results: "Resultados", predictions: "Pronósticos",
};

/* ============================================================
   ImportPanel — the Admin "Importar / Exportar" tab
   ============================================================ */
function ImportPanel() {
  const Q = useStore();
  const fileRef = useRef(null);
  const [staged, setStaged] = useState([]);   // [{name, collection, count, error}]
  const [payload, setPayload] = useState(null);
  const [result, setResult] = useState(null); // {ok, errors, summary}
  const [busy, setBusy] = useState(false);

  const reset = () => { setStaged([]); setPayload(null); setResult(null); if (fileRef.current) fileRef.current.value = ""; };

  const onFiles = async (files) => {
    setBusy(true); setResult(null);
    const next = [], pay = {};
    for (const f of Array.from(files)) {
      try {
        const text = await readFileText(f);
        if (/\.json$/i.test(f.name)) {
          const frag = normalizeJSON(JSON.parse(text));
          const keys = Object.keys(frag);
          if (!keys.length) { next.push({ name: f.name, error: "JSON sin colecciones reconocidas." }); continue; }
          mergePayload(pay, frag);
          keys.forEach((k) => {
            const count = k === "whitelist" ? ((frag.whitelist.emails || []).length + (frag.whitelist.domains || []).length) : frag[k].length;
            next.push({ name: f.name, collection: k, count });
          });
        } else {
          const { headers, rows } = parseCSV(text);
          const coll = detectCollection(headers);
          if (!coll) { next.push({ name: f.name, error: "No se reconocieron las columnas. Usa una plantilla." }); continue; }
          const frag = csvToFragment(coll, rows);
          mergePayload(pay, frag);
          const count = coll === "whitelist" ? (frag.whitelist.emails.length + frag.whitelist.domains.length) : (frag[coll] ? frag[coll].length : rows.length);
          next.push({ name: f.name, collection: coll, count });
        }
      } catch (e) {
        next.push({ name: f.name, error: "No se pudo leer: " + (e.message || e) });
      }
    }
    setStaged(next);
    setPayload(Object.keys(pay).length ? pay : null);
    setBusy(false);
  };

  const doImport = () => {
    if (!payload) return;
    const res = Q.actions.importBatch(payload);
    setResult(res);
    if (res.ok) {
      const parts = Object.keys(res.summary).map((k) => `${res.summary[k]} ${COLL_LABEL[k].toLowerCase()}`);
      toast("Datos importados · " + parts.join(", "), "ok");
      setStaged([]); setPayload(null);
      if (fileRef.current) fileRef.current.value = "";
    } else {
      toast(`${res.errors.length} error(es) — revisa el detalle`, "");
    }
  };

  const hasErrors = staged.some((s) => s.error);

  return (
    <div className="qm-panel">
      <h3>Plantillas</h3>
      <p className="ph">Descarga una plantilla, llénala (en Excel / Google Sheets / Numbers) y vuelve a cargarla abajo. Las fechas van como <code style={{ background: "var(--bg-3)", padding: "1px 5px", borderRadius: 5 }}>2026-06-11T18:00</code> (hora UTC). Los equipos se referencian por <b>código</b> (MEX, BRA…).</p>
      <div className="qm-tpl-grid">
        {[["calendario", "Calendario"], ["resultados", "Resultados"], ["usuarios", "Participantes"], ["lista_blanca", "Lista blanca"], ["equipos", "Equipos"], ["pronosticos", "Pronósticos"]].map(([k, l]) => (
          <button key={k} className="qm-tpl-btn" onClick={() => downloadTemplate(k)}>
            <Icon name="calendar" size={16} /><span>{l}</span><b>.csv</b>
          </button>
        ))}
      </div>
      <button className="qm-btn qm-btn-sm qm-btn-ghost" style={{ marginTop: 10 }} onClick={downloadJSONTemplate}>
        <Icon name="bolt" size={14} />Plantilla JSON completa
      </button>

      <div className="qm-divider" />

      <h3>Cargar datos</h3>
      <p className="ph">Acepta <b>.csv</b> (uno por colección — se detecta sola) y <b>.json</b>. Puedes seleccionar varios a la vez. Cada colección presente <b>reemplaza</b> la actual; las que no incluyas se mantienen.</p>

      <input ref={fileRef} type="file" accept=".csv,.json,text/csv,application/json" multiple style={{ display: "none" }} onChange={(e) => onFiles(e.target.files)} />
      <div className="qm-drop" onClick={() => fileRef.current && fileRef.current.click()}
        onDragOver={(e) => { e.preventDefault(); }}
        onDrop={(e) => { e.preventDefault(); if (e.dataTransfer.files.length) onFiles(e.dataTransfer.files); }}>
        <Icon name="plus" size={22} />
        <b>Elegir archivos o arrastrarlos aquí</b>
        <span>CSV o JSON</span>
      </div>

      {busy && <p className="ph" style={{ marginTop: 12 }}>Leyendo archivos…</p>}

      {staged.length > 0 && (
        <div className="qm-list" style={{ marginTop: 14 }}>
          {staged.map((s, i) => (
            <div className="qm-listitem" key={i}>
              <Icon name={s.error ? "x" : "check"} size={16} />
              <div style={{ minWidth: 0 }}>
                <div style={{ fontWeight: 700 }}>{s.name}</div>
                <div style={{ fontSize: 12, color: s.error ? "var(--accent)" : "var(--fg-3)" }}>
                  {s.error ? s.error : `${COLL_LABEL[s.collection]} · ${s.count} fila(s)`}
                </div>
              </div>
            </div>
          ))}
        </div>
      )}

      {payload && !hasErrors && (
        <div style={{ display: "flex", gap: 8, marginTop: 14 }}>
          <button className="qm-btn qm-btn-sm qm-btn-primary" onClick={doImport}><Icon name="check" size={15} />Importar datos</button>
          <button className="qm-btn qm-btn-sm qm-btn-ghost" onClick={reset}>Cancelar</button>
        </div>
      )}

      {result && !result.ok && (
        <div className="qm-import-errs">
          <b>No se importó nada — corrige estos {result.errors.length} problema(s):</b>
          <ul>{result.errors.slice(0, 40).map((e, i) => <li key={i}>{e}</li>)}</ul>
          {result.errors.length > 40 && <span style={{ opacity: .7 }}>…y {result.errors.length - 40} más.</span>}
        </div>
      )}
      {result && result.ok && (
        <div className="qm-import-ok"><Icon name="check" size={16} />Importación completa · ranking recalculado.</div>
      )}

      <div className="qm-divider" />

      <h3>Exportar datos actuales</h3>
      <p className="ph">Descarga la base tal como está hoy — útil para respaldo o para editar en hoja de cálculo y re-importar.</p>
      <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
        <button className="qm-btn qm-btn-sm qm-btn-dark" onClick={exportJSON}><Icon name="copy" size={14} />JSON completo</button>
        {[["calendario", "Calendario"], ["resultados", "Resultados"], ["usuarios", "Participantes"], ["pronosticos", "Pronósticos"], ["lista_blanca", "Lista blanca"], ["equipos", "Equipos"]].map(([k, l]) => (
          <button key={k} className="qm-btn qm-btn-sm qm-btn-ghost" onClick={() => exportCSV(k)}>{l} .csv</button>
        ))}
      </div>
    </div>
  );
}

Object.assign(window, { ImportPanel });
