/* global React, I, UI, SSSData */
const { useState: useStateU, useMemo: useMemoU } = React;
const uiU = window.UI;

// Map doc type → list key on SSSData and id field
const TYPE_TO_LIST = {
  invoice: { list: "Invoices", id: "no", party: "customer" },
  "tax-invoice": { list: "TaxInvoices", id: "no", party: "customer" },
  "billing-note": { list: "BillingNotes", id: "no", party: "customer" },
  "purchase-order": { list: "PurchaseOrders", id: "no", party: "vendor" },
  "payment-voucher": { list: "PaymentVouchers", id: "no", party: "vendor" },
  quotation: { list: "Quotations", id: "no", party: "customer" }
};

// =============== เปลี่ยนสถานะเอกสาร (บันทึกถาวร) ===============
const DOC_STATUS_CHOICES = {
  invoice: ["ค้างชำระ", "ชำระบางส่วน", "ชำระแล้ว", "เกินกำหนด", "ยกเลิกแล้ว"],
  "tax-invoice": ["เต็มรูป", "อย่างย่อ", "ยกเลิกแล้ว"],
  quotation: ["ร่าง", "ส่งแล้ว", "รออนุมัติ", "อนุมัติแล้ว", "แปลงเป็นใบสั่ง", "ปฏิเสธ", "ยกเลิกแล้ว"],
  "billing-note": ["ส่งแล้ว", "ลูกค้านัดรับ", "เก็บเงินแล้ว", "ยกเลิกแล้ว"],
  "purchase-order": ["รออนุมัติ", "อนุมัติแล้ว", "รับสินค้าแล้ว", "ยกเลิกแล้ว"],
  "payment-voucher": ["รอจ่าย", "รออนุมัติจ่าย", "อนุมัติแล้ว", "ออกเช็คแล้ว", "จ่ายแล้ว", "ยกเลิกแล้ว"]
};
const DS_KEY = "sss-doc-status";
function dsLoad() { try { return JSON.parse(localStorage.getItem(DS_KEY) || "{}"); } catch { return {}; } }
window.DocStatusStore = {
  set(docType, no, status) {
    const m = dsLoad();
    m[docType] = m[docType] || {};
    m[docType][no] = status;
    try { localStorage.setItem(DS_KEY, JSON.stringify(m)); } catch {}
    const info = TYPE_TO_LIST[docType];
    if (info) {
      const row = (window.SSSData[info.list] || []).find(r => r[info.id] === no);
      if (row) { row.status = status; if (docType === "tax-invoice") row.type = status; }
    }
    window.dispatchEvent(new Event("sss-doc-status-changed"));
  },
  apply() {
    const m = dsLoad();
    Object.entries(m).forEach(([dt, map]) => {
      const info = TYPE_TO_LIST[dt];
      if (!info) return;
      (window.SSSData[info.list] || []).forEach(r => { if (map[r[info.id]]) r.status = map[r[info.id]]; });
    });
  }
};
window.DocStatusStore.apply();

// =============== สถานะที่ 2 (ขั้นถัดไป) — เช่น แปลงเป็นใบส่งสินค้าแล้ว / ออกใบกำกับภาษีแล้ว ===============
const DS2_KEY = "sss-doc-status2";
function ds2Load() { try { return JSON.parse(localStorage.getItem(DS2_KEY) || "{}"); } catch { return {}; } }
window.DocStatus2Store = {
  get(docType, no) { const m = ds2Load(); return (m[docType] || {})[no] || null; },
  set(docType, no, status2) {
    const m = ds2Load();
    m[docType] = m[docType] || {};
    if (status2) m[docType][no] = status2; else delete m[docType][no];
    try { localStorage.setItem(DS2_KEY, JSON.stringify(m)); } catch {}
    window.dispatchEvent(new Event("sss-doc-status-changed"));
  }
};

// แปลงเลขเอกสารในข้อความ (DN/INV/TX/RC/PV/PO/QO/BN) ให้กดเปิดเอกสารต้นทางได้
const DOC_LINK_ROUTE = { DN: "delivery-notes", INV: "invoices", TX: "tax-invoices", RC: "receipts", RE: "receipts", PV: "payment-vouchers", PO: "purchase-orders", QO: "quotations", QT: "quotations", BN: "billing-notes" };
window.docLinkify = function (text, navigate) {
  if (!text) return text;
  const parts = String(text).split(/((?:DN|INV|TX|RC|RE|PV|PO|QO|QT|BN)-[0-9]{4}-[0-9]+)/g);
  return parts.map((p, i) => {
    const m = /^((?:DN|INV|TX|RC|RE|PV|PO|QO|QT|BN))-[0-9]{4}-[0-9]+$/.exec(p);
    if (m && DOC_LINK_ROUTE[m[1]]) return React.createElement("button", { key: i, className: "mono", style: { border: 0, background: "transparent", color: "var(--info)", cursor: "pointer", fontWeight: 700, padding: 0, fontSize: "inherit" }, title: "เปิดเอกสาร " + p, onClick: () => navigate && navigate(DOC_LINK_ROUTE[m[1]] + "/" + p) }, p + " ↗");
    return React.createElement(React.Fragment, { key: i }, p);
  });
};

// แปลงเลขเอกสาร → route หน้าเอกสารนั้น (ใช้กับการ "ไปแก้ต้นเอกสาร")
window.docRouteOf = function (no) {
  const m = /^([A-Z]{2,3})-/.exec(String(no || ""));
  if (m && DOC_LINK_ROUTE[m[1]]) return DOC_LINK_ROUTE[m[1]] + "/" + no;
  return null;
};

// พาเนลอ้างอิงเอกสาร — เอกสารนี้แปลงมาจากอะไร + ถูกแปลงไปเป็นอะไร (คลิกไปต้นทาง/ปลายทางได้)
window.DocRefPanel = function ({ row, navigate }) {
  if (!row) return null;
  const no = row.no || row.id || "";
  const from = row.fromDoc || "";
  const children = (window.DocCreateStore && window.DocCreateStore.findLinks) ? window.DocCreateStore.findLinks(no) : [];
  if (!from && children.length === 0) return null;
  const link = (n) => {
    const route = window.docRouteOf(n);
    return React.createElement("button", {
      className: "mono", title: "เปิดเอกสาร " + n,
      style: { border: 0, background: "transparent", color: "var(--info)", cursor: route ? "pointer" : "default", fontWeight: 700, padding: 0, fontSize: 12.5 },
      onClick: () => { if (route && navigate) navigate(route); }
    }, n + (route ? " ↗" : ""));
  };
  return (
    <div className="card" style={{ padding: "10px 14px", marginBottom: 14, background: "var(--surface-2)", border: "1px solid var(--line)" }}>
      <div style={{ fontSize: 11, fontWeight: 700, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: 6 }}>เอกสารอ้างอิง</div>
      {from && <div style={{ fontSize: 12.5, marginBottom: children.length ? 4 : 0 }}>📋 แปลงมาจาก: {link(from)}</div>}
      {children.length > 0 && (
        <div style={{ fontSize: 12.5 }}>↳ ถูกแปลงไปเป็น: {children.map((c, i) => <React.Fragment key={c.no}>{i ? ", " : ""}{link(c.no)} <span style={{ color: "var(--ink-4)", fontSize: 11 }}>({c.label})</span></React.Fragment>)}</div>
      )}
    </div>
  );
};

