/* global React, Icon, useToast, Modal */
// ============================================================
// scanner.jsx — ระบบสแกนเอกสาร (ทำงานเฉพาะในแอป Desktop)
// window.Desktop ถูกฉีดโดย Electron preload — ถ้าเปิดผ่าน
// browser ธรรมดา ปุ่ม/ฟีเจอร์สแกนจะไม่แสดง เว็บทำงานเหมือนเดิม
// ============================================================
const { useState: useStateS, useEffect: useEffectS } = React;

const SCANNER_SETTINGS_KEY = "jscontract_scanner_settings";

function getScannerSettings() {
  try {
    return { deviceId: "", dpi: 300, color: true, source: "auto", quality: 80,
      ...(JSON.parse(localStorage.getItem(SCANNER_SETTINGS_KEY)) || {}) };
  } catch (e) {
    return { deviceId: "", dpi: 300, color: true, source: "auto", quality: 80 };
  }
}
function saveScannerSettings(s) {
  localStorage.setItem(SCANNER_SETTINGS_KEY, JSON.stringify(s));
}

// ---------- ล้างอักขระที่ใช้ตั้งชื่อไฟล์ไม่ได้ ----------
// / \\ : * ? " < > | ฯลฯ → เปลี่ยนเป็น - (ภาษาไทยใช้ได้ปกติ เก็บไว้)
function sanitizeFilename(s) {
  const cleaned = String(s || "")
    .replace(/[\\/:*?"<>|#\[\]%&{}$!'@+=,;^~`\s-]+/g, "-")
    .replace(/-+/g, "-")
    .replace(/^-+|-+$/g, "")
    .slice(0, 40);
  return cleaned || "สแกน";
}

// ---------- หมุนภาพ JPEG (base64) ด้วย canvas — ใช้ตอนรวม PDF ----------
async function rotateB64(b64, deg) {
  if (!deg) return b64;
  const img = new Image();
  await new Promise((res, rej) => { img.onload = res; img.onerror = rej; img.src = "data:image/jpeg;base64," + b64; });
  const swap = deg % 180 !== 0;
  const canvas = document.createElement("canvas");
  canvas.width = swap ? img.height : img.width;
  canvas.height = swap ? img.width : img.height;
  const ctx = canvas.getContext("2d");
  ctx.translate(canvas.width / 2, canvas.height / 2);
  ctx.rotate(deg * Math.PI / 180);
  ctx.drawImage(img, -img.width / 2, -img.height / 2);
  return canvas.toDataURL("image/jpeg", 0.92).split(",")[1];
}

// ---------- รวมภาพ JPEG (base64) เป็น PDF ไฟล์เดียว ----------
async function pagesToPdfFile(pagesB64, filename) {
  const { PDFDocument } = window.PDFLib;
  const doc = await PDFDocument.create();
  for (const b64 of pagesB64) {
    const bytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
    const img = await doc.embedJpg(bytes);
    const page = doc.addPage([img.width, img.height]);
    page.drawImage(img, { x: 0, y: 0, width: img.width, height: img.height });
  }
  const pdfBytes = await doc.save();
  return new File([pdfBytes], filename, { type: "application/pdf" });
}

// ============================================================
// Modal ตั้งค่าเครื่องสแกน
// ============================================================
function ScannerSettingsModal({ onClose }) {
  const [settings, setSettings] = useStateS(getScannerSettings());
  const [devices, setDevices] = useStateS(null); // null = กำลังโหลด
  const [version, setVersion] = useStateS("");
  const toast = useToast();

  useEffectS(() => {
    window.Desktop.listScanners().then((r) => setDevices(r.ok ? r.devices : []));
    window.Desktop.appVersion().then(setVersion).catch(() => {});
  }, []);

  const save = () => {
    saveScannerSettings(settings);
    toast({ t: "บันทึกตั้งค่าเครื่องสแกนแล้ว" });
    onClose();
  };

  return (
    <Modal title="ตั้งค่าเครื่องสแกน" icon="settings" onClose={onClose} foot={
      <>
        <button className="btn" onClick={onClose}>ยกเลิก</button>
        <button className="btn primary" onClick={save}><Icon name="check" size={13} /> บันทึก</button>
      </>
    }>
      <div className="vstack" style={{ gap: 12 }}>
        <div className="field">
          <label>เครื่องสแกน</label>
          {devices === null ? (
            <div className="dim" style={{ fontSize: 13, padding: "8px 0" }}><span className="spinner" style={{ width: 12, height: 12 }}></span> กำลังค้นหาเครื่องสแกน...</div>
          ) : (
            <select className="select" value={settings.deviceId} onChange={(e) => setSettings({ ...settings, deviceId: e.target.value })}>
              <option value="">— อัตโนมัติ (เครื่องแรกที่พบ) —</option>
              {devices.map((d) => <option key={d.id} value={d.id}>{d.name}</option>)}
            </select>
          )}
          {devices !== null && devices.length === 0 && (
            <div style={{ fontSize: 12.5, color: "var(--warn)", marginTop: 4 }}>
              ⚠ ไม่พบเครื่องสแกน — ตรวจสอบว่าเชื่อมต่อและเปิดเครื่องแล้ว
            </div>
          )}
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <div className="field">
            <label>ความละเอียด (DPI)</label>
            <select className="select" value={settings.dpi} onChange={(e) => setSettings({ ...settings, dpi: Number(e.target.value) })}>
              <option value={150}>150 — เร็ว ไฟล์เล็ก</option>
              <option value={200}>200</option>
              <option value={300}>300 — แนะนำ</option>
              <option value={400}>400</option>
              <option value={600}>600 — ละเอียดสูง ช้า</option>
            </select>
          </div>
          <div className="field">
            <label>โหมดสี</label>
            <select className="select" value={settings.color ? "1" : "0"} onChange={(e) => setSettings({ ...settings, color: e.target.value === "1" })}>
              <option value="1">สี</option>
              <option value="0">ขาวดำ (Grayscale)</option>
            </select>
          </div>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <div className="field">
            <label>แหล่งกระดาษ</label>
            <select className="select" value={settings.source} onChange={(e) => setSettings({ ...settings, source: e.target.value })}>
              <option value="auto">อัตโนมัติ (มีกระดาษในถาด → ใช้ถาดป้อน)</option>
              <option value="feeder">ถาดป้อนเอกสาร (ADF)</option>
              <option value="flatbed">ถาดแก้ว (Flatbed)</option>
            </select>
          </div>
          <div className="field">
            <label>ความคมชัดของภาพใน PDF</label>
            <select className="select" value={settings.quality} onChange={(e) => setSettings({ ...settings, quality: Number(e.target.value) })}>
              <option value={70}>ประหยัดพื้นที่ — ไฟล์เล็กสุด</option>
              <option value={80}>มาตรฐาน — แนะนำ</option>
              <option value={90}>คมชัดสูง — ไฟล์ใหญ่ขึ้น</option>
            </select>
          </div>
        </div>
        <div className="dim" style={{ fontSize: 12, background: "var(--surface-2)", borderRadius: 6, padding: "7px 10px" }}>
          <Icon name="info" size={11} /> ทุกหน้าที่สแกนจะถูกบีบอัดและรวมเป็น <b>PDF ไฟล์เดียว</b> ก่อนอัพโหลดเสมอ
        </div>
        {version && <div className="dim" style={{ fontSize: 11.5, textAlign: "right" }}>JS Contract System แอปเวอร์ชัน {version}</div>}
      </div>
    </Modal>
  );
}

// ============================================================
// Modal สแกนเอกสาร — สแกน → ดูตัวอย่าง → สแกนเพิ่ม → รวมเป็น PDF
// ============================================================
function ScanModal({ onClose, onDone, title, nameHint }) {
  const [pages, setPages] = useStateS([]);       // base64 jpeg ต่อหน้า
  const [scanning, setScanning] = useStateS(false);
  const [building, setBuilding] = useStateS(false);
  const [error, setError] = useStateS("");
  const [showSettings, setShowSettings] = useStateS(false);
  const [dragIdx, setDragIdx] = useStateS(null);   // หน้าที่กำลังลาก
  const [overIdx, setOverIdx] = useStateS(null);   // หน้าที่ลากมาวางทับ
  const toast = useToast();

  // ย้ายหน้า from → to (ใช้ทั้งลากวางและปุ่มลูกศร)
  const movePage = (from, to) => {
    if (from == null || to == null || from === to || to < 0 || to >= pages.length) return;
    setPages((prev) => {
      const next = prev.slice();
      const [item] = next.splice(from, 1);
      next.splice(to, 0, item);
      return next;
    });
  };

  const doScan = async () => {
    setScanning(true); setError("");
    const s = getScannerSettings();
    const r = await window.Desktop.scan({
      deviceId: s.deviceId, dpi: s.dpi, color: s.color, source: s.source, quality: s.quality,
    });
    setScanning(false);
    if (!r.ok) { setError(r.error || "สแกนไม่สำเร็จ"); return; }
    setPages((prev) => [...prev, ...r.pages.map((b64) => ({ b64, rot: 0 }))]);
    toast({ t: `สแกนได้ ${r.pages.length} หน้า`, s: r.source === "feeder" ? "จากถาดป้อนเอกสาร" : "จากถาดแก้ว" });
  };

  // หมุนหน้า 90° ต่อคลิก (วน 0→90→180→270)
  const rotatePage = (idx) => setPages((prev) => prev.map((p, i) => i === idx ? { ...p, rot: (p.rot + 90) % 360 } : p));

  const removePage = (idx) => setPages(pages.filter((_, i) => i !== idx));

  const finish = async () => {
    if (!pages.length) return;
    setBuilding(true);
    try {
      const d = new Date();
      const p = (n) => String(n).padStart(2, "0");
      // ใช้เลขสัญญา/รหัสที่ส่งมาเป็นชื่อไฟล์ (ล้างอักขระต้องห้ามแล้ว) — ไม่มีก็ใช้ "สแกน"
      const prefix = sanitizeFilename(nameHint);
      const name = `${prefix}_${d.getFullYear()}${p(d.getMonth()+1)}${p(d.getDate())}_${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}.pdf`;
      // อบมุมหมุนของแต่ละหน้าเข้าไปในภาพจริง แล้วค่อยรวม PDF
      const baked = [];
      for (const pg of pages) baked.push(await rotateB64(pg.b64, pg.rot));
      const file = await pagesToPdfFile(baked, name);
      onDone(file);
    } catch (e) {
      setError("รวมไฟล์ PDF ไม่สำเร็จ: " + e.message);
    }
    setBuilding(false);
  };

  const busy = scanning || building;

  return (
    <>
      <Modal title={title || "สแกนเอกสาร"} icon="print" size="lg" onClose={busy ? () => {} : onClose} foot={
        <>
          <button className="btn" onClick={onClose} disabled={busy}>ยกเลิก</button>
          <div style={{ flex: 1 }}></div>
          <button className="btn" onClick={doScan} disabled={busy}>
            {scanning ? <><span className="spinner" /> กำลังสแกน...</> : pages.length ? <><Icon name="plus" size={13} /> สแกนเพิ่ม</> : <><Icon name="print" size={13} /> เริ่มสแกน</>}
          </button>
          <button className="btn primary" onClick={finish} disabled={busy || !pages.length}>
            {building ? <><span className="spinner" /> กำลังรวมไฟล์...</> : <><Icon name="check" size={13} /> เสร็จสิ้น ({pages.length} หน้า)</>}
          </button>
        </>
      }>
        <div className="hstack" style={{ marginBottom: 10, gap: 8 }}>
          <div className="dim" style={{ fontSize: 12.5, flex: 1 }}>
            {(() => { const s = getScannerSettings(); return `${s.dpi} DPI · ${s.color ? "สี" : "ขาวดำ"} · ${s.source === "feeder" ? "ถาดป้อน" : s.source === "flatbed" ? "ถาดแก้ว" : "อัตโนมัติ"}`; })()}
          </div>
          <button className="btn sm" onClick={() => setShowSettings(true)} disabled={busy}><Icon name="settings" size={12} /> ตั้งค่าเครื่องสแกน</button>
        </div>

        {error && (
          <div style={{ background: "#FEF2F2", border: "1px solid #FECACA", color: "#B91C1C", padding: "10px 12px", borderRadius: 8, fontSize: 13.5, marginBottom: 10 }}>
            ⚠ {error}
          </div>
        )}

        {scanning ? (
          <div style={{ display: "flex", flexDirection: "column", alignItems: "center", padding: 44, gap: 14, color: "var(--text-2)" }}>
            <span className="spinner" style={{ width: 34, height: 34, borderWidth: 3 }}></span>
            <div style={{ fontSize: 14.5, fontWeight: 500 }}>กำลังสแกนเอกสาร...</div>
            <div style={{ fontSize: 12.5 }}>ถ้าใช้ถาดป้อน ระบบจะดูดสแกนต่อเนื่องจนหมดถาดอัตโนมัติ</div>
          </div>
        ) : pages.length === 0 ? (
          <div className="detail-empty" style={{ padding: 40 }}>
            <div className="ico"><Icon name="print" size={36} /></div>
            <div style={{ fontWeight: 500, color: "var(--text-2)" }}>ใส่เอกสารในเครื่องสแกน แล้วกด "เริ่มสแกน"</div>
            <div style={{ fontSize: 12, marginTop: 4 }}>สแกนได้หลายรอบ — ทุกหน้าจะรวมเป็น PDF ไฟล์เดียว</div>
          </div>
        ) : (
          <>
            <div className="dim" style={{ fontSize: 11.5, marginBottom: 6 }}>
              💡 ลากรูปสลับลำดับหน้า · ปุ่ม ↻ หมุนหน้าที่ใส่กลับด้าน · ◀ ▶ เลื่อนทีละช่อง
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(120px, 1fr))", gap: 10, maxHeight: 380, overflow: "auto", padding: 2 }}>
              {pages.map((pg, i) => (
                <div
                  key={i}
                  draggable={!busy}
                  onDragStart={(e) => { setDragIdx(i); e.dataTransfer.effectAllowed = "move"; }}
                  onDragOver={(e) => { e.preventDefault(); e.dataTransfer.dropEffect = "move"; if (overIdx !== i) setOverIdx(i); }}
                  onDragLeave={() => { if (overIdx === i) setOverIdx(null); }}
                  onDrop={(e) => { e.preventDefault(); movePage(dragIdx, i); setDragIdx(null); setOverIdx(null); }}
                  onDragEnd={() => { setDragIdx(null); setOverIdx(null); }}
                  style={{
                    position: "relative", borderRadius: 8, overflow: "hidden", background: "#fff",
                    border: overIdx === i && dragIdx !== i ? "2px dashed var(--brand)" : "1px solid var(--border)",
                    opacity: dragIdx === i ? 0.4 : 1,
                    cursor: busy ? "default" : "grab",
                    transition: "border-color 0.1s, opacity 0.1s",
                  }}
                >
                  <div style={{ position: "relative", height: 150, background: "#f8fafc", overflow: "hidden" }}>
                    <img
                      src={`data:image/jpeg;base64,${pg.b64}`}
                      draggable={false}
                      style={{
                        width: "100%", height: "100%", objectFit: "contain", display: "block", pointerEvents: "none",
                        transform: `rotate(${pg.rot}deg)${pg.rot % 180 !== 0 ? " scale(0.72)" : ""}`,
                        transition: "transform 0.15s",
                      }}
                    />
                    <button
                      title="หมุน 90°"
                      onClick={(e) => { e.stopPropagation(); rotatePage(i); }}
                      style={{
                        position: "absolute", top: 4, right: 4, width: 26, height: 26,
                        border: "1px solid var(--border)", borderRadius: 6, background: "rgba(255,255,255,0.92)",
                        cursor: "pointer", fontSize: 15, lineHeight: 1, display: "grid", placeItems: "center",
                        color: "var(--brand-700)", fontWeight: 700,
                      }}
                    >↻</button>
                    {pg.rot !== 0 && (
                      <span style={{ position: "absolute", top: 4, left: 4, fontSize: 10, background: "var(--brand)", color: "#fff", borderRadius: 4, padding: "1px 5px" }}>
                        {pg.rot}°
                      </span>
                    )}
                  </div>
                  <div className="hstack" style={{ padding: "4px 6px", borderTop: "1px solid var(--border)", fontSize: 11.5, gap: 2 }}>
                    <span className="dim" style={{ fontWeight: 600 }}>หน้า {i + 1}</span>
                    <div style={{ flex: 1 }}></div>
                    <button className="ico-btn" title="เลื่อนไปทางซ้าย" style={{ width: 20, height: 20 }} disabled={i === 0} onClick={() => movePage(i, i - 1)}>
                      <Icon name="chevL" size={10} />
                    </button>
                    <button className="ico-btn" title="เลื่อนไปทางขวา" style={{ width: 20, height: 20 }} disabled={i === pages.length - 1} onClick={() => movePage(i, i + 1)}>
                      <Icon name="chevR" size={10} />
                    </button>
                    <button className="ico-btn danger" title="ลบหน้านี้" style={{ width: 20, height: 20 }} onClick={() => removePage(i)}>
                      <Icon name="x" size={11} />
                    </button>
                  </div>
                </div>
              ))}
            </div>
          </>
        )}
      </Modal>
      {showSettings && <ScannerSettingsModal onClose={() => setShowSettings(false)} />}
    </>
  );
}

// ============================================================
// ปุ่มสแกน (ใช้ใน modal แนบไฟล์ต่างๆ) — แสดงเฉพาะในแอป Desktop
// ============================================================
function ScanButton({ onFile, size = "sm", nameHint }) {
  const [show, setShow] = useStateS(false);
  if (!window.Desktop) return null;
  return (
    <>
      <button className={`btn ${size}`} type="button" onClick={(e) => { e.stopPropagation(); setShow(true); }}>
        <Icon name="print" size={12} /> สแกน
      </button>
      {show && (
        // stopPropagation กันคลิกใน modal ทะลุไปโดน file-drop ที่ครอบปุ่มนี้อยู่
        <span onClick={(e) => e.stopPropagation()}>
          <ScanModal
            nameHint={nameHint}
            onClose={() => setShow(false)}
            onDone={(file) => { setShow(false); onFile(file); }}
          />
        </span>
      )}
    </>
  );
}

// ============================================================
// Host — mount ใน App เพื่อรับคำสั่งจากเมนู "ตั้งค่าเครื่องสแกน"
// ============================================================
function DesktopScannerHost() {
  const [showSettings, setShowSettings] = useStateS(false);
  useEffectS(() => {
    if (!window.Desktop || !window.Desktop.onOpenScannerSettings) return;
    // แอปรุ่นเก่ายังไม่คืนฟังก์ชันถอด listener — ต้องเช็กก่อนเรียก
    const off = window.Desktop.onOpenScannerSettings(() => setShowSettings(true));
    return () => { if (typeof off === "function") off(); };
  }, []);
  if (!window.Desktop) return null;
  return showSettings ? <ScannerSettingsModal onClose={() => setShowSettings(false)} /> : null;
}

Object.assign(window, { ScanModal, ScanButton, ScannerSettingsModal, DesktopScannerHost, getScannerSettings, sanitizeFilename });
