/* ======================================================
   Import Center — bulk data import via CSV
   Works in Local mode (populates the shared store that every
   role reads) and posts to /api/import when D1 is connected.
====================================================== */

/* ---------- CSV parser (handles quotes, commas, Thai, CRLF) ---------- */
function parseCSV(text) {
  const rows = [];
  let row = [], cur = "", q = false;
  for (let i = 0; i < text.length; i++) {
    const c = text[i];
    if (q) {
      if (c === '"') { if (text[i + 1] === '"') { cur += '"'; i++; } else q = false; }
      else cur += c;
    } else {
      if (c === '"') q = true;
      else if (c === ",") { row.push(cur); cur = ""; }
      else if (c === "\n") { row.push(cur); cur = ""; rows.push(row); row = []; }
      else if (c === "\r") { /* skip */ }
      else cur += c;
    }
  }
  if (cur !== "" || row.length) { row.push(cur); rows.push(row); }
  return rows.filter(r => r.some(x => String(x).trim() !== ""));
}

function rowsToObjects(parsed) {
  if (!parsed.length) return { headers: [], objects: [] };
  const headers = parsed[0].map(h => h.trim());
  const objects = parsed.slice(1).map(r => {
    const o = {};
    headers.forEach((h, i) => { o[h] = (r[i] !== undefined ? String(r[i]).trim() : ""); });
    return o;
  });
  return { headers, objects };
}

/* ---------- Entity definitions ---------- */
const IMPORT_ENTITIES = {
  students: {
    label: "นักศึกษา", icon: "users", accent: "oklch(0.72 0.20 270)",
    columns: ["code", "fullName", "nickname", "classroom", "year"],
    required: ["code", "fullName"],
    sample: [
      ["code", "fullName", "nickname", "classroom", "year"],
      ["67-1050", "ธนกร ใจดี", "กร", "ปวส.2/1", "2"],
      ["67-1051", "พิมพ์มาดา ศรีสุข", "พิมพ์", "ปวส.2/1", "2"],
    ],
    hint: "code = รหัสนักศึกษา (ใช้เป็นตัวระบุตัวตน) · year = ชั้นปี",
  },
  teachers: {
    label: "อาจารย์", icon: "edit", accent: "oklch(0.72 0.22 340)",
    columns: ["id", "name", "spec", "email"],
    required: ["name"],
    sample: [
      ["id", "name", "spec", "email"],
      ["T20", "อ. สมชาย พัฒนกิจ", "DBT", "somchai@vrp.ac.th"],
      ["T21", "อ. มาลี ทองคำ", "ACC", "malee@vrp.ac.th"],
    ],
    hint: "id เว้นว่างได้ (ระบบสร้างให้) · spec = ความเชี่ยวชาญ เช่น DBT, ACC",
  },
  offerings: {
    label: "รายวิชาที่เปิดสอน", icon: "book", accent: "oklch(0.82 0.17 75)",
    columns: ["majorId", "code", "name", "credits", "teacherId", "year", "group", "schedule", "room", "students", "semester"],
    required: ["majorId", "code", "name", "teacherId"],
    sample: [
      ["majorId", "code", "name", "credits", "teacherId", "year", "group", "schedule", "room", "students", "semester"],
      ["hvd-dbt", "30204-2010", "การพัฒนาแอปพลิเคชันมือถือ", "3", "T01", "2", "1", "จ. 08:30-11:30", "IT-302", "28", "1/2569"],
    ],
    hint: "majorId เช่น hvd-dbt, voc-acc · teacherId เช่น T01 · ดูรหัสสาขาได้จากตารางด้านล่าง",
  },
  grades: {
    label: "คะแนน", icon: "chart", accent: "oklch(0.80 0.18 130)",
    columns: ["studentCode", "subjectId", "collected", "midterm", "final", "remark"],
    required: ["studentCode", "subjectId"],
    sample: [
      ["studentCode", "subjectId", "collected", "midterm", "final", "remark"],
      ["67-1004", "CN101", "25", "26", "34", "ตั้งใจเรียนดีมาก"],
    ],
    hint: "studentCode = รหัสนักศึกษา · subjectId = รหัสวิชา (ดูรายการด้านล่าง) · เก็บ/30 กลาง/30 ปลาย/40",
  },
  users: {
    label: "ผู้ใช้ระบบ", icon: "users", accent: "oklch(0.70 0.22 25)",
    columns: ["username", "name", "role", "email", "password", "linkLabel", "status"],
    required: ["username", "name", "role"],
    sample: [
      ["username", "name", "role", "email", "password", "linkLabel", "status"],
      ["somchai", "อ. สมชาย พัฒนกิจ", "teacher", "somchai@vrp.ac.th", "vrp12345", "T20 · DBT", "active"],
      ["parent_kan", "ผู้ปกครอง น.ส.กานต์", "parent", "kan@gmail.com", "vrp12345", "บุตร: 67-1050", "active"],
    ],
    hint: "role = teacher | parent | executive | academic | admin · password = รหัสผ่านเริ่มต้น",
  },
};