// แก้ไขเอกสาร — ถ้าสร้างจากเอกสารอื่น (fromDoc) แนะนำแก้ต้นเอกสาร แต่เลือกแก้ใบนี้ตรง ๆ ได้
window.editDocFlow = async function (row, docType, doEdit, navigate) {
  const src = row && row.fromDoc;
  if (src) {
    const route = window.docRouteOf(src);
    const ans = await window.confirmDialog({
      title: "เอกสารนี้สร้างต่อจาก " + src,
      message: `แก้ที่ต้นเอกสาร <b>${src}</b> แล้วออกใหม่ = ข้อมูลตรงกันทั้งสายเอกสาร<br/>หรือถ้าข้อมูลใบนี้ผิด/ไม่ตรง จะ<b>แก้ใบนี้โดยตรง</b>ก็ได้`,
      confirmText: "แก้ใบนี้เลย",
      extraText: route ? "ไปแก้ต้นเอกสาร" : "",
      cancelText: "ปิด"
    });
    if (ans === "extra") { if (route && navigate) navigate(route); return; }
    if (ans !== true) return;
  }
  doEdit && doEdit();
};

// ───────── แถบเปลี่ยนสถานะแบบคลิกเดียว (ใช้ซ้ำทุกเอกสาร) ─────────
function DocStatusBar({ docType, no, status, onChange, compact }) {
  const choices = DOC_STATUS_CHOICES[docType] || [];
  if (!choices.length) return null;
  const cur = status || choices[0];
  const set = async (s) => {
    if (s === cur) return;
    if (s === "ยกเลิกแล้ว") {
      const ok = await window.confirmDialog({ title: `ยกเลิกเอกสาร ${no}?`, message: "เอกสารจะถูกทำเครื่องหมาย <b>ยกเลิกแล้ว</b> (เก็บเลขไว้ ไม่ลบ) · ซิงค์ทุกเครื่อง", confirmText: "ยกเลิกเอกสาร", danger: true });
      if (!ok) return;
    }
    window.DocStatusStore.set(docType, no, s);
    window.logActivity && window.logActivity("เปลี่ยนสถานะ", `${no} → ${s}`, "update");
    window.toast && window.toast(`เปลี่ยนสถานะเป็น "${s}"`);
    onChange && onChange(s);
  };
  return (
    React.createElement("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 } },
      choices.map(s => {
        const on = s === cur;
        const cancel = s === "ยกเลิกแล้ว";
        const base = { cursor: "pointer", fontFamily: "var(--font)", fontSize: compact ? 11.5 : 12.5, fontWeight: 600, padding: compact ? "4px 9px" : "6px 12px", borderRadius: 999, border: "1px solid", transition: "all .12s", whiteSpace: "nowrap" };
        const styleOn = cancel
          ? { ...base, background: "var(--danger)", color: "#fff", borderColor: "var(--danger)" }
          : { ...base, background: "var(--accent, #7c3aed)", color: "#fff", borderColor: "var(--accent, #7c3aed)" };
        const styleOff = cancel
          ? { ...base, background: "transparent", color: "var(--danger)", borderColor: "var(--danger)" }
          : { ...base, background: "var(--surface)", color: "var(--ink-2)", borderColor: "var(--line-strong)" };
        return React.createElement("button", { key: s, onClick: () => set(s), style: on ? styleOn : styleOff, title: on ? "สถานะปัจจุบัน" : "เปลี่ยนเป็น " + s }, (on ? "● " : "") + s);
      })
    )
  );
}
window.DocStatusBar = DocStatusBar;

// Generate plausible line items from a row's total amount
function fakeLinesFor(docType, row) {
  if (!row) return { lines: [], party: {}, discount: 0, vatPct: 0, hasReal: false };
  const D = window.SSSData;
  // Try to find matching customer/vendor
  const cfg = window.DOC_TYPES[docType];
  const partyList = cfg.party === "customer" ? D.Customers : D.Vendors;
  const partyName = row.customer || row.vendor || row.payee;
  // snapshot ที่บันทึกติดเอกสารชนะ (ข้อมูล ณ วันออกเอกสาร) > โปรไฟล์ CRM ตามชื่อ
  // ไม่ fallback เป็นรายแรกในลิสต์ — แสดงข้อมูลคนอื่นบนเอกสารแย่กว่าเว้นว่าง
  const found = (partyList || []).find(p => p.name === partyName);
  const party = Object.assign({}, found || { name: partyName || "—" }, row.partySnap || {});

  // ✅ ใช้รายการจริงที่บันทึกตอนสร้างเอกสารก่อนเสมอ (กันรายการ/ยอดหาย)
  if (Array.isArray(row.lines) && row.lines.length > 0) {
    const lines = row.lines.map((l, i) => ({
      id: i + 1, sku: l.sku || "", name: l.name || l.desc || "",
      qty: Number(l.qty) || 1, unit: l.unit || "",
      price: l.price != null ? Number(l.price) : (Number(l.amount) || 0),
      img: l.img || ""
    }));
    return { lines, party, discount: Number(row.discount) || 0, vatPct: row.vatPct != null ? Number(row.vatPct) : (cfg.showVAT && docType !== "payment-voucher" ? 7 : 0), hasReal: true };
  }

  const totalIncVat = row.amount;
  const total = cfg.showVAT ? totalIncVat / 1.07 : totalIncVat;

  // Lines depending on doc type and party
  let lines = [];
  if (docType === "purchase-order") {
    // Raw materials based on vendor category
    if (party.category && party.category.includes("สแตนเลส")) {
      lines = [
        { id: 1, sku: "SS304-SH-1.0", name: "แผ่นสแตนเลส 304 หนา 1.0 มม. 4x8 ฟุต", qty: Math.floor(total / 2850 * 0.6), unit: "แผ่น", price: 2850 },
        { id: 2, sku: "SS304-SH-1.5", name: "แผ่นสแตนเลส 304 หนา 1.5 มม. 4x8 ฟุต", qty: Math.floor(total / 4180 * 0.4), unit: "แผ่น", price: 4180 }
      ];
    } else if (party.category && party.category.includes("เหล็ก")) {
      lines = [
        { id: 1, sku: "STL-PL-3", name: "แผ่นเหล็กดำ หนา 3 มม. 4x8 ฟุต", qty: Math.floor(total / 1240 * 0.7), unit: "แผ่น", price: 1240 },
        { id: 2, sku: "STL-HB-50", name: "เหล็กกล่อง 50x50 หนา 2.3 มม. ยาว 6 ม.", qty: Math.floor(total / 540 * 0.3), unit: "เส้น", price: 540 }
      ];
    } else {
      lines = [{ id: 1, sku: "", name: party.category || "วัตถุดิบ/อุปกรณ์", qty: 1, unit: "lot", price: total }];
    }
  } else if (docType === "payment-voucher") {
    const pvName = row.desc || row.purpose || (row.ref ? `จ่ายตามอ้างอิง: ${row.ref}` : `ชำระเงินให้ ${row.payee || party.name || ""}`.trim());
    lines = [{ id: 1, sku: "", name: pvName, qty: 1, unit: "ครั้ง", price: totalIncVat }];
  } else if (docType === "tax-invoice") {
    lines = [
      { id: 1, sku: "SS316-SH-2.0", name: "แผ่นสแตนเลส 316L หนา 2.0 มม. 4x8 ฟุต", qty: Math.floor(total / 11200 * 0.6), unit: "แผ่น", price: 11200 },
      { id: 2, sku: "SVC-CNC-LASER", name: "ค่าบริการตัด CNC Fiber Laser", qty: Math.floor(total * 0.2 / 850), unit: "ชม.", price: 850 },
      { id: 3, sku: "SVC-WELD-TIG", name: "ค่าบริการเชื่อม TIG", qty: Math.floor(total * 0.2 / 650), unit: "ชม.", price: 650 }
    ];
  } else if (docType === "invoice") {
    lines = [
      { id: 1, sku: "—", name: `งานตามใบเสนอราคา ${(row.no || "").replace("INV", "QO")}`, qty: 1, unit: "งาน", price: total }
    ];
  } else if (docType === "billing-note") {
    // List the underlying invoices
    lines = (row.invoices || []).map((inv, i) => ({
      id: i + 1, sku: "", name: `ใบแจ้งหนี้ ${inv}`, qty: 1, unit: "ใบ", price: row.amount / (row.invoices?.length || 1)
    }));
    if (lines.length === 0) lines = [{ id: 1, sku: "", name: "ค่าสินค้าและบริการ", qty: 1, unit: "lot", price: total }];
  } else {
    lines = [{ id: 1, sku: "", name: "ค่าสินค้าและบริการ", qty: 1, unit: "lot", price: total }];
  }

  return { lines: lines.filter(l => l.qty > 0), party, discount: 0, vatPct: cfg.showVAT && docType !== "payment-voucher" ? 7 : 0, hasReal: false };
}