function ImportCenter({ store, toast, apiMode }) {
  const { SUBJECTS, PROGRAMS } = window.VRP_DATA;
  const [entity, setEntity] = useState("students");
  const [raw, setRaw] = useState("");
  const [parsed, setParsed] = useState(null); // { headers, objects }
  const [applied, setApplied] = useState(null);
  const [liveMode, setLiveMode] = useState(apiMode);
  const fileRef = useRef(null);

  // Re-check DB readiness when the Import Center opens (the page may have
  // loaded before the database was migrated, leaving a stale "local" mode).
  useEffect(() => {
    if (window.VRPApi && window.VRPApi.probe) {
      window.VRPApi.probe().then(m => setLiveMode(m)).catch(() => {});
    }
  }, []);

  const def = IMPORT_ENTITIES[entity];

  const allMajors = useMemo(() => {
    const list = [];
    Object.values(PROGRAMS).forEach(p => p.categories.forEach(c => c.majors.forEach(m =>
      list.push({ id: m.id, name: m.name, levelCode: p.code, color: c.color }))));
    return list;
  }, []);

  const reset = () => { setRaw(""); setParsed(null); setApplied(null); };
  const switchEntity = (e) => { setEntity(e); reset(); };

  const doParse = (text) => {
    const obj = rowsToObjects(parseCSV(text));
    setParsed(obj);
    setApplied(null);
  };

  const onFile = (e) => {
    const f = e.target.files[0];
    if (!f) return;
    const reader = new FileReader();
    reader.onload = () => { setRaw(reader.result); doParse(reader.result); };
    reader.readAsText(f, "utf-8");
  };

  const downloadTemplate = () => {
    const csv = def.sample.map(r => r.map(c => /[",\n]/.test(c) ? '"' + c.replace(/"/g, '""') + '"' : c).join(",")).join("\n");
    const blob = new Blob(["\uFEFF" + csv], { type: "text/csv;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url; a.download = "vrp-import-" + entity + ".csv"; a.click();
    URL.revokeObjectURL(url);
  };

  // ---- validation ----
  const validation = useMemo(() => {
    if (!parsed) return null;
    const missing = def.required.filter(c => !parsed.headers.includes(c));
    const rowIssues = parsed.objects.map((o, i) => {
      const errs = [];
      def.required.forEach(c => { if (!o[c]) errs.push(c); });
      if (entity === "grades") {
        if (o.subjectId && !SUBJECTS.find(s => s.id === o.subjectId)) errs.push("subjectId ไม่ถูกต้อง");
        if (o.studentCode && !store.students.find(s => s.code === o.studentCode)) errs.push("ไม่พบนักศึกษา");
      }
      if (entity === "offerings" && o.majorId && !allMajors.find(m => m.id === o.majorId)) errs.push("majorId ไม่ถูกต้อง");
      if (entity === "users" && o.role && !["teacher","parent","executive","academic","admin"].includes(o.role)) errs.push("role ไม่ถูกต้อง");
      return errs;
    });
    const validCount = rowIssues.filter(e => e.length === 0).length;
    return { missing, rowIssues, validCount, total: parsed.objects.length };
  }, [parsed, entity]);

  // ---- apply (local) ----
  function applyLocal(objects) {
    const okRows = objects.filter((o, i) => validation.rowIssues[i].length === 0);
    if (entity === "students") {
      const next = [...store.students];
      const nd = { ...store.data };
      okRows.forEach(o => {
        const id = o.code;
        const parts = (o.fullName || "").trim().split(/\s+/);
        const stu = { id, code: o.code, fullName: o.fullName, firstName: parts[0] || "", lastName: parts.slice(1).join(" "),
          nickname: o.nickname || "", avatarSeed: (next.length % 6) + 1, classroom: o.classroom || "", year: Number(o.year) || 1, program: "เทคโนโลยีธุรกิจดิจิทัล" };
        const idx = next.findIndex(s => s.id === id);
        if (idx >= 0) next[idx] = { ...next[idx], ...stu }; else next.push(stu);
        if (!nd[id]) {
          nd[id] = {};
          SUBJECTS.forEach(sub => { nd[id][sub.id] = { scores: { collected: 0, midterm: 0, final: 0 },
            attendance: Array.from({ length: 16 }, (_, w) => w === 7 ? "H" : "P"), remark: "" }; });
        }
      });
      store.setStudents(next); store.setData(nd);
    } else if (entity === "teachers") {
      const next = [...store.teachers];
      okRows.forEach(o => {
        const id = o.id || ("T" + Math.random().toString(36).slice(2, 6));
        const t = { id, name: o.name, spec: o.spec || "", email: o.email || "", avatar: (next.length % 6) + 1 };
        const idx = next.findIndex(x => x.id === id);
        if (idx >= 0) next[idx] = { ...next[idx], ...t }; else next.push(t);
      });
      store.setTeachers(next);
    } else if (entity === "offerings") {
      const next = [...store.offerings];
      okRows.forEach(o => {
        const mj = allMajors.find(m => m.id === o.majorId);
        next.push({
          id: "OF" + Date.now().toString(36) + Math.random().toString(36).slice(2, 5),
          semester: o.semester || window.VRP_DATA.CURRENT_SEMESTER,
          level: o.majorId.startsWith("voc-") ? "voc" : "hvd",
          majorId: o.majorId, majorName: mj.name, levelCode: mj.levelCode, catName: "", majorColor: mj.color,
          code: o.code, name: o.name, credits: Number(o.credits) || 3,
          teacherId: o.teacherId, year: Number(o.year) || 1, group: o.group || "1",
          schedule: o.schedule || "", room: o.room || "", students: Number(o.students) || 30,
        });
      });
      store.setOfferings(next);
    } else if (entity === "grades") {
      const nd = { ...store.data };
      okRows.forEach(o => {
        const stu = store.students.find(s => s.code === o.studentCode);
        if (!stu || !nd[stu.id] || !nd[stu.id][o.subjectId]) return;
        nd[stu.id] = { ...nd[stu.id], [o.subjectId]: { ...nd[stu.id][o.subjectId],
          scores: { collected: Number(o.collected) || 0, midterm: Number(o.midterm) || 0, final: Number(o.final) || 0 },
          remark: o.remark || nd[stu.id][o.subjectId].remark } };
      });
      store.setData(nd);
    } else if (entity === "users") {
      const next = [...store.users];
      okRows.forEach(o => {
        if (next.find(u => u.username === o.username)) return;
        next.push({ id: "U-" + Math.random().toString(36).slice(2, 8), username: o.username, name: o.name,
          role: o.role, email: o.email || "", linkLabel: o.linkLabel || "", status: o.status || "active", lastLogin: "—" });
      });
      store.setUsers(next);
    }
    store.bump();
    return okRows.length;
  }

  const apply = async () => {
    if (!validation || validation.missing.length) { toast && toast("คอลัมน์ที่จำเป็นไม่ครบ"); return; }
    const okRows = parsed.objects.filter((o, i) => validation.rowIssues[i].length === 0);
    if (!okRows.length) { toast && toast("ไม่มีแถวที่ผ่านการตรวจสอบ"); return; }

    if (liveMode === "api" && ["students", "teachers", "offerings", "users"].includes(entity)) {
      try {
        const res = await window.VRPApi.post("/import", { entity, rows: okRows });
        if (res && res.error) { toast && toast("ฐานข้อมูล: " + res.error); return; }
        const n = applyLocal(parsed.objects);
        setApplied({ count: res && res.inserted != null ? res.inserted : n, db: true });
        toast && toast("นำเข้า " + (res && res.inserted != null ? res.inserted : n) + " รายการลงฐานข้อมูลแล้ว ✓");
      } catch (e) {
        toast && toast("เชื่อมต่อฐานข้อมูลไม่ได้: " + (e && e.message ? e.message : "error"));
      }
      return;
    }
    const n = applyLocal(parsed.objects);
    setApplied({ count: n, db: false });
    toast && toast("นำเข้า " + n + " รายการเรียบร้อย");
  };

  return (
    <div className="fade-in">
      {/* Hero */}
      <div className="hero-card" style={{ marginBottom: 18 }}>
        <div>
          <div className="eyebrow">ศูนย์นำเข้าข้อมูล · Bulk Import</div>
          <h2>นำเข้าข้อมูลเข้าสู่ระบบ</h2>
          <p>นำเข้านักศึกษา อาจารย์ รายวิชา คะแนน และผู้ใช้งาน ครั้งละจำนวนมากผ่านไฟล์ CSV · ข้อมูลจะเชื่อมโยงไปยังทุกบทบาทในระบบทันที</p>
          <div style={{ marginTop: 14 }}>
            {liveMode === "api" ? (
              <span className="pill good" style={{ fontSize: 12, padding: '6px 12px' }}>
                <span style={{ width: 7, height: 7, borderRadius: 50, background: 'var(--good)', boxShadow: '0 0 8px var(--good)' }}/>
                เชื่อมฐานข้อมูล D1 — การนำเข้าจะบันทึกลงฐานข้อมูลจริง
              </span>
            ) : (
              <span className="pill warn" style={{ fontSize: 12, padding: '6px 12px' }}>
                <Icon.alert width={12} height={12}/>
                โหมด Local — บันทึกในเครื่องเท่านั้น (ยังไม่เชื่อมฐานข้อมูล)
              </span>
            )}
          </div>
        </div>
        <div style={{ display: 'grid', placeItems: 'center' }}>
          <div style={{ width: 120, height: 120, borderRadius: 24, display: 'grid', placeItems: 'center',
                        background: 'linear-gradient(135deg, oklch(0.72 0.25 340), oklch(0.70 0.18 220))', color: 'white' }}>
            <svg width="52" height="52" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"><path d="M12 16V4"/><path d="m7 9 5-5 5 5"/><path d="M5 20h14"/></svg>
          </div>
        </div>
      </div>

      {/* Entity tabs */}
      <div className="row" style={{ marginBottom: 14 }}>
        {Object.entries(IMPORT_ENTITIES).map(([k, e]) => {
          const IconC = Icon[e.icon];
          const active = entity === k;
          return (
            <button key={k} className="card" style={{ padding: '14px 16px', flex: 1, cursor: 'pointer', textAlign: 'left',
                         borderColor: active ? e.accent : undefined, boxShadow: active ? `0 0 0 1px ${e.accent}` : undefined }}
                    onClick={() => switchEntity(k)}>
              <div style={{ width: 34, height: 34, borderRadius: 9, display: 'grid', placeItems: 'center', marginBottom: 8,
                            background: `color-mix(in oklab, ${e.accent} 22%, transparent)`, color: e.accent }}>
                <IconC width={18} height={18}/>
              </div>
              <div style={{ fontSize: 13, fontWeight: 600 }}>{e.label}</div>
              <div className="dim" style={{ fontSize: 10.5 }}>{e.columns.length} คอลัมน์</div>
            </button>
          );
        })}
      </div>

      <div className="grid-2" style={{ alignItems: 'start' }}>
        {/* Left: input */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div className="card">
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
              <h3>1 · วางข้อมูล CSV · {def.label}</h3>
              <div style={{ display: 'flex', gap: 6 }}>
                <button className="btn small" onClick={downloadTemplate}>
                  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8"><path d="M12 4v12"/><path d="m7 11 5 5 5-5"/><path d="M5 20h14"/></svg>
                  เทมเพลต
                </button>
                <button className="btn small" onClick={() => fileRef.current && fileRef.current.click()}>
                  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8"><path d="M12 16V4"/><path d="m7 9 5-5 5 5"/><path d="M5 20h14"/></svg>
                  อัปโหลดไฟล์
                </button>
                <input ref={fileRef} type="file" accept=".csv,text/csv" style={{ display: 'none' }} onChange={onFile}/>
              </div>
            </div>
            <div style={{ fontSize: 11.5, color: 'var(--fg-2)', marginBottom: 8, lineHeight: 1.5 }}>
              คอลัมน์: <span className="eng mono" style={{ color: 'var(--fg-1)' }}>{def.columns.join(", ")}</span><br/>
              <span className="dim">{def.hint}</span>
            </div>
            <textarea value={raw} onChange={e => { setRaw(e.target.value); }} onBlur={() => raw && doParse(raw)}
              placeholder={def.sample.map(r => r.join(",")).join("\n")}
              style={{ minHeight: 180, fontFamily: 'var(--font-mono)', fontSize: 12, width: '100%' }}/>
            <div style={{ display: 'flex', gap: 8, marginTop: 10 }}>
              <button className="btn primary" onClick={() => doParse(raw)} disabled={!raw.trim()}>
                <Icon.search width={14} height={14}/> ตรวจสอบข้อมูล
              </button>
              {parsed && <button className="btn ghost" onClick={reset}>ล้าง</button>}
            </div>
          </div>

          {/* Reference tables */}
          {(entity === "offerings") && (
            <div className="card">
              <h3 style={{ marginBottom: 10 }}>รหัสสาขาวิชา (majorId)</h3>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6 }}>
                {allMajors.map(m => (
                  <div key={m.id} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12 }}>
                    <span className="eng mono" style={{ color: m.color, minWidth: 64 }}>{m.id}</span>
                    <span className="dim">{m.levelCode} {m.name}</span>
                  </div>
                ))}
              </div>
            </div>
          )}
          {(entity === "grades") && (
            <div className="card">
              <h3 style={{ marginBottom: 10 }}>รหัสวิชา (subjectId)</h3>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 5 }}>
                {SUBJECTS.map(s => (
                  <div key={s.id} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12 }}>
                    <span className="eng mono" style={{ color: s.color, minWidth: 54 }}>{s.id}</span>
                    <span className="dim">{s.th}</span>
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>

        {/* Right: preview + apply */}
        <div className="card" style={{ minHeight: 300 }}>
          <h3 style={{ marginBottom: 12 }}>2 · ตรวจสอบและยืนยัน</h3>
          {!parsed ? (
            <div style={{ display: 'grid', placeItems: 'center', height: 220, color: 'var(--fg-3)', textAlign: 'center' }}>
              <div>
                <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4" style={{ opacity: .4, marginBottom: 10 }}><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/></svg>
                <div style={{ fontSize: 13 }}>วางข้อมูล CSV แล้วกด "ตรวจสอบข้อมูล"</div>
              </div>
            </div>
          ) : validation.missing.length ? (
            <div style={{ padding: 14, borderRadius: 12, background: 'color-mix(in oklab, var(--bad) 14%, transparent)', color: 'oklch(0.85 0.12 25)', fontSize: 13 }}>
              <Icon.alert width={16} height={16} style={{ verticalAlign: '-3px', marginRight: 6 }}/>
              ขาดคอลัมน์ที่จำเป็น: <span className="eng mono">{validation.missing.join(", ")}</span>
            </div>
          ) : (
            <>
              <div className="row" style={{ marginBottom: 12 }}>
                <div className="stat" style={{ flex: 1, padding: '12px 14px' }}>
                  <div className="label">พบทั้งหมด</div>
                  <div className="value"><b style={{ fontSize: 24 }}>{validation.total}</b><span>แถว</span></div>
                </div>
                <div className="stat" style={{ flex: 1, padding: '12px 14px' }}>
                  <div className="label">ผ่านตรวจสอบ</div>
                  <div className="value"><b style={{ fontSize: 24, color: 'var(--good)' }}>{validation.validCount}</b></div>
                </div>
                <div className="stat" style={{ flex: 1, padding: '12px 14px' }}>
                  <div className="label">มีปัญหา</div>
                  <div className="value"><b style={{ fontSize: 24, color: validation.total - validation.validCount ? 'var(--bad)' : 'var(--fg-2)' }}>{validation.total - validation.validCount}</b></div>
                </div>
              </div>

              <div style={{ maxHeight: 280, overflowY: 'auto', border: '1px solid var(--line)', borderRadius: 10 }}>
                <table className="tbl" style={{ fontSize: 12 }}>
                  <thead><tr>
                    <th style={{ width: 28 }}></th>
                    {def.columns.filter(c => parsed.headers.includes(c)).map(c => <th key={c} className="eng">{c}</th>)}
                  </tr></thead>
                  <tbody>
                    {parsed.objects.slice(0, 50).map((o, i) => {
                      const errs = validation.rowIssues[i];
                      return (
                        <tr key={i} style={{ background: errs.length ? 'color-mix(in oklab, var(--bad) 8%, transparent)' : undefined }}>
                          <td>{errs.length
                            ? <span title={errs.join(", ")}><Icon.alert width={13} height={13} style={{ color: 'var(--bad)' }}/></span>
                            : <Icon.check width={13} height={13} style={{ color: 'var(--good)' }}/>}</td>
                          {def.columns.filter(c => parsed.headers.includes(c)).map(c => (
                            <td key={c} style={{ whiteSpace: 'nowrap', maxWidth: 160, overflow: 'hidden', textOverflow: 'ellipsis' }}>{o[c]}</td>
                          ))}
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
              {parsed.objects.length > 50 && <div className="dim" style={{ fontSize: 11, marginTop: 6 }}>แสดง 50 จาก {parsed.objects.length} แถว</div>}

              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 14, borderTop: '1px solid var(--line)', paddingTop: 14 }}>
                {applied ? (
                  <span className="pill good"><Icon.check width={12} height={12}/> นำเข้าแล้ว {applied.count} รายการ {applied.db ? "(ฐานข้อมูล)" : "(Local)"}</span>
                ) : <span className="dim" style={{ fontSize: 12 }}>จะนำเข้าเฉพาะแถวที่ผ่านการตรวจสอบ ({validation.validCount} แถว)</span>}
                <button className="btn primary" onClick={apply} disabled={!validation.validCount || !!applied}>
                  <Icon.save width={14} height={14}/> นำเข้า {validation.validCount} รายการ
                </button>
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

window.ImportCenter = ImportCenter;
window.IMPORT_ENTITIES = IMPORT_ENTITIES;