// ============ Universal doc detail view ============
function UniversalDocDetail({ docType, docId, navigate }) {
  const D = window.SSSData;
  const info = TYPE_TO_LIST[docType];
  const list = D[info.list] || [];
  const row = list.find(r => r[info.id] === docId) || list[0];
  const cfg = window.DOC_TYPES[docType];
  const { lines, party, discount: rDiscount, vatPct: rVatPct } = useMemoU(() => fakeLinesFor(docType, row), [docType, row]);
  const [, forceU] = useStateU(0);
  const [payModal, setPayModal] = useStateU(false);

  const rawSubtotal = lines.reduce((s, l) => s + l.qty * l.price, 0);
  const discount = rDiscount || 0;
  const vatPct = rVatPct != null ? rVatPct : (cfg.showVAT && docType !== "payment-voucher" ? 7 : 0);
  const inclusive = !!row.vatIncl && cfg.showVAT && vatPct > 0;   // ราคาที่กรอกรวม VAT แล้ว → ถอดออก
  const subtotal = inclusive ? rawSubtotal / (1 + vatPct / 100) : rawSubtotal;
  const afterDisc = subtotal - discount;
  const vat = (cfg.showVAT && vatPct > 0) ? afterDisc * vatPct / 100 : 0;
  const grand = afterDisc + vat;
  // หัก ณ ที่จ่าย: ใช้ค่าที่บันทึกติดเอกสาร (แสดงในใบพิมพ์ซ้ำได้เหมือนตอนออก)
  const whtPct = row && row.whtPct != null ? Number(row.whtPct) : 0;
  const wht = row && row.wht != null ? Number(row.wht) : (whtPct > 0 ? afterDisc * whtPct / 100 : 0);

  const { Btn, Badge, Card, PageHead, Workflow, fmt0, fmtM } = uiU;

  // Workflow steps per doc type
  const workflows = {
    invoice: ["สร้าง", "ส่งให้ลูกค้า", "รอชำระ", "ชำระแล้ว"],
    "tax-invoice": ["สร้าง", "ออกเอกสาร", "ส่งให้ลูกค้า", "นำส่งใน ภ.พ.30"],
    "billing-note": ["สร้าง", "นัดวันเก็บ", "ลูกค้าเซ็นรับ", "เก็บเงินแล้ว"],
    "purchase-order": ["ร่าง", "รออนุมัติ", "ส่งให้ vendor", "รับสินค้าแล้ว"],
    "payment-voucher": ["บันทึก", "อนุมัติ", "ออกเช็ค/โอน", "จ่ายแล้ว"]
  };
  const currentStep = {
    invoice: row.status === "ชำระแล้ว" ? 3 : row.status === "ชำระบางส่วน" ? 2 : row.status === "เกินกำหนด" ? 2 : 2,
    "tax-invoice": 2,
    "billing-note": row.status === "เก็บเงินแล้ว" ? 3 : row.status === "ลูกค้านัดรับ" ? 1 : 2,
    "purchase-order": row.status === "รับสินค้าแล้ว" ? 3 : row.status === "อนุมัติแล้ว" ? 2 : 1,
    "payment-voucher": row.status === "จ่ายแล้ว" ? 3 : 2
  }[docType] || 1;

  // แปลงใบส่งสินค้า/ใบแจ้งหนี้ → ใบเสร็จรับเงิน (+ ใบกำกับภาษี) — สร้างเอกสารจริง
  const convertInvoice = async (withTax) => {
    const inv = row;
    const baseLines = lines.map(l => ({ sku: l.sku, name: l.name, qty: l.qty, unit: l.unit, price: l.price }));
    const ok = await window.confirmDialog({
      title: withTax ? "แปลงเป็นใบเสร็จรับเงิน + ใบกำกับภาษี" : "แปลงเป็นใบเสร็จรับเงินอย่างเดียว",
      message: `บันทึกรับชำระเงินจาก <b>${inv.customer}</b> ตาม <b class="mono">${inv[info.id]}</b> ยอด <b>฿${fmt0(inv.amount)}</b>`,
      bullets: withTax
        ? ["ออกใบกำกับภาษีเต็มรูป (VAT 7%) ให้อัตโนมัติ", "เปิดฟอร์มใบเสร็จรับเงินให้ตรวจแล้วบันทึก (เงินเข้าบัญชีอัตโนมัติ)", "เปลี่ยนสถานะใบแจ้งหนี้เป็น 'ชำระแล้ว'"]
        : ["เปิดฟอร์มใบเสร็จรับเงินให้ตรวจแล้วบันทึก (เงินเข้าบัญชีอัตโนมัติ)", "เปลี่ยนสถานะใบแจ้งหนี้เป็น 'ชำระแล้ว'"],
      confirmText: withTax ? "ออกใบเสร็จ + ใบกำกับภาษี" : "ออกใบเสร็จ"
    });
    if (!ok) return;
    if (!window.openNewDoc) { window.toast && window.toast("ระบบออกเอกสารยังไม่พร้อม ลองรีเฟรช"); return; }
    let txNo = "";
    if (withTax && window.DocCreateStore) {
      const _m = ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."];
      const _d = new Date(); const today = `${_d.getDate()} ${_m[_d.getMonth()]} ${_d.getFullYear() + 543}`;
      txNo = window.DocCreateStore.nextNo("TaxInvoices", "TX");
      const _pct = inv.vatPct != null ? Number(inv.vatPct) : 7;
      const _base = Math.round((Number(inv.amount) || 0) / (1 + _pct / 100));
      window.DocCreateStore.add("TaxInvoices", {
        no: txNo, date: today, customer: inv.customer, amount: inv.amount, status: "ออกแล้ว", type: "เต็มรูป",
        // ยึด base/vat ที่บันทึกไว้จริงในใบแจ้งหนี้ (ตรงกันแน่นอน) — คำนวณเองเฉพาะใบเก่าที่ไม่มีข้อมูล
        base: inv.base != null ? inv.base : _base,
        vat: inv.vat != null ? inv.vat : Math.round((Number(inv.amount) || 0) - _base),
        vatIncl: !!inv.vatIncl,   // ธง "รวมภาษี" ต้องตามใบแจ้งหนี้ — ไม่งั้นยอดถูกคิด VAT ซ้ำ
        lines: baseLines, vatPct: _pct, discount: inv.discount || 0,
        whtPct: inv.whtPct != null ? Number(inv.whtPct) : 0, wht: inv.wht != null ? Number(inv.wht) : 0,
        fromDoc: inv[info.id], project: inv.project || "", projectName: inv.projectName || "",
        partySnap: inv.partySnap || undefined,
        issuedBy: (window.Session && window.Session.get() && window.Session.get().name) || ""
      });
    }
    window.DocStatusStore.set("invoice", inv[info.id], "ชำระแล้ว");
    window.DocStatus2Store.set("invoice", inv[info.id], withTax ? `ออกใบเสร็จ + ใบกำกับภาษีแล้ว (${txNo})` : "ออกใบเสร็จแล้ว");
    window.logActivity && window.logActivity("แปลงเอกสาร", `${inv[info.id]} → ใบเสร็จ${withTax ? " + " + txNo : ""}`, "create");
    window.openNewDoc("receipt", {
      fromDoc: inv[info.id], partyName: inv.customer, project: inv.project || "", projectName: inv.projectName || "",
      lines: baseLines, discount: Number(inv.discount) || 0, vatPct: inv.vatPct != null ? Number(inv.vatPct) : 7,
      vatIncl: !!inv.vatIncl, whtPct: inv.whtPct != null ? Number(inv.whtPct) : 0
    });
    forceU(n => n + 1);
  };

  // แปลงใบกำกับภาษี → ใบเสร็จรับเงิน (ส่งต่อเอกสาร + ลิงก์อ้างอิง)
  const convertTaxToReceipt = async () => {
    const tx = row;
    const baseLines = lines.map(l => ({ sku: l.sku, name: l.name, qty: l.qty, unit: l.unit, price: l.price }));
    const ok = await window.confirmDialog({
      title: "ออกใบเสร็จรับเงินจากใบกำกับภาษี",
      message: `บันทึกรับชำระเงินจาก <b>${tx.customer}</b> ตามใบกำกับภาษี <b class="mono">${tx[info.id]}</b> ยอด <b>฿${fmt0(tx.amount)}</b>`,
      bullets: ["เปิดฟอร์มใบเสร็จรับเงินให้ตรวจแล้วบันทึก (เงินเข้าบัญชีอัตโนมัติ)", "ลิงก์อ้างอิงกับใบกำกับภาษีนี้"],
      confirmText: "ออกใบเสร็จ"
    });
    if (!ok) return;
    if (!window.openNewDoc) { window.toast && window.toast("ระบบออกเอกสารยังไม่พร้อม ลองรีเฟรช"); return; }
    window.DocStatus2Store.set("tax-invoice", tx[info.id], "ออกใบเสร็จแล้ว");
    window.logActivity && window.logActivity("แปลงเอกสาร", `${tx[info.id]} → ใบเสร็จรับเงิน`, "create");
    window.openNewDoc("receipt", {
      fromDoc: tx[info.id], partyName: tx.customer, project: tx.project || "", projectName: tx.projectName || "",
      lines: baseLines, discount: Number(tx.discount) || 0, vatPct: tx.vatPct != null ? Number(tx.vatPct) : 7,
      vatIncl: !!tx.vatIncl, whtPct: tx.whtPct != null ? Number(tx.whtPct) : 0
    });
    forceU(n => n + 1);
  };

  const listRoute = docType === "invoice" ? "invoices" : docType === "tax-invoice" ? "tax-invoices" : docType === "billing-note" ? "billing-notes" : docType === "purchase-order" ? "purchase-orders" : "payment-vouchers";
  if (!row) {
    return (
      <div style={{ display: "grid", placeItems: "center", minHeight: "60vh" }}>
        <div style={{ textAlign: "center", maxWidth: 360 }}>
          <div style={{ fontSize: 16, fontWeight: 700, marginBottom: 6 }}>ไม่พบเอกสารนี้</div>
          <div style={{ fontSize: 13, color: "var(--ink-3)", marginBottom: 16 }}>เอกสารอาจถูกลบไปแล้ว หรือย้ายไปถังกู้คืน</div>
          <Btn kind="primary" onClick={() => navigate(listRoute)}>กลับไปหน้ารายการ</Btn>
        </div>
      </div>
    );
  }

  return (
    <>
      <PageHead
        title={<span style={{display: "flex", alignItems: "center", gap: 12}}>
          <Btn kind="ghost" size="sm" onClick={() => navigate(listRoute)}>
            <I.chevronLeft size={14} className="icon"/>กลับ
          </Btn>
          {cfg.title} <span className="mono" style={{fontSize: 16, color: "var(--ink-3)", fontWeight: 500}}>{row[info.id]}</span>
        </span>}
        sub={`${cfg.partyLabel}: ${row.customer || row.vendor || row.payee} · ${row.date}`}
        right={<>
          <Btn icon={I.edit} kind="ghost" onClick={() => window.editDocFlow(row, docType, () => window.openNewDoc && window.openNewDoc(docType, { editing: true, docNo: row[info.id], date: row.date, partyName: row.customer || row.vendor || row.payee, lines: lines.map(l => ({ sku: l.sku, name: l.name, qty: l.qty, unit: l.unit, price: l.price })) }), navigate)}>แก้ไขเอกสาร</Btn>
          <Btn icon={I.msg} kind="ghost" onClick={() => window.toast && window.toast(`ส่ง ${cfg.title} ${row[info.id]} ทางอีเมลให้ ${row.customer || row.vendor || row.payee} แล้ว`)}>ส่งทางอีเมล</Btn>
          <Btn icon={I.print} kind="ghost" onClick={() => window.printDocPaperWithOptions()}>พิมพ์</Btn>
          <Btn icon={I.download} kind={(docType === "invoice" || docType === "payment-voucher") ? "ghost" : "primary"} onClick={() => window.printDocPaperWithOptions()}>ดาวน์โหลด PDF</Btn>
          {row.status !== "ยกเลิกแล้ว" && <Btn icon={I.close} kind="ghost" onClick={() => window.cancelDocFlow && window.cancelDocFlow(info.list, row[info.id], cfg.title, () => forceU(n => n + 1))}>ยกเลิกเอกสาร</Btn>}
          <Btn icon={I.trash} kind="ghost" onClick={() => window.deleteDocFlow && window.deleteDocFlow(info.list, row[info.id], cfg.title, navigate)}>ลบ</Btn>
          {docType === "payment-voucher" && row.status !== "จ่ายแล้ว" && (
            <Btn icon={I.money} kind="primary" onClick={() => setPayModal(true)}>กดจ่าย → เลือกบัญชีบริษัท</Btn>
          )}
          {docType === "invoice" && <>
            <Btn icon={I.receipt} kind="ghost" onClick={() => convertInvoice(false)}>ใบเสร็จอย่างเดียว</Btn>
            <Btn icon={I.arrowRight} kind="primary" onClick={() => convertInvoice(true)}>แปลงเป็นใบเสร็จ + ใบกำกับภาษี</Btn>
          </>}
          {docType === "tax-invoice" && row.status !== "ยกเลิกแล้ว" && (
            <Btn icon={I.receipt} kind="primary" onClick={convertTaxToReceipt}>ออกใบเสร็จรับเงิน</Btn>
          )}
        </>}
      />

      <div className="grid" style={{gridTemplateColumns: "1fr 320px", gap: 14, alignItems: "flex-start"}}>
        <div>
          <window.DocRefPanel row={row} navigate={navigate}/>
          {/* Workflow */}
          <Card padded={false} className="mb-lg" flush>
            <div style={{padding: "14px 16px"}}>
              <Workflow steps={workflows[docType] || ["สร้าง", "ออก", "ส่ง", "ปิดงาน"]} current={currentStep}/>
            </div>
          </Card>

          {/* Doc paper */}
          <window.NewDocPrintablePaper
            cfg={cfg}
            docType={docType}
            docNo={row[info.id]}
            date={row.date}
            dueDate={row.due || row.dueDate || row.expected || "—"}
            validity={row.validity || "—"}
            expected={row.expected || "—"}
            method={row.method || "โอน · KBank"}
            party={party}
            lines={lines}
            subtotal={subtotal}
            discount={discount}
            vat={vat}
            vatPct={vatPct}
            wht={wht}
            whtPct={whtPct}
            grand={grand}
            notes={row.notes || cfg.note}
            withImages={row.withImages}
            issuedBy={row.issuedBy}
            docDetail={docType === "receipt" ? (row.detail || "") : ""}
            signStamp={!!row.signStamp}
          />
        </div>

        {/* Side panel */}
        <div style={{display: "flex", flexDirection: "column", gap: 14}}>
          <Card title="สถานะ" right={<Badge>{row.status || "ออกแล้ว"}</Badge>}>
            {(() => { const s2 = window.DocStatus2Store && window.DocStatus2Store.get(docType, row[info.id]); return s2 ? (
              <div style={{display: "flex", alignItems: "center", gap: 8, padding: "7px 10px", marginBottom: 10, background: "var(--success-bg, var(--surface-2))", border: "1px solid var(--success)", borderRadius: 8, fontSize: 12.5}}>
                <I.check size={14} stroke="var(--success)"/>
                <span style={{flex: 1}}><b style={{color: "var(--success)"}}>สถานะที่ 2:</b> {window.docLinkify ? window.docLinkify(s2, navigate) : s2}</span>
                <button className="icon-btn" title="ลบสถานะที่ 2" onClick={() => { window.DocStatus2Store.set(docType, row[info.id], null); forceU(n => n + 1); }}><I.close size={11}/></button>
              </div>
            ) : null; })()}
            <div style={{display: "flex", flexDirection: "column", gap: 8, fontSize: 13}}>
              {DOC_STATUS_CHOICES[docType] && (
                <div className="field" style={{marginBottom: 2}}>
                  <label style={{fontSize: 11, color: "var(--ink-3)", display: "block", marginBottom: 6}}>เปลี่ยนสถานะ — คลิกเดียว</label>
                  <window.DocStatusBar docType={docType} no={row[info.id]} status={row.status} onChange={() => forceU(n => n + 1)}/>
                </div>
              )}
              <div style={{display: "flex", justifyContent: "space-between"}}><span className="muted">เลขที่</span><span className="mono">{row[info.id]}</span></div>
              <div style={{display: "flex", justifyContent: "space-between"}}><span className="muted">วันที่</span><span>{row.date}</span></div>
              {row.due && <div style={{display: "flex", justifyContent: "space-between"}}><span className="muted">ครบกำหนด</span><span>{row.due}</span></div>}
              {row.dueDate && <div style={{display: "flex", justifyContent: "space-between"}}><span className="muted">ครบกำหนด</span><span>{row.dueDate}</span></div>}
              {row.expected && <div style={{display: "flex", justifyContent: "space-between"}}><span className="muted">นัดรับ</span><span>{row.expected}</span></div>}
              {row.paid !== undefined && <div style={{display: "flex", justifyContent: "space-between"}}><span className="muted">ชำระแล้ว</span><span className="amount">฿{fmt0(row.paid)}</span></div>}
              {row.method && <div style={{display: "flex", justifyContent: "space-between"}}><span className="muted">วิธีจ่าย</span><span>{row.method}</span></div>}
            </div>
          </Card>

          <Card title={cfg.partyLabel} right={<Btn size="sm" kind="ghost" onClick={() => navigate(cfg.party === "customer" ? "customers" : "vendors")}>เปิดโปรไฟล์</Btn>}>
            <div style={{fontSize: 13, lineHeight: 1.6}}>
              <div style={{fontWeight: 500, marginBottom: 4}}>{party.name}</div>
              <div className="muted">เลขผู้เสียภาษี <span className="mono">{party.taxId}</span></div>
              <div className="muted">{party.contact}</div>
              <div className="mono muted">{party.phone}</div>
              {party.credit !== undefined && <div className="muted">เครดิต {party.credit} วัน</div>}
              {party.terms && <div className="muted">เงื่อนไข: {party.terms}</div>}
            </div>
          </Card>

          {(docType === "billing-note" && row.invoices) && (
            <Card title="ใบแจ้งหนี้ที่รวม">
              <div style={{display: "flex", flexDirection: "column", gap: 6}}>
                {row.invoices.map(inv => <Badge key={inv}>{inv}</Badge>)}
              </div>
            </Card>
          )}

          {docType === "payment-voucher" && (
            <Card title="อ้างอิง">
              <div className="mono" style={{fontSize: 12, lineHeight: 1.6}}>{row.ref}</div>
            </Card>
          )}

          {window.DocHistoryPanel && <window.DocHistoryPanel listKey={info.list} docNo={row[info.id]}/>}
        </div>
      </div>

      {payModal && <PayFromCompanyModal row={row} onClose={() => setPayModal(false)} navigate={navigate}/>}
    </>
  );
}

// =============== กดจ่ายใบสำคัญจ่าย → เลือกบัญชีบริษัท ===============
function PayFromCompanyModal({ row, onClose, navigate }) {
  const { Btn, fmt0 } = window.UI;
  const [accountId, setAccountId] = useStateU("SCB");
  const balances = window.CompanyCashStore ? window.CompanyCashStore.balances() : [];
  const confirmPay = () => {
    if (!window.CompanyCashStore) { window.toast && window.toast("ระบบบัญชีบริษัทยังไม่พร้อม"); return; }
    const acc = balances.find(a => a.id === accountId);
    window.CompanyCashStore.addPayment({
      voucherNo: row.no, payee: row.payee,
      desc: `ตามใบสำคัญจ่าย ${row.no} · อ้างอิง ${row.ref || "—"}`,
      accountId, amount: row.amount
    });
    window.DocStatusStore && window.DocStatusStore.set("payment-voucher", row.no, "รออนุมัติจ่าย");
    window.logActivity && window.logActivity("กดจ่ายใบสำคัญจ่าย", `${row.no} → จ่ายผ่าน${acc ? acc.short : accountId}`, "expense");
    window.toast && window.toast(`สร้างรายการจ่าย ${row.no} ขึ้นที่บัญชี${acc ? acc.short : ""}แล้ว — ไปอนุมัติจ่าย + แนบสลิปต่อ`);
    onClose();
    setTimeout(() => navigate("company-cash"), 500);
  };
  return (
    <>
      <div className="scrim" style={{zIndex: 80}} onClick={onClose}></div>
      <div style={{position: "fixed", left: "50%", top: "50%", transform: "translate(-50%, -50%)", zIndex: 81, background: "var(--surface)", border: "1px solid var(--line)", borderRadius: 12, padding: 18, width: 480, maxWidth: "94vw", maxHeight: "92vh", overflowY: "auto", boxShadow: "var(--shadow-lg)"}}>
        <div style={{fontSize: 14.5, fontWeight: 700, marginBottom: 4}}>กดจ่าย — เลือกบัญชีที่จะจ่าย</div>
        <div style={{fontSize: 12.5, color: "var(--ink-3)", marginBottom: 12}}>{row.no} · {row.payee} · <b className="amount" style={{color: "var(--ink-1)"}}>฿{fmt0(row.amount)}</b></div>
        {window.CCAccountPicker
          ? <window.CCAccountPicker value={accountId} onChange={setAccountId} balances={balances}/>
          : <div className="muted" style={{fontSize: 12}}>ไม่พบข้อมูลบัญชี</div>}
        <div style={{marginTop: 10, padding: "8px 12px", background: "var(--surface-2)", borderRadius: 8, fontSize: 11.5, color: "var(--ink-3)", lineHeight: 1.7}}>
          รายการจะขึ้นที่บัญชีที่เลือก สถานะ "รออนุมัติจ่าย" — จากนั้นไปกด <b style={{color: "var(--ink-1)"}}>อนุมัติจ่าย + แนบสลิป/หลักฐาน</b> ระบบจึงจะบันทึกลงระบบบัญชี
        </div>
        <div style={{display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 14}}>
          <Btn kind="ghost" onClick={onClose}>ยกเลิก</Btn>
          <Btn kind="primary" icon={I.check} onClick={confirmPay}>สร้างรายการจ่าย</Btn>
        </div>
      </div>
    </>
  );
}

window.UniversalDocDetail = UniversalDocDetail;

// =============== Bank slip uploader (for payment vouchers) ===============
function SlipUpload({ voucherNo }) {
  const { Btn, Card } = window.UI;
  // เก็บในแมพรวม sss-doc-slips ผ่าน lsSyncGet/lsSyncSet — sync ทุกเครื่อง + ไม่กินโควต้า localStorage
  // (เดิม sss-slip-<no> ค้างเครื่องเดียว ล้างเบราว์เซอร์แล้วหาย — มีตัวย้ายข้อมูลเก่าอัตโนมัติใน supabase-sync)
  const slipsGet = () => {
    const map = (window.lsSyncGet && window.lsSyncGet("sss-doc-slips")) || {};
    if (Array.isArray(map[voucherNo])) return map[voucherNo];
    try { return JSON.parse(localStorage.getItem(`sss-slip-${voucherNo}`) || "[]"); } catch { return []; }
  };
  const [slips, setSlips] = useStateU(slipsGet);
  const [preview, setPreview] = useStateU(null);

  const save = (list) => {
    setSlips(list);
    const map = Object.assign({}, (window.lsSyncGet && window.lsSyncGet("sss-doc-slips")) || {});
    map[voucherNo] = list;
    if (window.lsSyncSet) window.lsSyncSet("sss-doc-slips", map);
    else { try { localStorage.setItem(`sss-slip-${voucherNo}`, JSON.stringify(list)); } catch {} }
  };

  const onPick = (e) => {
    const files = [...e.target.files];
    Promise.all(files.map(f => new Promise(res => {
      const reader = new FileReader();
      reader.onload = () => res({
        name: f.name,
        url: reader.result,
        size: f.size,
        type: f.type,
        uploadedAt: new Date().toLocaleString("th-TH", { day: "2-digit", month: "short", year: "2-digit", hour: "2-digit", minute: "2-digit" })
      });
      reader.readAsDataURL(f);
    }))).then(loaded => {
      save([...slipsGet(), ...loaded]);   // ต่อท้ายข้อมูลสด — สลิปที่เครื่องอื่นแนบไม่หาย
      window.toast && window.toast(`แนบสลิป ${loaded.length} ไฟล์`);
    });
    e.target.value = "";
  };

  const removeSlip = (i) => {
    const t = slips[i];
    save(slipsGet().filter(x => !(x && t && x.url === t.url && x.name === t.name)));
  };

  return (
    <>
      <Card title="สลิปการโอนเงิน" sub={`${slips.length} ไฟล์`} right={
        <label className="btn sm" style={{cursor: "pointer"}}>
          <I.upload className="icon" size={13}/>
          แนบสลิป
          <input type="file" accept="image/*,application/pdf" multiple style={{display: "none"}} onChange={onPick}/>
        </label>
      }>
        {slips.length === 0 ? (
          <label style={{cursor: "pointer", display: "block"}}>
            <input type="file" accept="image/*,application/pdf" multiple style={{display: "none"}} onChange={onPick}/>
            <div className="attach-dropzone">
              <I.upload size={20}/>
              <div style={{marginTop: 6, fontSize: 12}}>คลิกหรือลากไฟล์สลิปมาวาง</div>
              <div style={{fontSize: 11, marginTop: 2}}>JPG, PNG หรือ PDF</div>
            </div>
          </label>
        ) : (
          <div style={{display: "flex", flexDirection: "column", gap: 8}}>
            {slips.map((s, i) => {
              const isImg = s.type && s.type.startsWith("image/");
              return (
                <div key={i} style={{display: "flex", gap: 10, padding: 8, border: "1px solid var(--line)", borderRadius: 6, alignItems: "center"}}>
                  {isImg ? (
                    <img src={s.url} alt={s.name} onClick={() => setPreview(s)}
                      style={{width: 56, height: 56, objectFit: "cover", borderRadius: 4, cursor: "pointer", border: "1px solid var(--line)"}}/>
                  ) : (
                    <div style={{width: 56, height: 56, borderRadius: 4, background: "var(--surface-2)", border: "1px solid var(--line)", display: "grid", placeItems: "center", color: "var(--ink-3)", fontSize: 10, fontWeight: 600}}>PDF</div>
                  )}
                  <div style={{flex: 1, minWidth: 0}}>
                    <div style={{fontSize: 12.5, fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>{s.name}</div>
                    <div style={{fontSize: 10.5, color: "var(--ink-3)"}}>{(s.size/1024).toFixed(0)} KB · {s.uploadedAt}</div>
                  </div>
                  <div style={{display: "flex", gap: 4}}>
                    <button className="icon-btn" onClick={() => isImg ? setPreview(s) : window.open(s.url, "_blank")} title="ดู"><I.search size={12}/></button>
                    <button className="icon-btn" onClick={() => removeSlip(i)} title="ลบ"><I.trash size={12}/></button>
                  </div>
                </div>
              );
            })}
            <label style={{cursor: "pointer"}}>
              <input type="file" accept="image/*,application/pdf" multiple style={{display: "none"}} onChange={onPick}/>
              <div style={{padding: "8px 12px", border: "1.5px dashed var(--line-strong)", borderRadius: 6, textAlign: "center", color: "var(--ink-3)", fontSize: 12}}>+ เพิ่มสลิป</div>
            </label>
          </div>
        )}
      </Card>

      {preview && (
        <div className="scrim" style={{display: "flex", alignItems: "center", justifyContent: "center", padding: 24}} onClick={() => setPreview(null)}>
          <div style={{position: "relative", maxWidth: "90vw", maxHeight: "90vh"}}>
            <button className="icon-btn" onClick={() => setPreview(null)} style={{position: "absolute", top: -36, right: 0, background: "white"}}>
              <I.close size={14}/>
            </button>
            <img src={preview.url} alt={preview.name} style={{maxWidth: "90vw", maxHeight: "90vh", borderRadius: 6, boxShadow: "0 20px 60px rgba(0,0,0,0.4)"}}/>
            <div style={{position: "absolute", left: 0, bottom: -28, color: "white", fontSize: 12}}>{preview.name}</div>
          </div>
        </div>
      )}
    </>
  );
}

window.SlipUpload = SlipUpload;

// =============== แผงท้ายเอกสาร: ประวัติ + แนบสลิป + คอมเมนต์ (sync ผ่าน DocCreateStore) ===============
function DocHistoryPanel({ listKey, docNo }) {
  const { Card, Btn } = window.UI;
  const [, forceH] = useStateU(0);
  const [comment, setComment] = useStateU("");
  const [preview, setPreview] = useStateU(null);
  React.useEffect(() => {
    const h = () => forceH(n => n + 1);
    window.addEventListener("sss-docs-changed", h);
    window.addEventListener("sss-data-synced", h);
    return () => { window.removeEventListener("sss-docs-changed", h); window.removeEventListener("sss-data-synced", h); };
  }, []);
  const list = window.SSSData[listKey] || [];
  const row = list.find(r => r.no === docNo) || {};
  const me = (window.Session && window.Session.get() && window.Session.get().name) || (window.SSSData.Company.currentUser && window.SSSData.Company.currentUser.name) || "ผู้ใช้";
  const nowStr = () => new Date().toLocaleString("th-TH", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" });
  const comments = Array.isArray(row.comments) ? row.comments : [];
  const slips = Array.isArray(row.slips) ? row.slips : [];
  const acts = (window.SSSData.Activity || []).filter(a => (a.target || "").includes(docNo)).slice(0, 12);

  const addComment = () => {
    if (!comment.trim() || !window.DocCreateStore) return;
    window.DocCreateStore.patch(listKey, docNo, { comments: [...comments, { by: me, text: comment.trim(), at: nowStr() }] });
    setComment(""); window.toast && window.toast("เพิ่มความคิดเห็นแล้ว");
  };
  const delComment = (i) => window.DocCreateStore.patch(listKey, docNo, { comments: comments.filter((_, j) => j !== i) });

  const onPickSlip = async (e) => {
    const files = [...e.target.files]; e.target.value = "";
    const out = [];
    for (const f of files) {
      const url = window.DeliveryStore && window.DeliveryStore.resizeImage ? await window.DeliveryStore.resizeImage(f, 1100) : null;
      if (url) out.push({ url, name: f.name, by: me, at: nowStr() });
    }
    if (out.length) {
      window.DocCreateStore.patch(listKey, docNo, { slips: [...slips, ...out] });
      window.logActivity && window.logActivity("แนบสลิป", `${docNo} (${out.length} ไฟล์)`, "update");
      window.toast && window.toast(`แนบสลิป ${out.length} ไฟล์แล้ว`);
    }
  };
  const delSlip = (i) => window.DocCreateStore.patch(listKey, docNo, { slips: slips.filter((_, j) => j !== i) });

  return (
    <>
      {/* แนบสลิป / หลักฐาน */}
      <Card title="สลิป / หลักฐานการชำระ" sub={`${slips.length} ไฟล์ · ซิงค์ทุกเครื่อง`} right={
        <label className="btn sm" style={{ cursor: "pointer" }}><I.upload className="icon" size={13} />แนบสลิป
          <input type="file" accept="image/*" multiple style={{ display: "none" }} onChange={onPickSlip} /></label>
      }>
        {slips.length === 0 ? (
          <label style={{ cursor: "pointer", display: "block" }}>
            <input type="file" accept="image/*" multiple style={{ display: "none" }} onChange={onPickSlip} />
            <div className="attach-dropzone"><I.upload size={20} /><div style={{ marginTop: 6, fontSize: 12 }}>คลิกเพื่อแนบสลิปโอนเงิน</div></div>
          </label>
        ) : (
          <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
            {slips.map((s, i) => (
              <div key={i} style={{ position: "relative" }}>
                <img src={s.url} alt="" onClick={() => setPreview(s)} title={`${s.by || ""} · ${s.at || ""}`}
                  style={{ width: 78, height: 78, objectFit: "cover", borderRadius: 6, cursor: "pointer", border: "1px solid var(--line)" }} />
                <button className="icon-btn" onClick={() => delSlip(i)} title="ลบ"
                  style={{ position: "absolute", top: -6, right: -6, background: "var(--surface)", boxShadow: "var(--shadow-sm)", width: 20, height: 20 }}><I.close size={11} /></button>
              </div>
            ))}
          </div>
        )}
      </Card>

      {/* ความคิดเห็น */}
      <Card title="ความคิดเห็น" sub={`${comments.length} ข้อความ`}>
        <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 10 }}>
          {comments.length === 0 && <div style={{ fontSize: 12.5, color: "var(--ink-3)" }}>ยังไม่มีความคิดเห็น</div>}
          {comments.map((c, i) => (
            <div key={i} style={{ background: "var(--surface-2)", borderRadius: 8, padding: "8px 10px" }}>
              <div style={{ display: "flex", justifyContent: "space-between", gap: 8 }}>
                <b style={{ fontSize: 12 }}>{c.by}</b>
                <span style={{ display: "flex", alignItems: "center", gap: 6 }}>
                  <span style={{ fontSize: 10.5, color: "var(--ink-3)" }}>{c.at}</span>
                  {c.by === me && <button className="icon-btn" style={{ width: 18, height: 18 }} onClick={() => delComment(i)} title="ลบ"><I.close size={10} /></button>}
                </span>
              </div>
              <div style={{ fontSize: 12.5, marginTop: 2, whiteSpace: "pre-wrap" }}>{c.text}</div>
            </div>
          ))}
        </div>
        <div style={{ display: "flex", gap: 6 }}>
          <input className="input" value={comment} onChange={e => setComment(e.target.value)} placeholder="เขียนความคิดเห็น…"
            onKeyDown={e => { if (e.key === "Enter") addComment(); }} style={{ flex: 1, height: 34 }} />
          <Btn size="sm" kind="primary" icon={I.send} onClick={addComment}>ส่ง</Btn>
        </div>
      </Card>

      {/* ประวัติเอกสาร */}
      <Card title="ประวัติเอกสาร" sub={`${acts.length} กิจกรรม`}>
        {acts.length === 0 ? <div style={{ fontSize: 12.5, color: "var(--ink-3)" }}>ยังไม่มีประวัติ</div> : (
          <div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
            {acts.map((a, i) => (
              <div key={i} style={{ display: "flex", gap: 9, padding: "7px 0", borderBottom: i < acts.length - 1 ? "1px solid var(--line-soft)" : "none" }}>
                <span style={{ width: 7, height: 7, borderRadius: "50%", background: "var(--brand)", marginTop: 5, flexShrink: 0 }} />
                <div style={{ minWidth: 0 }}>
                  <div style={{ fontSize: 12.5 }}><b>{a.user}</b> {a.action}</div>
                  <div style={{ fontSize: 11, color: "var(--ink-3)" }}>{a.when}</div>
                </div>
              </div>
            ))}
          </div>
        )}
      </Card>

      {preview && (
        <div className="scrim" style={{ display: "flex", alignItems: "center", justifyContent: "center", padding: 24, zIndex: 200 }} onClick={() => setPreview(null)}>
          <img src={preview.url} alt="" style={{ maxWidth: "90vw", maxHeight: "90vh", borderRadius: 8, boxShadow: "0 20px 60px rgba(0,0,0,0.4)" }} />
        </div>
      )}
    </>
  );
}
window.DocHistoryPanel = DocHistoryPanel;
