// Purchase Request module — Item Master page (Phase 1)
// Additional pages (PR list, Create PR wizard, Approvals, Reports) are added in later phases
// within this same file to keep the module bundled together.

const PR_ITEM_CATEGORIES = [
  "IT Equipment",
  "Software License",
  "Office Supplies",
  "Furniture",
  "Marketing Material",
  "Consumables",
  "Service",
  "Other",
];

// Small icon-only action button reused across PR pages
const IconBtn = ({ icon, tip, onClick, disabled, danger }) => {
  const btn = (
    <button onClick={onClick} disabled={disabled}
      className={`w-7 h-7 rounded-md flex items-center justify-center transition
        ${danger ? "text-rose-500 hover:bg-rose-50" : "text-ink-500 hover:bg-ink-100 hover:text-ink-800"}
        ${disabled ? "opacity-40 cursor-not-allowed" : ""}`}>
      <Icon name={icon} size={13}/>
    </button>
  );
  return tip ? <Tip tip={tip}>{btn}</Tip> : btn;
};

// Thai date input: 3 segments (DD / MM / YYYY in BE).
// Internally stores as ISO CE "YYYY-MM-DD" so the rest of the system (DB, formatThaiDate)
// keeps working without conversion. Empty string when any segment is missing.
const ThaiDateInput = ({ value, onChange, placeholder, min, max, disabled }) => {
  // Parse external CE ISO → BE-display segments
  const initial = (() => {
    if (!value) return { d:"", m:"", y:"" };
    const m = String(value).match(/^(\d{4})-(\d{2})-(\d{2})/);
    if (!m) return { d:"", m:"", y:"" };
    return {
      d: m[3].replace(/^0/, ""),
      m: m[2].replace(/^0/, ""),
      y: String(parseInt(m[1], 10) + 543),
    };
  })();
  const [seg, setSeg] = useState(initial);
  // Re-sync if external value changes
  useEffect(() => { setSeg(initial); /* eslint-disable-next-line */ }, [value]);

  const emit = (next) => {
    setSeg(next);
    const dd = parseInt(next.d, 10);
    const mm = parseInt(next.m, 10);
    const yBE = parseInt(next.y, 10);
    // Wait until all 3 valid before emitting
    if (!dd || !mm || !yBE || dd < 1 || dd > 31 || mm < 1 || mm > 12 || yBE < 2400 || yBE > 2700) {
      onChange(""); return;
    }
    const yCE = yBE - 543;
    const iso = `${yCE}-${String(mm).padStart(2,"0")}-${String(dd).padStart(2,"0")}`;
    if (min && iso < min) return;
    if (max && iso > max) return;
    onChange(iso);
  };

  const segClass = "w-full text-center text-[12.5px] font-mono bg-transparent focus:outline-none disabled:opacity-50";
  return (
    <div className={`flex items-center gap-1 h-9 px-2 bg-white border border-ink-200 rounded-lg ${disabled?"opacity-60":"focus-within:border-brand-500 ring-focus"}`}>
      <input type="number" inputMode="numeric" min="1" max="31" placeholder="วว" value={seg.d} disabled={disabled}
        onChange={e=>emit({...seg, d:e.target.value})} className={segClass + " w-9"}/>
      <span className="text-ink-300 select-none">/</span>
      <input type="number" inputMode="numeric" min="1" max="12" placeholder="ดด" value={seg.m} disabled={disabled}
        onChange={e=>emit({...seg, m:e.target.value})} className={segClass + " w-9"}/>
      <span className="text-ink-300 select-none">/</span>
      <input type="number" inputMode="numeric" min="2400" max="2700" placeholder="ปปปป (พ.ศ.)" value={seg.y} disabled={disabled}
        onChange={e=>emit({...seg, y:e.target.value})} className={segClass + " w-16"}/>
      <Icon name="calendar" size={13} className="ml-auto text-ink-400 shrink-0"/>
    </div>
  );
};

// =========================================================================
// ITEM MASTER PAGE
// =========================================================================
const ItemMasterPage = ({ tenant, currentUser }) => {
  const toast = useToast();
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(false);
  const [q, setQ] = useState("");
  const [filterCat, setFilterCat] = useState("__all__");
  const [filterStatus, setFilterStatus] = useState("active");
  const [editFor, setEditFor] = useState(null);   // null | "new" | item object
  const [importOpen, setImportOpen] = useState(false);

  const reload = async () => {
    if (!tenant?.id || !window.apiClient) return;
    setLoading(true);
    try {
      const rows = await window.apiClient.prListItems(tenant.id);
      setItems(Array.isArray(rows) ? rows : []);
    } catch (e) {
      toast({ kind:"error", msg: e.message || "โหลดรายการสินค้าไม่สำเร็จ" });
    } finally { setLoading(false); }
  };
  useEffect(() => { reload(); /* eslint-disable-next-line */ }, [tenant?.id]);

  // KPI counts
  const totalCount = items.length;
  const activeCount = items.filter(i => i.status === "active").length;
  const inactiveCount = items.filter(i => i.status === "inactive").length;
  const categoryCount = new Set(items.map(i => i.category).filter(Boolean)).size;

  // Filtered + searched view
  const filtered = useMemo(() => {
    const ql = q.trim().toLowerCase();
    return items.filter(it => {
      if (filterStatus !== "__all__" && it.status !== filterStatus) return false;
      if (filterCat !== "__all__" && (it.category || "") !== filterCat) return false;
      if (!ql) return true;
      return (it.item_code || "").toLowerCase().includes(ql)
          || (it.name || "").toLowerCase().includes(ql)
          || (it.description || "").toLowerCase().includes(ql);
    });
  }, [items, q, filterCat, filterStatus]);

  const onSave = async (form, isNew) => {
    try {
      if (isNew) {
        await window.apiClient.prCreateItem(tenant.id, form);
        toast({ kind:"success", msg:"สร้างรายการสินค้าใหม่แล้ว" });
      } else {
        await window.apiClient.prUpdateItem(tenant.id, editFor.id, form);
        toast({ kind:"success", msg:"บันทึกการแก้ไขแล้ว" });
      }
      setEditFor(null);
      reload();
    } catch (e) {
      toast({ kind:"error", msg: e.message || "บันทึกไม่สำเร็จ" });
    }
  };

  const onToggleStatus = async (it) => {
    const next = it.status === "active" ? "inactive" : "active";
    try {
      await window.apiClient.prUpdateItem(tenant.id, it.id, { status: next });
      toast({ kind:"success", msg: next === "inactive" ? "ปิดใช้งานสินค้าแล้ว" : "เปิดใช้งานสินค้าแล้ว" });
      reload();
    } catch (e) {
      toast({ kind:"error", msg: e.message });
    }
  };

  const onExportExcel = () => {
    // Export simple CSV — Excel-compatible. UTF-8 BOM for Thai compatibility.
    const head = ["รหัสสินค้า","ชื่อสินค้า","รายละเอียด","หมวด","หน่วย","Supplier","ราคาฐาน (บาท)","สถานะ"];
    const lines = [head.join(",")];
    filtered.forEach(it => {
      const row = [
        it.item_code, it.name, it.description||"", it.category||"",
        it.unit||"", it.supplier_name||"", Number(it.base_price)||0, it.status
      ].map(v => {
        const s = String(v ?? "");
        return s.includes(",") || s.includes('"') || s.includes("\n") ? `"${s.replace(/"/g,'""')}"` : s;
      });
      lines.push(row.join(","));
    });
    const csv = "﻿" + lines.join("\r\n");
    const blob = new Blob([csv], { type:"text/csv;charset=utf-8" });
    const a = document.createElement("a");
    a.href = URL.createObjectURL(blob);
    a.download = `ItemMaster_${tenant?.tenant_code || "tenant"}_${new Date().toISOString().slice(0,10)}.csv`;
    a.click();
    URL.revokeObjectURL(a.href);
  };

  return (
    <div className="p-5 max-w-[1600px] mx-auto">
      {/* Header */}
      <div className="flex items-end justify-between mb-5 flex-wrap gap-3">
        <div>
          <div className="text-[11px] uppercase tracking-[.2em] text-ink-400 font-semibold">ฐานข้อมูลสินค้า · ITEM MASTER</div>
          <h1 className="text-[26px] font-bold tracking-tight mt-1 text-ink-900">Item Master</h1>
          <p className="text-[13px] text-ink-500 mt-1">จัดการรายการสินค้าและบริการที่ใช้ในการสร้างคำขอจัดซื้อ (PR)</p>
        </div>
        <div className="flex items-center gap-2">
          <Button variant="secondary" icon="upload" onClick={()=>setImportOpen(true)}>นำเข้า Excel</Button>
          <Button variant="secondary" icon="download" onClick={onExportExcel}>ส่งออก Excel</Button>
          <Button icon="plus" onClick={()=>setEditFor("new")}>เพิ่มสินค้าใหม่</Button>
        </div>
      </div>

      {/* KPI cards */}
      <div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-5">
        <KpiCard icon="package" tone="indigo" label="สินค้าทั้งหมด" value={totalCount} trend="รายการที่บันทึกไว้"/>
        <KpiCard icon="check" tone="emerald" label="สินค้าใช้งานอยู่" value={activeCount} trend="Active"/>
        <KpiCard icon="ban" tone="rose" label="ไม่ใช้งาน" value={inactiveCount} trend="Inactive"/>
        <KpiCard icon="bookmark" tone="violet" label="หมวดสินค้า" value={categoryCount} trend="Categories"/>
      </div>

      {/* Filter row */}
      <div className="flex flex-wrap items-center gap-2 mb-3">
        <div className="relative flex-1 min-w-[240px] max-w-[420px]">
          <Icon name="search" size={13} className="absolute left-3 top-1/2 -translate-y-1/2 text-ink-400"/>
          <input value={q} onChange={e=>setQ(e.target.value)} placeholder="ค้นหารหัส / ชื่อสินค้า…"
            className="w-full h-9 pl-9 pr-3 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus"/>
        </div>
        <select value={filterCat} onChange={e=>setFilterCat(e.target.value)}
          className="h-9 px-3 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus">
          <option value="__all__">ทุกหมวด</option>
          {PR_ITEM_CATEGORIES.map(c => <option key={c} value={c}>{c}</option>)}
        </select>
        <select value={filterStatus} onChange={e=>setFilterStatus(e.target.value)}
          className="h-9 px-3 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus">
          <option value="active">เฉพาะ Active</option>
          <option value="inactive">เฉพาะ Inactive</option>
          <option value="__all__">ทั้งหมด</option>
        </select>
        <div className="ml-auto text-[12px] text-ink-500">พบ <strong className="text-ink-800">{filtered.length}</strong> / {items.length} รายการ</div>
      </div>

      {/* Table */}
      <div className="rounded-2xl border border-ink-200 bg-white overflow-hidden">
        <table className="w-full text-[12.5px]">
          <thead className="bg-ink-50 text-ink-500 text-[11px] uppercase tracking-wider">
            <tr>
              {["รหัสสินค้า","ชื่อสินค้า / รายละเอียด","หมวด","หน่วย","Supplier หลัก","ราคาฐาน","สถานะ","อัปเดตล่าสุด","การกระทำ"].map(h => (
                <th key={h} className="text-left font-semibold px-3 py-2.5 border-b border-ink-200">{h}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {loading && (
              <tr><td colSpan={9} className="text-center py-10 text-ink-400">กำลังโหลด…</td></tr>
            )}
            {!loading && filtered.length === 0 && (
              <tr><td colSpan={9} className="text-center py-16 text-ink-400">ไม่พบรายการที่ตรงกับเงื่อนไข</td></tr>
            )}
            {!loading && filtered.map(it => (
              <tr key={it.id} className="hover:bg-ink-50/60 border-b border-ink-100 last:border-0">
                <td className="px-3 py-3 font-mono text-ink-700">{it.item_code}</td>
                <td className="px-3 py-3">
                  <div className="font-semibold text-ink-900">{it.name}</div>
                  {it.description && <div className="text-[11.5px] text-ink-500 truncate-1">{it.description}</div>}
                </td>
                <td className="px-3 py-3">
                  {it.category && <span className="inline-block px-2 py-0.5 rounded-md bg-violet-50 text-violet-700 text-[11px] font-medium">{it.category}</span>}
                </td>
                <td className="px-3 py-3 text-ink-600">{it.unit || "—"}</td>
                <td className="px-3 py-3 text-ink-700">{it.supplier_name || "—"}</td>
                <td className="px-3 py-3 font-mono text-ink-800 text-right">฿{Number(it.base_price||0).toLocaleString("th-TH", { minimumFractionDigits:2, maximumFractionDigits:2 })}</td>
                <td className="px-3 py-3">
                  <span className={`inline-flex items-center gap-1 px-1.5 py-0.5 rounded-md text-[11px] font-medium ${it.status==="active" ? "bg-emerald-50 text-emerald-700" : "bg-rose-50 text-rose-700"}`}>
                    <span className={`w-1.5 h-1.5 rounded-full ${it.status==="active"?"bg-emerald-500":"bg-rose-500"}`}/>
                    {it.status === "active" ? "Active" : "Inactive"}
                  </span>
                </td>
                <td className="px-3 py-3 font-mono text-ink-500">{(it.updated_at||"").slice(0,10)}</td>
                <td className="px-3 py-3">
                  <div className="flex items-center gap-1">
                    <IconBtn icon="edit" tip="แก้ไข" onClick={()=>setEditFor(it)}/>
                    <IconBtn icon={it.status==="active"?"ban":"check"} tip={it.status==="active"?"ปิดใช้งาน":"เปิดใช้งาน"} onClick={()=>onToggleStatus(it)}/>
                  </div>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {/* Edit modal */}
      <ItemEditModal target={editFor} onClose={()=>setEditFor(null)} onSave={onSave}/>
      {/* Import modal */}
      <ItemImportModal open={importOpen} tenant={tenant} existingItems={items} onClose={()=>setImportOpen(false)} onDone={()=>{ setImportOpen(false); reload(); }}/>
    </div>
  );
};

// =========================================================================
// ITEM EDIT MODAL
// =========================================================================
const ItemEditModal = ({ target, onClose, onSave }) => {
  const [f, setF] = useState({});
  useEffect(() => {
    if (!target) return;
    if (target === "new") {
      setF({ item_code:"", name:"", description:"", category:"IT Equipment", unit:"", supplier_name:"", base_price:0, status:"active" });
    } else {
      setF({ ...target, base_price: target.base_price ?? 0 });
    }
  }, [target]);
  if (!target) return null;
  const isNew = target === "new";
  const set = (k,v) => setF(p => ({ ...p, [k]:v }));
  const valid = (f.item_code||"").trim() && (f.name||"").trim();

  return (
    <Modal open onClose={onClose}
      title={isNew ? "เพิ่มสินค้าใหม่" : "แก้ไขรายการสินค้า"}
      subtitle={isNew ? "กรอกข้อมูลรายการสินค้าหรือบริการ" : `${target.item_code} · ${target.name}`}
      width={620}
      footer={<>
        <Button variant="secondary" onClick={onClose}>ยกเลิก</Button>
        <Button icon="check" disabled={!valid} onClick={()=>onSave(f, isNew)}>{isNew?"สร้าง":"บันทึก"}</Button>
      </>}>
      <div className="grid grid-cols-2 gap-3">
        <Field label="รหัสสินค้า" required>
          <Input value={f.item_code||""} onChange={e=>set("item_code", e.target.value.toUpperCase())} placeholder="เช่น IT-LP-001" className="font-mono uppercase"/>
        </Field>
        <Field label="หมวดสินค้า">
          <select value={f.category||""} onChange={e=>set("category", e.target.value)}
            className="w-full h-9 px-2.5 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus">
            <option value="">— ไม่ระบุ —</option>
            {PR_ITEM_CATEGORIES.map(c => <option key={c} value={c}>{c}</option>)}
          </select>
        </Field>
        <Field label="ชื่อสินค้า" required className="col-span-2">
          <Input value={f.name||""} onChange={e=>set("name", e.target.value)} placeholder="เช่น Notebook Dell Latitude 5550"/>
        </Field>
        <Field label="รายละเอียด / Spec" className="col-span-2">
          <textarea value={f.description||""} onChange={e=>set("description", e.target.value)} rows={2}
            className="w-full px-2.5 py-2 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus"
            placeholder="เช่น i7-1355U, 16GB RAM, 512GB SSD, 14&quot;"/>
        </Field>
        <Field label="หน่วยนับ">
          <Input value={f.unit||""} onChange={e=>set("unit", e.target.value)} placeholder="เช่น เครื่อง, ใบ, License/ปี"/>
        </Field>
        <Field label="Supplier หลัก">
          <Input value={f.supplier_name||""} onChange={e=>set("supplier_name", e.target.value)} placeholder="ชื่อ Supplier"/>
        </Field>
        <Field label="ราคาฐาน (บาท)">
          <Input type="number" min="0" step="0.01" value={f.base_price||0} onChange={e=>set("base_price", e.target.value)} className="font-mono text-right"/>
        </Field>
        <Field label="สถานะ">
          <select value={f.status||"active"} onChange={e=>set("status", e.target.value)}
            className="w-full h-9 px-2.5 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus">
            <option value="active">Active · ใช้งานได้</option>
            <option value="inactive">Inactive · ปิดใช้งาน</option>
          </select>
        </Field>
      </div>
      <div className="mt-4 px-3 py-2 rounded-md bg-blue-50 border border-blue-200 text-blue-700 text-[11.5px] flex items-start gap-2">
        <Icon name="info" size={13} className="mt-0.5 shrink-0"/>
        <span>สินค้าที่ถูกใช้งานใน PR แล้ว <strong>ยังคงดูได้</strong>แม้จะเปลี่ยนเป็น Inactive — แต่จะไม่ปรากฏใน list ตอนสร้าง PR ใหม่</span>
      </div>
    </Modal>
  );
};

// =========================================================================
// ITEM IMPORT MODAL — template download + file upload (CSV/XLSX) + duplicate preview
// =========================================================================
// Lazy-load SheetJS only when the user actually picks an .xlsx file
const loadXLSX = () => new Promise((resolve, reject) => {
  if (window.XLSX) return resolve(window.XLSX);
  const s = document.createElement("script");
  s.src = "https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js";
  s.onload = () => window.XLSX ? resolve(window.XLSX) : reject(new Error("XLSX library โหลดผิดพลาด"));
  s.onerror = () => reject(new Error("ดาวน์โหลด XLSX library ไม่สำเร็จ — กรุณาตรวจอินเทอร์เน็ต"));
  document.head.appendChild(s);
});

// CSV-safe quote: wrap in "..." if value contains comma/quote/newline
const csvQuote = (v) => {
  const s = String(v ?? "");
  return s.includes(",") || s.includes('"') || s.includes("\n") ? `"${s.replace(/"/g, '""')}"` : s;
};

const ITEM_TEMPLATE_HEADER = ["รหัสสินค้า","ชื่อสินค้า","รายละเอียด","หมวด","หน่วย","Supplier","ราคาฐาน","สถานะ"];
const ITEM_TEMPLATE_EXAMPLES = [
  ["IT-LP-001", "Notebook Dell Latitude 5550", "i7-1355U, 16GB RAM, 512GB SSD, 14\"", "IT Equipment", "เครื่อง", "บจก. เดลล์ คอร์ปอเรชั่น", "38500", "active"],
  ["SW-0365-01", "Microsoft 365 Business Premium", "License/User/Year", "Software License", "License/ปี", "บจก. ไมโครซอฟท์ ไทยแลนด์", "7920", "active"],
  ["OS-PA-101", "กระดาษ A4 80 แกรม", "500 แผ่น/รีม · 5 รีม/กล่อง", "Office Supplies", "กล่อง", "บจก. ออฟฟิศพลัส", "690", "active"],
];

const downloadItemTemplate = () => {
  const lines = [ITEM_TEMPLATE_HEADER.join(",")];
  ITEM_TEMPLATE_EXAMPLES.forEach(row => lines.push(row.map(csvQuote).join(",")));
  const csv = "﻿" + lines.join("\r\n");
  const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
  const a = document.createElement("a");
  a.href = URL.createObjectURL(blob);
  a.download = "Item_Master_Template.csv";
  a.click();
  setTimeout(() => URL.revokeObjectURL(a.href), 1000);
};

// Strict CSV parser — handles quoted cells with comma + escaped quotes
const parseCsvText = (text) => {
  const rows = [];
  let row = [], cell = "", inQuote = false;
  for (let i = 0; i < text.length; i++) {
    const c = text[i], n = text[i+1];
    if (inQuote) {
      if (c === '"' && n === '"') { cell += '"'; i++; }
      else if (c === '"') inQuote = false;
      else cell += c;
    } else {
      if (c === '"') inQuote = true;
      else if (c === ',' || c === '\t') { row.push(cell); cell = ""; }
      else if (c === '\r') { /* ignore */ }
      else if (c === '\n') { row.push(cell); rows.push(row); row=[]; cell=""; }
      else cell += c;
    }
  }
  if (cell || row.length) { row.push(cell); rows.push(row); }
  return rows.filter(r => r.length && r.some(c => (c||"").trim()));
};

const ItemImportModal = ({ open, tenant, existingItems, onClose, onDone }) => {
  const toast = useToast();
  const [csv, setCsv] = useState("");
  const [busy, setBusy] = useState(false);
  const [fileName, setFileName] = useState("");
  const fileInputRef = useRef(null);
  useEffect(() => { if (open) { setCsv(""); setFileName(""); } }, [open]);
  if (!open) return null;

  // Existing item codes (uppercase) for fast duplicate lookup
  const existingCodeMap = new Map();
  (existingItems || []).forEach(it => existingCodeMap.set(String(it.item_code || "").toUpperCase(), it));

  // Parse + classify what's in the textarea — used for live preview AND on import
  const parseAndClassify = () => {
    const trimmed = csv.trim();
    if (!trimmed) return { ok: false, rows: [], summary: null };
    const rows = parseCsvText(trimmed.replace(/^﻿/, ""));
    if (rows.length < 2) return { ok: false, error: "ไม่พบข้อมูล (ต้องมี header + แถวอย่างน้อย 1 แถว)" };
    const header = rows[0].map(h => (h||"").trim());
    const idxOf = (...keys) => header.findIndex(h => keys.some(k => h.toLowerCase().includes(k.toLowerCase())));
    const idx = {
      item_code: idxOf("รหัส","code"),
      name: idxOf("ชื่อ","name"),
      description: idxOf("รายละเอียด","description","spec"),
      category: idxOf("หมวด","category"),
      unit: idxOf("หน่วย","unit"),
      supplier_name: idxOf("supplier","ผู้ขาย"),
      base_price: idxOf("ราคา","price"),
      status: idxOf("สถานะ","status"),
    };
    if (idx.item_code < 0 || idx.name < 0) return { ok: false, error: "ไม่พบ column รหัส/ชื่อ ใน header — กรุณาตรวจไฟล์" };

    const seenInBatch = new Set();
    const items = [];
    let invalid = 0, dupInBatch = 0;
    rows.slice(1).forEach(r => {
      const code = (r[idx.item_code] || "").trim().toUpperCase();
      const name = (r[idx.name] || "").trim();
      if (!code || !name) { invalid++; return; }
      if (seenInBatch.has(code)) { dupInBatch++; return; }
      seenInBatch.add(code);
      items.push({
        item_code: code, name,
        description: idx.description>=0 ? (r[idx.description]||"").trim() : "",
        category: idx.category>=0 ? (r[idx.category]||"").trim() : "",
        unit: idx.unit>=0 ? (r[idx.unit]||"").trim() : "",
        supplier_name: idx.supplier_name>=0 ? (r[idx.supplier_name]||"").trim() : "",
        base_price: idx.base_price>=0 ? Number(String(r[idx.base_price]||"").replace(/,/g,"")) || 0 : 0,
        status: idx.status>=0 && /inactive|ปิด/i.test(r[idx.status]||"") ? "inactive" : "active",
      });
    });

    const willCreate = items.filter(it => !existingCodeMap.has(it.item_code));
    const willUpdate = items.filter(it => existingCodeMap.has(it.item_code));
    return {
      ok: items.length > 0,
      items,
      summary: {
        total: items.length, create: willCreate.length, update: willUpdate.length,
        invalid, dupInBatch,
        duplicateCodes: willUpdate.map(it => it.item_code).slice(0, 5),
      },
    };
  };

  const preview = parseAndClassify();

  // Handle file picker — supports both .csv and .xlsx
  const onPickFile = async (e) => {
    const file = e.target.files?.[0];
    e.target.value = ""; // allow re-uploading the same file
    if (!file) return;
    setFileName(file.name);
    try {
      if (/\.xlsx?$/i.test(file.name)) {
        const XLSX = await loadXLSX();
        const buf = await file.arrayBuffer();
        const wb = XLSX.read(buf, { type: "array" });
        const sheetName = wb.SheetNames[0];
        if (!sheetName) throw new Error("ไม่พบ sheet ในไฟล์ Excel");
        const csvText = XLSX.utils.sheet_to_csv(wb.Sheets[sheetName]);
        setCsv(csvText);
        toast({ kind:"success", msg:`อ่านไฟล์ ${file.name} สำเร็จ — ตรวจสอบ preview ด้านล่าง` });
      } else if (/\.csv$/i.test(file.name) || file.type.includes("csv")) {
        const text = await file.text();
        setCsv(text);
        toast({ kind:"success", msg:`อ่านไฟล์ ${file.name} สำเร็จ` });
      } else {
        toast({ kind:"error", msg:"รองรับเฉพาะไฟล์ .csv และ .xlsx เท่านั้น" });
      }
    } catch (err) {
      toast({ kind:"error", msg: err.message || "อ่านไฟล์ไม่สำเร็จ" });
    }
  };

  const doImport = async () => {
    if (!preview.ok) {
      toast({ kind:"error", msg: preview.error || "ไม่มีรายการที่ถูกต้องให้นำเข้า" });
      return;
    }
    // Confirm if there are duplicates that will overwrite existing items
    if (preview.summary.update > 0) {
      const codes = preview.summary.duplicateCodes.join(", ");
      const more = preview.summary.update > 5 ? ` (และอีก ${preview.summary.update - 5})` : "";
      const ok = window.confirm(
        `พบรหัสซ้ำกับของเดิม ${preview.summary.update} รายการ:\n${codes}${more}\n\n` +
        `กดยืนยันแล้วระบบจะ "อัปเดตทับ" ของเดิม ไม่สามารถย้อนกลับได้ — ต้องการดำเนินการต่อหรือไม่?`
      );
      if (!ok) return;
    }
    setBusy(true);
    try {
      const res = await window.apiClient.prBulkImportItems(tenant.id, preview.items);
      toast({ kind:"success", msg:`นำเข้าสำเร็จ — เพิ่มใหม่ ${res.inserted} · อัปเดต ${res.updated} · ข้าม ${res.skipped}` });
      onDone();
    } catch (e) {
      toast({ kind:"error", msg: e.message || "นำเข้าไม่สำเร็จ" });
    } finally { setBusy(false); }
  };

  return (
    <Modal open onClose={onClose} title="นำเข้ารายการสินค้า (Excel/CSV)"
      subtitle="ดาวน์โหลด template, อัปโหลดไฟล์ หรือคัดลอกจาก Excel มาวาง"
      width={720}
      footer={<>
        <Button variant="secondary" onClick={onClose}>ยกเลิก</Button>
        <Button icon="upload" disabled={busy || !preview.ok} onClick={doImport}>
          {busy ? "กำลังนำเข้า…" : preview.summary ? `นำเข้า ${preview.summary.total} รายการ` : "นำเข้า"}
        </Button>
      </>}>
      <div className="space-y-3">
        {/* Action row: Download template + Upload file */}
        <div className="flex flex-wrap items-center gap-2">
          <Button variant="secondary" icon="download" onClick={downloadItemTemplate}>ดาวน์โหลด Template</Button>
          <Button variant="secondary" icon="upload" onClick={()=>fileInputRef.current?.click()}>เลือกไฟล์ (.csv / .xlsx)</Button>
          <input ref={fileInputRef} type="file" accept=".csv,.xlsx,.xls" className="hidden" onChange={onPickFile}/>
          {fileName && <div className="text-[11.5px] text-ink-600 flex items-center gap-1.5"><Icon name="fileText" size={12}/>{fileName}</div>}
        </div>

        {/* Format hint */}
        <div className="px-3 py-2.5 rounded-md bg-amber-50 border border-amber-200 text-amber-800 text-[11.5px] flex items-start gap-2">
          <Icon name="info" size={13} className="mt-0.5 shrink-0"/>
          <div>
            <div className="font-semibold mb-0.5">Header ที่รองรับ (column ใดก็ได้ตามลำดับ):</div>
            <div className="font-mono text-[10.5px]">รหัสสินค้า, ชื่อสินค้า, รายละเอียด, หมวด, หน่วย, Supplier, ราคาฐาน, สถานะ</div>
            <div className="mt-1.5">รายการที่มีรหัสซ้ำกับของเดิมจะถูก <strong>อัปเดตทับ</strong> · ใน batch เดียวกันที่ซ้ำกันเองจะใช้แถวแรก</div>
          </div>
        </div>

        {/* Textarea */}
        <textarea value={csv} onChange={e=>setCsv(e.target.value)} rows={10}
          placeholder="วาง CSV หรือคัดลอกจาก Excel มาวางที่นี่... (หรือใช้ปุ่ม &quot;เลือกไฟล์&quot; ด้านบน)"
          className="w-full px-3 py-2 text-[11.5px] font-mono bg-ink-50 border border-ink-200 rounded-lg focus:border-brand-500 ring-focus"/>

        {/* Live preview / duplicate detection */}
        {csv.trim() && (
          <div className="rounded-lg border border-ink-200 p-3 space-y-2 text-[12px]">
            <div className="text-[11px] uppercase tracking-wider text-ink-500 font-semibold">สรุปก่อนนำเข้า</div>
            {!preview.ok && (
              <div className="text-rose-600 flex items-center gap-1.5"><Icon name="warning" size={13}/>{preview.error || "ไม่มีรายการที่ใช้งานได้"}</div>
            )}
            {preview.ok && (
              <>
                <div className="grid grid-cols-2 md:grid-cols-4 gap-2">
                  <div className="px-2.5 py-1.5 rounded-md bg-emerald-50 border border-emerald-200">
                    <div className="text-[10.5px] text-emerald-700 uppercase">รายการใหม่</div>
                    <div className="text-[16px] font-bold text-emerald-700">{preview.summary.create}</div>
                  </div>
                  <div className={`px-2.5 py-1.5 rounded-md border ${preview.summary.update>0?"bg-amber-50 border-amber-200":"bg-ink-50 border-ink-200"}`}>
                    <div className="text-[10.5px] uppercase" style={{color: preview.summary.update>0 ? "#b45309" : "#6b7280"}}>อัปเดตทับ</div>
                    <div className="text-[16px] font-bold" style={{color: preview.summary.update>0 ? "#b45309" : "#9ca3af"}}>{preview.summary.update}</div>
                  </div>
                  <div className={`px-2.5 py-1.5 rounded-md border ${preview.summary.invalid>0?"bg-rose-50 border-rose-200":"bg-ink-50 border-ink-200"}`}>
                    <div className="text-[10.5px] uppercase" style={{color: preview.summary.invalid>0 ? "#be123c" : "#6b7280"}}>ข้าม (ไม่ครบ)</div>
                    <div className="text-[16px] font-bold" style={{color: preview.summary.invalid>0 ? "#be123c" : "#9ca3af"}}>{preview.summary.invalid}</div>
                  </div>
                  <div className={`px-2.5 py-1.5 rounded-md border ${preview.summary.dupInBatch>0?"bg-rose-50 border-rose-200":"bg-ink-50 border-ink-200"}`}>
                    <div className="text-[10.5px] uppercase" style={{color: preview.summary.dupInBatch>0 ? "#be123c" : "#6b7280"}}>ซ้ำใน batch</div>
                    <div className="text-[16px] font-bold" style={{color: preview.summary.dupInBatch>0 ? "#be123c" : "#9ca3af"}}>{preview.summary.dupInBatch}</div>
                  </div>
                </div>
                {preview.summary.update > 0 && (
                  <div className="text-[11.5px] text-amber-800 bg-amber-50 border border-amber-200 rounded-md px-2.5 py-1.5">
                    <strong>⚠ รหัสที่ซ้ำกับของเดิม:</strong> {preview.summary.duplicateCodes.join(", ")}{preview.summary.update > 5 ? ` (และอีก ${preview.summary.update - 5})` : ""}
                  </div>
                )}
              </>
            )}
          </div>
        )}
      </div>
    </Modal>
  );
};

// =========================================================================
// SHARED — Status meta and formatting helpers
// =========================================================================
const PR_STATUS_META = {
  draft:     { label:"แบบร่าง",     color:"bg-slate-100 text-slate-700",   dot:"bg-slate-500" },
  pending:   { label:"รออนุมัติ",   color:"bg-amber-100 text-amber-700",   dot:"bg-amber-500" },
  approved:  { label:"อนุมัติแล้ว", color:"bg-emerald-100 text-emerald-700",dot:"bg-emerald-500" },
  rejected:  { label:"ถูกปฏิเสธ",   color:"bg-rose-100 text-rose-700",     dot:"bg-rose-500" },
  cancelled: { label:"ยกเลิก",      color:"bg-ink-100 text-ink-600",       dot:"bg-ink-400" },
  purchased: { label:"จัดซื้อแล้ว", color:"bg-indigo-100 text-indigo-700", dot:"bg-indigo-500" },
};
const PRStatusPill = ({ status }) => {
  const m = PR_STATUS_META[status] || PR_STATUS_META.draft;
  return (
    <span className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-[11px] font-medium ${m.color}`}>
      <span className={`w-1.5 h-1.5 rounded-full ${m.dot}`}/>{m.label}
    </span>
  );
};

// Format CE year → Buddhist year for display
const formatThaiDate = (yyyyMmDd) => {
  if (!yyyyMmDd) return "—";
  const m = String(yyyyMmDd).match(/^(\d{4})-(\d{2})-(\d{2})/);
  if (!m) return yyyyMmDd;
  const beYear = parseInt(m[1], 10) + 543;
  const months = ["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค."];
  return `${parseInt(m[3],10)} ${months[parseInt(m[2],10)-1]} ${beYear}`;
};
const fmtMoney = (n) => "฿" + Number(n||0).toLocaleString("th-TH", { minimumFractionDigits:2, maximumFractionDigits:2 });

// Find user display name + dept by id (best effort from users array)
const getUserDisplay = (uid, users) => {
  const u = (users || []).find(x => x.id === uid || x.api_user_id === uid || x.user_id === uid);
  if (!u) return { name: uid || "—", dept: "—", position: "" };
  return { name: u.full_name || u.email || uid, dept: u.department_name || "—", position: u.position_name || "" };
};

// =========================================================================
// PURCHASE REQUEST LIST PAGE
// =========================================================================
const PurchaseRequestListPage = ({ tenant, currentUser, currentRole, period, users, onCreate }) => {
  const toast = useToast();
  const [requests, setRequests] = useState([]);
  const [loading, setLoading] = useState(false);
  const [activeTab, setActiveTab] = useState("all"); // all | draft | pending | approved | rejected | cancelled | purchased
  const [orderingFilter, setOrderingFilter] = useState("__all__"); // __all__ | not_ordered | partial | fully_ordered | closed
  const [q, setQ] = useState("");
  const [detailFor, setDetailFor] = useState(null);
  // Header sort — default newest first. Click cycles desc → asc → reset.
  const [sortBy, setSortBy] = useState({ key: 'updated_at', dir: 'desc' });
  const toggleSort = (key) => setSortBy(prev => {
    if (prev.key !== key) return { key, dir: 'desc' };
    if (prev.dir === 'desc') return { key, dir: 'asc' };
    return { key: 'updated_at', dir: 'desc' };  // third click = reset to default
  });

  const reload = async () => {
    if (!tenant?.id || !window.apiClient) return;
    setLoading(true);
    try {
      const rows = await window.apiClient.prListRequests(tenant.id);
      setRequests(Array.isArray(rows) ? rows : []);
    } catch (e) {
      toast({ kind:"error", msg: e.message || "โหลดรายการ PR ไม่สำเร็จ" });
    } finally { setLoading(false); }
  };
  useEffect(() => { reload(); /* eslint-disable-next-line */ }, [tenant?.id]);

  // Filter by current period (month/year)
  const inPeriod = (pr) => {
    if (!pr.pr_date) return false;
    const [y, m] = pr.pr_date.split("-");
    return parseInt(y,10) === period.year && parseInt(m,10) === period.month;
  };
  const periodRequests = requests.filter(inPeriod);

  // KPI counts (current period only)
  const k = {
    total: periodRequests.length,
    pending: periodRequests.filter(r => r.status === "pending").length,
    approved: periodRequests.filter(r => r.status === "approved").length,
    purchased: periodRequests.filter(r => r.status === "purchased").length,
    rejected: periodRequests.filter(r => r.status === "rejected" || r.status === "cancelled").length,
    total_amount: periodRequests.filter(r => r.status !== "cancelled" && r.status !== "rejected")
      .reduce((s, r) => s + (Number(r.total_amount)||0), 0),
  };

  // Tab counts
  const tabCounts = {
    all: periodRequests.length,
    draft: periodRequests.filter(r => r.status === "draft").length,
    pending: periodRequests.filter(r => r.status === "pending").length,
    approved: periodRequests.filter(r => r.status === "approved").length,
    rejected: periodRequests.filter(r => r.status === "rejected").length,
    cancelled: periodRequests.filter(r => r.status === "cancelled").length,
    purchased: periodRequests.filter(r => r.status === "purchased").length,
  };

  const filtered = useMemo(() => {
    const ql = q.trim().toLowerCase();
    const rows = periodRequests.filter(r => {
      if (activeTab !== "all" && r.status !== activeTab) return false;
      if (orderingFilter !== "__all__" && (r.ordering_status || "not_ordered") !== orderingFilter) return false;
      if (!ql) return true;
      const reqName = getUserDisplay(r.requester_id, users).name.toLowerCase();
      const apprName = getUserDisplay(r.approver_id, users).name.toLowerCase();
      return (r.pr_number||"").toLowerCase().includes(ql)
        || reqName.includes(ql) || apprName.includes(ql)
        || (r.purpose||"").toLowerCase().includes(ql)
        || (r.line_item_names||"").toLowerCase().includes(ql)
        || (r.line_item_codes||"").toLowerCase().includes(ql);
    });
    // Sort by the active key (date fields compare lexicographically because they're ISO strings)
    return rows.slice().sort((a, b) => {
      const av = a[sortBy.key] || "";
      const bv = b[sortBy.key] || "";
      if (av < bv) return sortBy.dir === 'asc' ? -1 : 1;
      if (av > bv) return sortBy.dir === 'asc' ? 1 : -1;
      return 0;
    });
  }, [periodRequests, activeTab, orderingFilter, q, users, sortBy]);

  return (
    <div className="p-5 max-w-[1600px] mx-auto">
      {/* Header */}
      <div className="flex items-end justify-between mb-5 flex-wrap gap-3">
        <div>
          <div className="text-[11px] uppercase tracking-[.2em] text-ink-400 font-semibold">PURCHASE REQUEST · {`พ.ค. ${period.year + 543}`}</div>
          <h1 className="text-[26px] font-bold tracking-tight mt-1 text-ink-900">สถานะคำขอจัดซื้อ (Purchase Request)</h1>
          <p className="text-[13px] text-ink-500 mt-1">ติดตาม สร้าง อนุมัติ และจัดการคำขอจัดซื้อภายในองค์กร</p>
        </div>
        <div className="flex items-center gap-2">
          <Button variant="secondary" icon="download" onClick={()=>toast({kind:"info", msg:"ใช้เมนู Reports & Export สำหรับการส่งออกครบทุก field"})}>ส่งออก Excel</Button>
          <Button icon="plus" onClick={onCreate}>สร้างคำขอใหม่</Button>
        </div>
      </div>

      {/* KPI cards (6 cols) */}
      <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3 mb-5">
        <KpiCard icon="fileText" tone="indigo" label="PR ทั้งหมด" value={k.total} trend={`ในเดือน ${`พ.ค. ${period.year + 543}`}`}/>
        <KpiCard icon="clock" tone="amber" label="รออนุมัติ" value={k.pending} trend="ต้องดำเนินการ"/>
        <KpiCard icon="check" tone="emerald" label="อนุมัติแล้ว" value={k.approved} trend="พร้อมจัดซื้อ"/>
        <KpiCard icon="package" tone="indigo" label="จัดซื้อแล้ว" value={k.purchased} trend="เดือนนี้"/>
        <KpiCard icon="ban" tone="rose" label="ถูกปฏิเสธ / ยกเลิก" value={k.rejected} trend="เดือนนี้"/>
        <KpiCard icon="bar" tone="violet" label="มูลค่ารวม (THB)" value={fmtMoney(k.total_amount)} trend="มูลค่ารวมทั้งสิ้น"/>
      </div>

      {/* Status tabs */}
      <div className="flex items-center gap-1 mb-3 border-b border-ink-200 overflow-x-auto">
        {[
          ["all","ทั้งหมด"], ["draft","แบบร่าง"], ["pending","รออนุมัติ"],
          ["approved","อนุมัติแล้ว"], ["rejected","ถูกปฏิเสธ"], ["cancelled","ยกเลิก"], ["purchased","จัดซื้อแล้ว"]
        ].map(([key,label]) => (
          <button key={key} onClick={()=>setActiveTab(key)}
            className={`relative px-3 py-2 text-[12.5px] font-medium whitespace-nowrap
              ${activeTab===key ? "text-brand-700" : "text-ink-500 hover:text-ink-800"}`}>
            {label}
            <span className={`ml-1.5 px-1.5 py-0.5 rounded-md text-[10.5px] ${activeTab===key?"bg-brand-100 text-brand-700":"bg-ink-100 text-ink-500"}`}>{tabCounts[key]||0}</span>
            {activeTab===key && <span className="absolute bottom-0 left-0 right-0 h-0.5 bg-brand-500"/>}
          </button>
        ))}
      </div>

      {/* Filter row */}
      <div className="flex flex-wrap items-center gap-2 mb-3">
        <div className="relative flex-1 min-w-[260px] max-w-[400px]">
          <Icon name="search" size={13} className="absolute left-3 top-1/2 -translate-y-1/2 text-ink-400"/>
          <input value={q} onChange={e=>setQ(e.target.value)} placeholder="ค้นหา PR Number / ผู้ขอ / ผู้อนุมัติ / ชื่อสินค้า / รหัสสินค้า"
            className="w-full h-9 pl-9 pr-3 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus"/>
        </div>
        <select value={orderingFilter} onChange={e=>setOrderingFilter(e.target.value)}
          className="h-9 px-2.5 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus">
          <option value="__all__">Ordering: ทั้งหมด</option>
          <option value="not_ordered">ยังไม่สั่ง</option>
          <option value="partial">สั่งบางส่วน</option>
          <option value="fully_ordered">สั่งครบแล้ว</option>
          <option value="closed">ปิดยอด</option>
        </select>
        <div className="ml-auto text-[12px] text-ink-500">พบ <strong className="text-ink-800">{filtered.length}</strong> / {periodRequests.length} รายการ</div>
      </div>

      {/* Table */}
      <div className="rounded-2xl border border-ink-200 bg-white overflow-x-auto">
        <table className="w-full text-[12.5px] min-w-[1300px]">
          <thead className="bg-ink-50 text-ink-500 text-[11px] uppercase tracking-wider">
            <tr>
              {[
                { label:"PR Number" },
                { label:"วันที่สร้าง", key:"pr_date" },
                { label:"ผู้ขอ" },
                { label:"แผนกผู้ขอ" },
                { label:"ผู้อนุมัติ" },
                { label:"มูลค่ารวม" },
                { label:"กำหนดส่ง", key:"required_date" },
                { label:"ความสำคัญ" },
                { label:"สถานะ PR" },
                { label:"Ordering" },
                { label:"อัปเดตล่าสุด", key:"updated_at" },
                { label:"การกระทำ" },
              ].map(h => {
                const isActive = h.key && sortBy.key === h.key;
                const arrow = isActive ? (sortBy.dir === 'asc' ? "▲" : "▼") : "";
                return (
                  <th key={h.label} className={`text-left font-semibold px-3 py-2.5 border-b border-ink-200 whitespace-nowrap ${h.key ? "cursor-pointer hover:bg-ink-100 select-none" : ""}`}
                    onClick={() => h.key && toggleSort(h.key)}>
                    {h.label}
                    {h.key && <span className={`ml-1 text-[10px] ${isActive ? "text-brand-600 font-bold" : "text-ink-300"}`}>{arrow || "↕"}</span>}
                  </th>
                );
              })}
            </tr>
          </thead>
          <tbody>
            {loading && <tr><td colSpan={12} className="text-center py-10 text-ink-400">กำลังโหลด…</td></tr>}
            {!loading && filtered.length === 0 && <tr><td colSpan={12} className="text-center py-16 text-ink-400">ยังไม่มีคำขอจัดซื้อในเงื่อนไขนี้</td></tr>}
            {!loading && filtered.map(r => {
              const reqU = getUserDisplay(r.requester_id, users);
              const apprU = getUserDisplay(r.approver_id, users);
              return (
                <tr key={r.id} className="hover:bg-ink-50/60 border-b border-ink-100 last:border-0">
                  <td className="px-3 py-3">
                    <button onClick={()=>setDetailFor(r.id)} className="text-brand-700 hover:underline font-mono font-semibold">{r.pr_number}</button>
                    {r.purpose && <div className="text-[11px] text-ink-500 truncate-1 max-w-[200px]" title={r.purpose}>{r.purpose}</div>}
                  </td>
                  <td className="px-3 py-3 text-ink-700">{formatThaiDate(r.pr_date)}</td>
                  <td className="px-3 py-3">
                    <div className="flex items-center gap-2"><Avatar name={reqU.name} size={24}/>
                      <div className="min-w-0">
                        <div className="font-medium text-ink-800 truncate">{reqU.name}</div>
                        {reqU.position && <div className="text-[10.5px] text-ink-500 truncate">{reqU.position}</div>}
                      </div></div>
                  </td>
                  <td className="px-3 py-3 text-ink-700">{r.requester_dept_snapshot || reqU.dept || "—"}</td>
                  <td className="px-3 py-3">
                    {r.approver_id ? (
                      <div className="flex items-center gap-2"><Avatar name={apprU.name} size={24}/>
                        <div className="min-w-0">
                          <div className="font-medium text-ink-800 truncate">{apprU.name}</div>
                          {apprU.position && <div className="text-[10.5px] text-ink-500 truncate">{apprU.position}</div>}
                        </div></div>
                    ) : <span className="text-ink-400">—</span>}
                  </td>
                  <td className="px-3 py-3 font-mono text-ink-800 text-right">{fmtMoney(r.total_amount)}</td>
                  <td className="px-3 py-3 text-ink-700">{formatThaiDate(r.required_date)}</td>
                  <td className="px-3 py-3">
                    {r.priority === "urgent"
                      ? <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded-md bg-rose-50 text-rose-700 text-[11px] font-medium"><Icon name="warning" size={11}/>ด่วน</span>
                      : <span className="text-ink-500 text-[11px]">ปกติ</span>}
                  </td>
                  <td className="px-3 py-3"><PRStatusPill status={r.status}/></td>
                  <td className="px-3 py-3">
                    {(r.status === "approved" || r.status === "purchased")
                      ? <PRLineStatusPill status={r.ordering_status || "not_ordered"}/>
                      : <span className="text-ink-300 text-[11px]">—</span>}
                  </td>
                  <td className="px-3 py-3 font-mono text-ink-500 text-[11.5px]">{(r.updated_at||"").slice(0,16).replace("T"," ")}</td>
                  <td className="px-3 py-3">
                    <IconBtn icon="search" tip="ดูรายละเอียด" onClick={()=>setDetailFor(r.id)}/>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {detailFor && <PRDetailModal tenant={tenant} prId={detailFor} onClose={()=>setDetailFor(null)} onChanged={reload} users={users} currentUser={currentUser} currentRole={currentRole}/>}
    </div>
  );
};

// =========================================================================
// PR DETAIL MODAL — view full PR + audit + take actions
// =========================================================================
const PRDetailModal = ({ tenant, prId, onClose, onChanged, users, currentUser, currentRole }) => {
  const toast = useToast();
  const [pr, setPr] = useState(null);
  const [busy, setBusy] = useState(false);
  const [rejectOpen, setRejectOpen] = useState(false);
  const [cancelOpen, setCancelOpen] = useState(false);
  // Per-line ordering modals (Phase 5)
  const [updateLineFor, setUpdateLineFor] = useState(null);   // line object or null
  const [historyLineFor, setHistoryLineFor] = useState(null); // line object or null
  const [closeLineFor, setCloseLineFor] = useState(null);     // line object or null
  const canOrder = canManageOrdering(currentRole);

  const reload = async () => {
    try {
      const data = await window.apiClient.prGetRequest(tenant.id, prId);
      setPr(data);
    } catch (e) { toast({ kind:"error", msg: e.message }); }
  };
  useEffect(() => { reload(); /* eslint-disable-next-line */ }, [prId]);
  if (!pr) return null;

  const isRequester = pr.requester_id === currentUser?.id;
  const isApprover = pr.approver_id === currentUser?.id;
  const canApprove = isApprover && pr.status === "pending";
  const canCancel = isRequester && (pr.status === "draft" || pr.status === "pending" || pr.status === "rejected");
  // Ordering section visible once PR is approved (or already purchased)
  const showOrdering = pr.status === "approved" || pr.status === "purchased";

  const action = async (fn, msg) => {
    setBusy(true);
    try { await fn(); toast({ kind:"success", msg }); reload(); onChanged?.(); }
    catch (e) { toast({ kind:"error", msg: e.message }); }
    finally { setBusy(false); }
  };

  const reqU = getUserDisplay(pr.requester_id, users);
  const apprU = getUserDisplay(pr.approver_id, users);

  return (
    <Modal open onClose={onClose} title={pr.pr_number} subtitle={`${reqU.name} · ${pr.requester_dept_snapshot || reqU.dept}`} width={1200}
      footer={<div className="flex items-center gap-2 w-full">
        <Button variant="secondary" onClick={onClose}>ปิด</Button>
        <div className="ml-auto flex items-center gap-2">
          {canCancel && <Button variant="secondary" icon="x" onClick={()=>setCancelOpen(true)}>ยกเลิก PR</Button>}
          {canApprove && <Button variant="secondary" icon="ban" onClick={()=>setRejectOpen(true)}>ปฏิเสธ</Button>}
          {canApprove && <Button icon="check" disabled={busy} onClick={()=>action(()=>window.apiClient.prApproveRequest(tenant.id, prId, ""), "อนุมัติแล้ว")}>อนุมัติ</Button>}
        </div>
      </div>}>
      <div className="grid grid-cols-3 gap-4">
        {/* Header info */}
        <div className="col-span-2 space-y-3">
          <div className="flex items-center gap-3 pb-3 border-b border-ink-100 flex-wrap">
            <PRStatusPill status={pr.status}/>
            {pr.priority === "urgent" && <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded-md bg-rose-50 text-rose-700 text-[11px] font-medium"><Icon name="warning" size={11}/>ด่วน</span>}
            {pr.ordering_status && pr.ordering_status !== 'not_ordered' && (
              <span className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-[11px] font-medium ${PR_LINE_STATUS_META[pr.ordering_status]?.color || 'bg-ink-100'}`}
                    title="Ordering Status">
                <Icon name="cart" size={11}/>{PR_LINE_STATUS_META[pr.ordering_status]?.label}
              </span>
            )}
            <div className="ml-auto text-[12px] text-ink-500">สร้างเมื่อ {formatThaiDate(pr.pr_date)}</div>
          </div>
          <div className="grid grid-cols-2 gap-3 text-[12px]">
            <Kv label="ผู้ขอ" value={`${reqU.name}${reqU.position ? " · " + reqU.position : ""}`}/>
            <Kv label="ผู้อนุมัติ" value={pr.approver_id ? `${apprU.name}${apprU.position ? " · " + apprU.position : ""}` : "—"}/>
            <Kv label="กำหนดวันที่ต้องการ" value={formatThaiDate(pr.required_date)}/>
            <Kv label="Budget / Cost Center" value={pr.budget_code || "—"}/>
            <Kv label="Project Code" value={pr.project_code || "—"}/>
            <Kv label="สกุลเงิน" value={pr.currency || "THB"}/>
          </div>
          {pr.purpose && (
            <div className="pt-2"><div className="text-[11px] text-ink-500 mb-1">วัตถุประสงค์</div><div className="text-[12.5px] text-ink-800 whitespace-pre-wrap">{pr.purpose}</div></div>
          )}
          {pr.notes && (
            <div className="pt-2"><div className="text-[11px] text-ink-500 mb-1">หมายเหตุ</div><div className="text-[12.5px] text-ink-700 whitespace-pre-wrap">{pr.notes}</div></div>
          )}
          {pr.rejected_reason && (
            <div className="px-3 py-2 rounded-md bg-rose-50 border border-rose-200 text-rose-700 text-[12px]">
              <div className="font-semibold mb-0.5">เหตุผลที่ถูกปฏิเสธ:</div>{pr.rejected_reason}
            </div>
          )}

          {/* Line items */}
          <div className="pt-3">
            <div className="text-[12px] font-semibold text-ink-800 mb-1.5">รายการสินค้า ({pr.line_items.length})</div>
            <div className="rounded-lg border border-ink-200 overflow-hidden">
              <table className="w-full text-[11.5px]">
                <thead className="bg-ink-50 text-ink-500 text-[10.5px] uppercase">
                  <tr>
                    <th className="text-left px-2 py-1.5">รหัส</th><th className="text-left px-2 py-1.5">ชื่อสินค้า</th>
                    <th className="text-right px-2 py-1.5">จำนวน</th><th className="text-left px-2 py-1.5">หน่วย</th>
                    <th className="text-right px-2 py-1.5">ราคา/หน่วย</th><th className="text-right px-2 py-1.5">รวม</th>
                  </tr>
                </thead>
                <tbody>
                  {pr.line_items.map(li => (
                    <tr key={li.id} className="border-t border-ink-100">
                      <td className="px-2 py-1.5 font-mono">{li.item_code || "—"}</td>
                      <td className="px-2 py-1.5"><div className="font-medium">{li.item_name}</div>{li.description && <div className="text-[10.5px] text-ink-500">{li.description}</div>}</td>
                      <td className="px-2 py-1.5 text-right font-mono">{Number(li.quantity).toLocaleString()}</td>
                      <td className="px-2 py-1.5">{li.unit || "—"}</td>
                      <td className="px-2 py-1.5 text-right font-mono">{fmtMoney(li.unit_price)}</td>
                      <td className="px-2 py-1.5 text-right font-mono font-semibold">{fmtMoney(li.line_total)}</td>
                    </tr>
                  ))}
                </tbody>
                <tfoot className="bg-ink-50/50 text-[11.5px]">
                  <tr className="border-t border-ink-200"><td colSpan={5} className="px-2 py-1.5 text-right font-semibold">มูลค่ารวม</td><td className="px-2 py-1.5 text-right font-mono font-bold text-brand-700">{fmtMoney(pr.total_amount)}</td></tr>
                </tfoot>
              </table>
            </div>
          </div>

          {/* Attachments — always show, even when empty */}
          <div className="pt-3">
            <div className="text-[12px] font-semibold text-ink-800 mb-1.5 flex items-center gap-1.5">
              <Icon name="paperclip" size={13} className="text-ink-500"/>
              เอกสารแนบ ({pr.attachments.length})
            </div>
            <AttachmentList tenant={tenant} prId={prId} attachments={pr.attachments}/>
          </div>
        </div>

        {/* Audit log sidebar */}
        <div className="col-span-1">
          <div className="text-[11px] uppercase tracking-wider text-ink-500 font-semibold mb-2">ประวัติการดำเนินการ</div>
          <div className="space-y-2.5 max-h-[500px] overflow-y-auto pr-1">
            {pr.audit_log.map(a => (
              <div key={a.id} className="text-[11.5px] pl-3 border-l-2 border-ink-200">
                <div className="font-medium text-ink-800">{a.action}</div>
                {a.details && <div className="text-ink-600 mt-0.5">{a.details}</div>}
                <div className="text-[10.5px] text-ink-400 mt-0.5 font-mono">{(a.performed_at||"").slice(0,16).replace("T"," ")}</div>
              </div>
            ))}
          </div>
        </div>
      </div>

      {/* Ordering Status by PR Line — full-width row below the main grid for breathing room */}
      {showOrdering && (
        <div className="mt-4">
          <OrderingByLineSection
            pr={pr}
            canOrder={canOrder}
            onUpdate={(line)=>setUpdateLineFor(line)}
            onClose={(line)=>setCloseLineFor(line)}
            onHistory={(line)=>setHistoryLineFor(line)}/>
        </div>
      )}

      {/* Reject modal */}
      {rejectOpen && (
        <ReasonModal open onClose={()=>setRejectOpen(false)} title="ปฏิเสธคำขอจัดซื้อ" subtitle={pr.pr_number}
          placeholder="โปรดระบุเหตุผลที่ปฏิเสธ จะถูกแจ้งกลับไปยังผู้ขอและบันทึก Audit Log"
          confirmLabel="ยืนยันการปฏิเสธ"
          onConfirm={(reason) => action(() => window.apiClient.prRejectRequest(tenant.id, prId, reason).then(()=>setRejectOpen(false)), "ปฏิเสธคำขอแล้ว")}/>
      )}
      {/* Cancel modal */}
      {cancelOpen && (
        <ReasonModal open onClose={()=>setCancelOpen(false)} title="ยกเลิกคำขอจัดซื้อ" subtitle={pr.pr_number}
          placeholder="ระบุเหตุผลในการยกเลิก (optional)"
          confirmLabel="ยืนยันยกเลิก"
          onConfirm={(reason) => action(() => window.apiClient.prCancelRequest(tenant.id, prId, reason).then(()=>{ setCancelOpen(false); onClose(); }), "ยกเลิกคำขอแล้ว")}/>
      )}
      {/* Per-line ordering modals (Phase 5) */}
      {updateLineFor && (
        <UpdateOrderModal tenant={tenant} prId={prId} pr={pr} line={updateLineFor}
          onClose={()=>setUpdateLineFor(null)}
          onSaved={()=>{ setUpdateLineFor(null); reload(); onChanged?.(); }}/>
      )}
      {historyLineFor && (
        <OrderHistoryModal tenant={tenant} prId={prId} line={historyLineFor}
          onClose={()=>setHistoryLineFor(null)}
          onChanged={()=>{ reload(); onChanged?.(); }}
          currentUser={currentUser} currentRole={currentRole} users={users}/>
      )}
      {closeLineFor && (
        <CloseLineModal tenant={tenant} prId={prId} line={closeLineFor}
          onClose={()=>setCloseLineFor(null)}
          onSaved={()=>{ setCloseLineFor(null); reload(); onChanged?.(); }}/>
      )}
    </Modal>
  );
};
const Kv = ({ label, value }) => (
  <div><div className="text-[10.5px] uppercase tracking-wider text-ink-500 font-semibold">{label}</div><div className="text-[12.5px] text-ink-800 mt-0.5">{value}</div></div>
);

// =========================================================================
// PR LINE ORDERING — Phase 5 components
// =========================================================================

// Permission helper — exposed by workspace.jsx; fallback for safety.
const canManageOrdering = (role) => typeof window !== "undefined" && window.canManageOrdering
  ? window.canManageOrdering(role)
  : (role === 'admin' || role === 'procurement' || role === 'super_admin');

// Round to 6 decimal places to dodge JS floating-point noise (e.g. 5 - 3.7 = 1.299999998).
// Use anywhere we compute remaining quantity for display or validation.
const roundQty = (n) => Math.round((Number(n) || 0) * 1e6) / 1e6;
// Match-with-tolerance — qty <= remaining is true if within an epsilon of 6 decimal places.
const lteWithEpsilon = (a, b) => (Number(a) || 0) <= (Number(b) || 0) + 1e-6;

const PR_LINE_STATUS_META = {
  not_ordered:    { label:"ยังไม่สั่ง",      color:"bg-slate-100 text-slate-600", dot:"bg-slate-400" },
  partial:        { label:"สั่งบางส่วน",     color:"bg-amber-100 text-amber-700", dot:"bg-amber-500" },
  fully_ordered:  { label:"สั่งครบแล้ว",     color:"bg-emerald-100 text-emerald-700", dot:"bg-emerald-500" },
  closed:         { label:"ปิดยอด",         color:"bg-ink-200 text-ink-700",    dot:"bg-ink-500" },
};
const PRLineStatusPill = ({ status }) => {
  const m = PR_LINE_STATUS_META[status] || PR_LINE_STATUS_META.not_ordered;
  return (
    <span className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-[11px] font-medium ${m.color}`}>
      <span className={`w-1.5 h-1.5 rounded-full ${m.dot}`}/>{m.label}
    </span>
  );
};

// Inline section under "รายการสินค้า" — shows requested / ordered / remaining per line
const OrderingByLineSection = ({ pr, canOrder, onUpdate, onClose, onHistory }) => {
  // Distinct PO numbers per line, from active updates only
  const poByLine = {};
  let lastDate = null;
  const datesByLine = {};
  (pr.line_order_updates || []).filter(u => u.status === 'active').forEach(u => {
    if (!poByLine[u.pr_line_id]) poByLine[u.pr_line_id] = new Set();
    poByLine[u.pr_line_id].add(u.external_po_number);
    if (!datesByLine[u.pr_line_id] || u.ordered_date > datesByLine[u.pr_line_id]) {
      datesByLine[u.pr_line_id] = u.ordered_date;
    }
    if (!lastDate || u.ordered_date > lastDate) lastDate = u.ordered_date;
  });

  return (
    <div className="pt-3">
      <div className="text-[12px] font-semibold text-ink-800 mb-1.5 flex items-center gap-1.5">
        <Icon name="cart" size={13} className="text-ink-500"/>
        Ordering Status by PR Line
      </div>
      <div className="rounded-lg border border-ink-200 overflow-x-auto">
        <table className="w-full text-[11.5px] min-w-[800px]">
          <thead className="bg-ink-50 text-ink-500 text-[10.5px] uppercase">
            <tr>
              <th className="text-left px-2 py-1.5">รหัส / ชื่อสินค้า</th>
              <th className="text-right px-2 py-1.5">Requested</th>
              <th className="text-right px-2 py-1.5">Ordered</th>
              <th className="text-right px-2 py-1.5">Remaining</th>
              <th className="text-left px-2 py-1.5">Status</th>
              <th className="text-left px-2 py-1.5">PO Number(s)</th>
              <th className="text-left px-2 py-1.5">Last Ordered</th>
              <th className="text-right px-2 py-1.5">Action</th>
            </tr>
          </thead>
          <tbody>
            {pr.line_items.map(line => {
              const requested = Number(line.quantity) || 0;
              const ordered = Number(line.ordered_quantity) || 0;
              const remaining = Math.max(0, roundQty(requested - ordered - (Number(line.closed_quantity) || 0)));
              const status = line.line_status || 'not_ordered';
              const pos = poByLine[line.id] ? Array.from(poByLine[line.id]) : [];
              const canUpdate = canOrder && remaining > 0 && status !== 'closed' && status !== 'fully_ordered';
              const canCloseLine = canOrder && remaining > 0 && status !== 'closed';
              return (
                <tr key={line.id} className="border-t border-ink-100 align-top">
                  <td className="px-2 py-2">
                    <div className="font-mono text-[10.5px] text-ink-500">{line.item_code || '—'}</div>
                    <div className="text-[12px] font-medium text-ink-800">{line.item_name}</div>
                  </td>
                  <td className="px-2 py-2 text-right font-mono">{requested.toLocaleString()} {line.unit||''}</td>
                  <td className="px-2 py-2 text-right font-mono font-semibold text-brand-700">{ordered.toLocaleString()}</td>
                  <td className={`px-2 py-2 text-right font-mono ${remaining>0?"text-amber-700":"text-ink-400"}`}>{remaining.toLocaleString()}</td>
                  <td className="px-2 py-2"><PRLineStatusPill status={status}/></td>
                  <td className="px-2 py-2">
                    {pos.length === 0 ? <span className="text-ink-400">—</span> :
                      <div className="flex flex-wrap gap-1">
                        {pos.map(po => <span key={po} className="font-mono text-[10.5px] px-1.5 py-0.5 rounded bg-indigo-50 text-indigo-700">{po}</span>)}
                      </div>}
                  </td>
                  <td className="px-2 py-2 text-ink-700">{datesByLine[line.id] ? formatThaiDate(datesByLine[line.id]) : '—'}</td>
                  <td className="px-2 py-2 text-right">
                    <div className="flex items-center gap-1 justify-end flex-wrap">
                      {canUpdate && <button onClick={()=>onUpdate(line)}
                        className="px-2 py-1 rounded-md bg-brand-500 hover:bg-brand-600 text-white text-[10.5px] font-medium">
                        <Icon name="plus" size={10} className="inline mb-0.5"/> อัปเดต
                      </button>}
                      {canCloseLine && <button onClick={()=>onClose(line)}
                        className="px-2 py-1 rounded-md bg-ink-100 hover:bg-ink-200 text-ink-700 text-[10.5px] font-medium">
                        ปิดยอด
                      </button>}
                      <button onClick={()=>onHistory(line)}
                        className="px-2 py-1 rounded-md border border-ink-200 hover:bg-ink-50 text-ink-700 text-[10.5px] font-medium">
                        <Icon name="history" size={10} className="inline mb-0.5"/> History
                      </button>
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
      {!canOrder && (
        <div className="text-[11px] text-ink-400 italic mt-1.5">มุมมองแบบอ่านอย่างเดียว · เฉพาะ Procurement / Admin เท่านั้นที่อัปเดตได้</div>
      )}
    </div>
  );
};

// Update Ordering Information modal — entry point for adding a new "we ordered N units" record
const UpdateOrderModal = ({ tenant, prId, pr, line, onClose, onSaved }) => {
  const toast = useToast();
  const requested = Number(line.quantity) || 0;
  const alreadyOrdered = Number(line.ordered_quantity) || 0;
  const remaining = Math.max(0, roundQty(requested - alreadyOrdered));
  const todayISO = new Date().toISOString().slice(0, 10);
  const [po, setPo] = useState("");
  const [qty, setQty] = useState("");
  const [orderedDate, setOrderedDate] = useState(todayISO);
  const [comment, setComment] = useState("");
  const [busy, setBusy] = useState(false);

  const qtyNum = Number(qty);
  const validQty = qtyNum > 0 && lteWithEpsilon(qtyNum, remaining);
  const valid = po.trim() && validQty && orderedDate;

  const submit = async () => {
    if (!valid) return;
    setBusy(true);
    try {
      await window.apiClient.prAddLineOrderUpdate(tenant.id, prId, line.id, {
        external_po_number: po.trim(),
        ordered_quantity: qtyNum,
        ordered_date: orderedDate,
        comment: comment.trim() || null,
      });
      toast({ kind:"success", msg:`บันทึก Order ${qtyNum} ${line.unit||''} · PO: ${po.trim()}` });
      onSaved();
    } catch (e) {
      toast({ kind:"error", msg: e.message || "บันทึกไม่สำเร็จ" });
    } finally { setBusy(false); }
  };

  return (
    <Modal open onClose={onClose} title="Update Ordering Information" subtitle={`${pr.pr_number} · ${line.item_name}`} width={560}
      footer={<>
        <Button variant="secondary" onClick={onClose} disabled={busy}>ยกเลิก</Button>
        <Button icon="check" disabled={!valid || busy} onClick={submit}>{busy?"กำลังบันทึก...":"บันทึก Update"}</Button>
      </>}>
      <div className="space-y-3">
        {/* Read-only summary of current line state */}
        <div className="grid grid-cols-4 gap-2">
          <div className="px-2.5 py-2 rounded-md bg-ink-50 border border-ink-200"><div className="text-[10px] uppercase text-ink-500">Requested</div><div className="text-[15px] font-bold text-ink-800 font-mono">{requested.toLocaleString()} {line.unit||''}</div></div>
          <div className="px-2.5 py-2 rounded-md bg-brand-50 border border-brand-200"><div className="text-[10px] uppercase text-brand-700">Already Ordered</div><div className="text-[15px] font-bold text-brand-700 font-mono">{alreadyOrdered.toLocaleString()}</div></div>
          <div className="px-2.5 py-2 rounded-md bg-amber-50 border border-amber-200"><div className="text-[10px] uppercase text-amber-700">Remaining</div><div className="text-[15px] font-bold text-amber-700 font-mono">{remaining.toLocaleString()}</div></div>
          <div className="px-2.5 py-2 rounded-md bg-white border border-ink-200"><div className="text-[10px] uppercase text-ink-500">Status</div><div className="mt-0.5"><PRLineStatusPill status={line.line_status||'not_ordered'}/></div></div>
        </div>

        <Field label="External PO Number" required hint="เลขที่ PO ที่เปิดในระบบ ERP">
          <Input value={po} onChange={e=>setPo(e.target.value.toUpperCase())} placeholder="เช่น PO-ERP-001" className="font-mono uppercase" autoFocus/>
        </Field>
        <div className="grid grid-cols-2 gap-3">
          <Field label="Ordered Quantity" required hint={`สั่งได้ไม่เกิน ${remaining} ${line.unit||''}`} error={qty!=="" && !validQty ? `เกินจำนวนคงเหลือ (${remaining})` : ""}>
            <Input type="number" min="0" step="1" max={remaining} value={qty}
              onChange={e=>setQty(e.target.value.replace(/^0+(?=\d)/,""))} placeholder="0" className="font-mono text-right"/>
          </Field>
          <Field label="Ordered Date" required>
            <ThaiDateInput value={orderedDate} onChange={setOrderedDate}/>
          </Field>
        </div>
        <Field label="Comment / Remark" hint="หมายเหตุเพิ่มเติม (optional)">
          <textarea value={comment} onChange={e=>setComment(e.target.value)} rows={2}
            placeholder="เช่น เลขที่เอกสาร, หมายเหตุการสั่งซื้อ..."
            className="w-full px-3 py-2 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus"/>
        </Field>
      </div>
    </Modal>
  );
};

// Close Remaining modal — requires reason, sets line to closed
const CloseLineModal = ({ tenant, prId, line, onClose, onSaved }) => {
  const toast = useToast();
  const requested = Number(line.quantity) || 0;
  const ordered = Number(line.ordered_quantity) || 0;
  const remaining = Math.max(0, roundQty(requested - ordered));
  const [reason, setReason] = useState("");
  const [busy, setBusy] = useState(false);
  const valid = reason.trim().length > 0;
  const submit = async () => {
    if (!valid) return;
    setBusy(true);
    try {
      await window.apiClient.prCloseLine(tenant.id, prId, line.id, reason.trim());
      toast({ kind:"success", msg:`ปิดยอดคงเหลือ ${remaining} ${line.unit||''}` });
      onSaved();
    } catch (e) {
      toast({ kind:"error", msg: e.message || "ปิดยอดไม่สำเร็จ" });
    } finally { setBusy(false); }
  };
  return (
    <Modal open onClose={onClose} title="ปิดยอดคงเหลือ (Close Remaining)" subtitle={line.item_name} width={500}
      footer={<>
        <Button variant="secondary" onClick={onClose} disabled={busy}>ยกเลิก</Button>
        <Button icon="ban" disabled={!valid || busy} onClick={submit}>{busy?"กำลังปิดยอด...":"ยืนยันปิดยอด"}</Button>
      </>}>
      <div className="space-y-3">
        <div className="px-3 py-2 rounded-md bg-amber-50 border border-amber-200 text-amber-800 text-[11.5px] flex items-start gap-2">
          <Icon name="warning" size={13} className="mt-0.5 shrink-0"/>
          <span>การปิดยอดจะทำให้ <strong>ไม่สามารถสั่งซื้อเพิ่ม</strong> จากรายการนี้ได้อีก · จำเป็นต้องระบุเหตุผล</span>
        </div>
        <div className="grid grid-cols-3 gap-2 text-[12px]">
          <Kv label="Requested" value={<span className="font-mono">{requested.toLocaleString()} {line.unit||''}</span>}/>
          <Kv label="Already Ordered" value={<span className="font-mono">{ordered.toLocaleString()}</span>}/>
          <Kv label="Remaining (จะถูกปิด)" value={<span className="font-mono font-bold text-rose-600">{remaining.toLocaleString()}</span>}/>
        </div>
        <Field label="เหตุผลในการปิดยอด" required>
          <textarea value={reason} onChange={e=>setReason(e.target.value)} rows={3} autoFocus
            placeholder="เช่น ผู้ขอแจ้งไม่ต้องการของส่วนที่เหลือแล้ว / สินค้าเลิกผลิต"
            className="w-full px-3 py-2 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus"/>
        </Field>
      </div>
    </Modal>
  );
};

// History modal per line — list updates (active + voided), allow voiding
const OrderHistoryModal = ({ tenant, prId, line, onClose, onChanged, currentUser, currentRole, users }) => {
  const toast = useToast();
  const [list, setList] = useState(null);
  const [voidFor, setVoidFor] = useState(null); // update record

  const reload = async () => {
    try {
      const rows = await window.apiClient.prListLineOrderUpdates(tenant.id, prId, line.id);
      setList(Array.isArray(rows) ? rows : []);
    } catch (e) { toast({ kind:"error", msg: e.message }); }
  };
  useEffect(() => { reload(); /* eslint-disable-next-line */ }, [line.id]);

  const isAdmin = currentRole === 'admin' || currentRole === 'super_admin';
  const lookupName = (uid) => {
    if (uid === 'system') return 'ระบบ (backfill)';
    const u = (users || []).find(x => x.id === uid || x.api_user_id === uid);
    return u?.full_name || uid || '—';
  };

  return (
    <Modal open onClose={onClose} title="Ordering History" subtitle={line.item_name} width={760}>
      {!list && <div className="text-center py-8 text-ink-400">กำลังโหลด...</div>}
      {list && list.length === 0 && (
        <div className="text-center py-8 text-ink-400">ยังไม่มี Order Update สำหรับรายการนี้</div>
      )}
      {list && list.length > 0 && (
        <div className="space-y-2">
          {list.map(u => {
            const isVoided = u.status === 'voided';
            const canVoid = !isVoided && (u.created_by === currentUser?.id || isAdmin);
            return (
              <div key={u.id} className={`rounded-lg border p-3 ${isVoided ? "border-ink-200 bg-ink-50/40 opacity-70" : "border-ink-200 bg-white"}`}>
                <div className="flex items-center gap-2 flex-wrap">
                  {isVoided && <span className="px-1.5 py-0.5 rounded-md bg-rose-100 text-rose-700 text-[10.5px] font-semibold uppercase">VOIDED</span>}
                  <span className="font-mono text-[12px] font-bold text-brand-700">{u.external_po_number}</span>
                  <span className="text-ink-400">·</span>
                  <span className="font-mono text-[12px]">{Number(u.ordered_quantity).toLocaleString()} {line.unit||''}</span>
                  <span className="text-ink-400">·</span>
                  <span className="text-[11.5px] text-ink-700">{formatThaiDate(u.ordered_date)}</span>
                  {canVoid && (
                    <button onClick={()=>setVoidFor(u)}
                      className="ml-auto px-2 py-1 rounded-md text-[10.5px] font-medium text-rose-600 hover:bg-rose-50 border border-rose-200">
                      Void
                    </button>
                  )}
                </div>
                {u.comment && <div className="text-[11.5px] text-ink-700 mt-1.5">{u.comment}</div>}
                <div className="text-[10.5px] text-ink-500 mt-1 font-mono">
                  by {lookupName(u.created_by)} · {(u.created_at||'').slice(0,16).replace('T',' ')}
                </div>
                {isVoided && (
                  <div className="mt-2 px-2 py-1.5 rounded bg-rose-50 border border-rose-200 text-[11px] text-rose-700">
                    <strong>เหตุผล Void:</strong> {u.voided_reason} · <span className="text-rose-600">by {lookupName(u.voided_by)}</span> · {(u.voided_at||'').slice(0,16).replace('T',' ')}
                  </div>
                )}
              </div>
            );
          })}
        </div>
      )}

      {voidFor && (
        <ReasonModal open onClose={()=>setVoidFor(null)} title="Void Update Record" subtitle={`PO ${voidFor.external_po_number} · ${Number(voidFor.ordered_quantity)} ${line.unit||''}`}
          placeholder="โปรดระบุเหตุผลในการ Void update นี้ — Ordered Quantity จะถูกคำนวณใหม่"
          confirmLabel="ยืนยัน Void"
          onConfirm={async (reason) => {
            try {
              await window.apiClient.prVoidLineOrderUpdate(tenant.id, prId, line.id, voidFor.id, reason);
              toast({ kind:"success", msg:"Void update record แล้ว" });
              setVoidFor(null);
              await reload();
              onChanged?.();
            } catch (e) {
              toast({ kind:"error", msg: e.message });
            }
          }}/>
      )}
    </Modal>
  );
};

// Detect if attachment is a previewable image
const isImageAttachment = (att) =>
  /^image\//i.test(att.content_type || "") ||
  /\.(jpg|jpeg|png|gif|webp|bmp|svg)$/i.test(att.filename || "");

// Lazy-loaded image thumbnail (fetches Blob via JWT, builds object URL)
const ImageThumb = ({ tenantId, prId, att }) => {
  const [src, setSrc] = useState(null);
  const [err, setErr] = useState(false);
  useEffect(() => {
    let mounted = true;
    let revokeUrl = null;
    window.apiClient.prDownloadAttachmentBlob(tenantId, prId, att.id)
      .then(blob => {
        if (!mounted) return;
        revokeUrl = URL.createObjectURL(blob);
        setSrc(revokeUrl);
      })
      .catch(() => mounted && setErr(true));
    return () => {
      mounted = false;
      if (revokeUrl) URL.revokeObjectURL(revokeUrl);
    };
  }, [tenantId, prId, att.id]);
  if (err) return <div className="w-full h-24 bg-rose-50 rounded flex items-center justify-center text-rose-500 text-[10.5px]">โหลดไม่ได้</div>;
  if (!src) return <div className="w-full h-24 bg-ink-100 animate-pulse rounded"/>;
  return <img src={src} alt={att.filename} className="w-full h-24 object-cover rounded"/>;
};

// Grid list of attachments with image previews + click to open lightbox / download
const AttachmentList = ({ tenant, prId, attachments }) => {
  const [previewing, setPreviewing] = useState(null); // { url, filename, isImage }

  if (!attachments || attachments.length === 0) {
    return <div className="text-[11.5px] text-ink-400 italic px-3 py-3 rounded-md border border-dashed border-ink-200 text-center">— ไม่มีเอกสารแนบ —</div>;
  }

  const openAttachment = async (att) => {
    try {
      const blob = await window.apiClient.prDownloadAttachmentBlob(tenant.id, prId, att.id);
      const url = URL.createObjectURL(blob);
      if (isImageAttachment(att)) {
        setPreviewing({ url, filename: att.filename, isImage: true });
      } else {
        // Non-image → trigger download to user's machine
        const a = document.createElement("a");
        a.href = url; a.download = att.filename; a.click();
        setTimeout(() => URL.revokeObjectURL(url), 2000);
      }
    } catch (e) {
      alert("เปิดไฟล์ไม่สำเร็จ: " + (e.message || ""));
    }
  };

  return (
    <>
      <div className="grid grid-cols-2 md:grid-cols-3 gap-2">
        {attachments.map(att => {
          const isImg = isImageAttachment(att);
          return (
            <button key={att.id} onClick={()=>openAttachment(att)} type="button"
              className="text-left rounded-lg border border-ink-200 bg-white hover:bg-ink-50 hover:border-brand-400 transition p-2 overflow-hidden">
              {isImg
                ? <ImageThumb tenantId={tenant.id} prId={prId} att={att}/>
                : <div className="w-full h-24 bg-ink-50 rounded flex items-center justify-center"><Icon name="fileText" size={28} className="text-ink-400"/></div>
              }
              <div className="mt-1.5 text-[11.5px] font-medium text-ink-800 truncate" title={att.filename}>{att.filename}</div>
              <div className="text-[10.5px] text-ink-500 font-mono flex items-center gap-1.5 mt-0.5">
                <span>{((att.file_size||0)/1024).toFixed(1)} KB</span>
                <span>·</span>
                <span className="text-brand-600">{isImg ? "ดูภาพ" : "ดาวน์โหลด"}</span>
              </div>
            </button>
          );
        })}
      </div>
      {previewing && (
        <ImageLightbox url={previewing.url} filename={previewing.filename}
          onClose={()=>{ URL.revokeObjectURL(previewing.url); setPreviewing(null); }}/>
      )}
    </>
  );
};

// Fullscreen image preview — click outside to close
const ImageLightbox = ({ url, filename, onClose }) => {
  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [onClose]);
  return (
    <div onClick={onClose}
      style={{ position:"fixed", inset:0, background:"rgba(0,0,0,0.85)", zIndex:200, display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", padding:24 }}>
      <div className="absolute top-3 right-4 flex items-center gap-2">
        <a href={url} download={filename} onClick={e=>e.stopPropagation()}
          className="px-3 h-8 inline-flex items-center gap-1.5 rounded-md bg-white/90 hover:bg-white text-ink-800 text-[12px] font-medium">
          <Icon name="download" size={13}/>ดาวน์โหลด
        </a>
        <button onClick={onClose} className="w-8 h-8 rounded-md bg-white/90 hover:bg-white text-ink-800 flex items-center justify-center">
          <Icon name="x" size={14}/>
        </button>
      </div>
      <img src={url} alt={filename} onClick={e=>e.stopPropagation()}
        className="max-w-[92vw] max-h-[85vh] object-contain rounded-lg shadow-2xl"/>
      <div className="mt-3 text-white text-[12px] font-medium">{filename}</div>
    </div>
  );
};

// =========================================================================
// CREATE PR — 5-step wizard
// =========================================================================
const CreatePRPage = ({ tenant, currentUser, users, positions, departments, onDone, onCancel }) => {
  const toast = useToast();
  const [step, setStep] = useState(1);
  const [items, setItems] = useState([]); // master items for picker
  const [data, setData] = useState({
    pr_number_preview: "PR-2569-XXXXX",  // placeholder until allocated
    pr_date: new Date().toISOString().slice(0,10),
    required_date: "",
    purpose: "",
    budget_code: "",
    project_code: "",
    currency: "THB",
    priority: "normal",
    notes: "",
    line_items: [],
    attachments: [],     // local File objects: { _local: true, file, _id }
    approver_id: "",
  });
  const [draftId, setDraftId] = useState(null);   // becomes set once a draft is saved
  const [busy, setBusy] = useState(false);

  // Load item master once for picker
  useEffect(() => {
    if (!tenant?.id) return;
    window.apiClient.prListItems(tenant.id)
      .then(rows => setItems((rows || []).filter(r => r.status === "active")))
      .catch(() => {});
  }, [tenant?.id]);

  // Derived: requester info
  const myPosId = currentUser?.positions?.[0];
  const myPos = positions?.find(p => p.id === myPosId);
  const myDept = departments?.find(d => d.id === myPos?.department_id);
  const requesterDept = myDept?.name || "";
  const requesterEmpCode = currentUser?.employee_code || "";

  // Totals
  const subtotal = data.line_items.reduce((s, l) => s + (Number(l.quantity)||0) * (Number(l.unit_price)||0), 0);
  // VAT removed from PR module per requirement — total = subtotal directly
  const vatRate = 0;
  const vat = 0;
  const total = subtotal;

  const updateLine = (idx, patch) => {
    setData(d => ({ ...d, line_items: d.line_items.map((l, i) => i === idx ? { ...l, ...patch } : l) }));
  };
  const addLine = (preset) => {
    setData(d => ({ ...d, line_items: [...d.line_items, preset || { item_code:"", item_name:"", quantity:1, unit_price:0, unit:"", description:"", category:"", supplier_name:"" }] }));
  };
  const removeLine = (idx) => setData(d => ({ ...d, line_items: d.line_items.filter((_, i) => i !== idx) }));

  const MAX_ATTACHMENT_SIZE = 10 * 1024 * 1024;  // 10 MB per file
  const MAX_ATTACHMENT_COUNT = 3;                 // max 3 files per PR
  const addFiles = (fileList) => {
    const incoming = Array.from(fileList || []);
    if (incoming.length === 0) return;

    // 1) Reject oversized files (and tell the user which ones)
    const oversize = incoming.filter(f => f.size > MAX_ATTACHMENT_SIZE);
    const sized = incoming.filter(f => f.size <= MAX_ATTACHMENT_SIZE);
    if (oversize.length > 0) {
      const names = oversize.map(f => `${f.name} (${(f.size/1024/1024).toFixed(1)}MB)`).join(", ");
      toast({ kind:"error", msg:`ไฟล์เกิน 10MB ถูกข้าม: ${names}` });
    }
    if (sized.length === 0) return;

    // 2) Cap total attachments at MAX_ATTACHMENT_COUNT
    const remaining = MAX_ATTACHMENT_COUNT - data.attachments.length;
    if (remaining <= 0) {
      toast({ kind:"error", msg:`อัปโหลดได้สูงสุด ${MAX_ATTACHMENT_COUNT} ไฟล์ — กรุณาลบไฟล์เดิมก่อนเพิ่มใหม่` });
      return;
    }
    let toAdd = sized;
    if (sized.length > remaining) {
      toast({ kind:"warning", msg:`เพิ่มได้อีกแค่ ${remaining} ไฟล์ จาก ${sized.length} ที่เลือก — ส่วนเกินถูกข้าม` });
      toAdd = sized.slice(0, remaining);
    }
    const arr = toAdd.map(f => ({ _local:true, file:f, _id:"loc-"+Math.random().toString(36).slice(2,8), filename:f.name, size:f.size }));
    setData(d => ({ ...d, attachments: [...d.attachments, ...arr] }));
  };
  const removeAttachment = (id) => setData(d => ({ ...d, attachments: d.attachments.filter(a => a._id !== id && a.id !== id) }));

  // Validation per step
  const stepValid = {
    1: !!data.purpose.trim() && !!data.required_date,
    2: data.line_items.length > 0 && data.line_items.every(l => l.item_master_id && (l.item_name||"").trim() && Number(l.quantity) > 0 && Number(l.unit_price) >= 0),
    3: true, // attachments optional
    4: !!data.approver_id,
    5: true,
  };

  // Submit (create + optionally submit for approval + upload attachments)
  const doSave = async (submitForApproval) => {
    setBusy(true);
    try {
      const payload = {
        pr_date: data.pr_date,
        required_date: data.required_date || null,
        requester_dept: requesterDept,
        requester_emp_code: requesterEmpCode,
        approver_id: data.approver_id || null,
        purpose: data.purpose,
        budget_code: data.budget_code,
        project_code: data.project_code,
        currency: data.currency,
        priority: data.priority,
        notes: data.notes,
        vat_rate: vatRate,
        submit: !!submitForApproval,
        line_items: data.line_items.map(l => ({
          item_code: l.item_code, item_master_id: l.item_master_id,
          item_name: l.item_name, description: l.description, category: l.category,
          unit: l.unit, quantity: l.quantity, unit_price: l.unit_price,
          supplier_name: l.supplier_name,
        })),
      };
      const res = await window.apiClient.prCreateRequest(tenant.id, payload);
      setDraftId(res.id);
      // Upload attachments (one by one). Track failures so user gets a clear summary.
      const filesToUpload = data.attachments.filter(a => a._local && a.file);
      const failed = [];
      for (const att of filesToUpload) {
        try {
          await window.apiClient.prUploadAttachment(tenant.id, res.id, att.file);
        } catch (e) {
          failed.push({ name: att.filename, error: e.message });
        }
      }
      if (failed.length > 0) {
        // Block redirect — surface the error clearly so the user can decide what to do.
        toast({ kind:"error", msg: `อัปโหลดไฟล์ ${failed.length}/${filesToUpload.length} ไม่สำเร็จ: ${failed[0].error} · PR ${res.pr_number} ถูกสร้างแล้ว สามารถ login ใหม่แล้วเปิด PR เพื่อแนบใหม่ได้` });
        // Still redirect after a delay so user can read the message
        setTimeout(() => onDone?.(), 100);
        return;
      }
      toast({ kind:"success", msg: submitForApproval ? `ส่งคำขอ ${res.pr_number} ให้อนุมัติแล้ว${filesToUpload.length>0?` (แนบไฟล์ ${filesToUpload.length} ไฟล์)`:""}` : `บันทึก ${res.pr_number} เป็นแบบร่าง` });
      onDone?.();
    } catch (e) {
      toast({ kind:"error", msg: e.message || "บันทึกไม่สำเร็จ" });
    } finally { setBusy(false); }
  };

  const stepDef = [
    { n:1, title:"STEP 1", label:"ข้อมูล PR" },
    { n:2, title:"STEP 2", label:"รายการสินค้า" },
    { n:3, title:"STEP 3", label:"เอกสารแนบ" },
    { n:4, title:"STEP 4", label:"เลือกผู้อนุมัติ" },
    { n:5, title:"STEP 5", label:"ตรวจสอบ & ส่ง" },
  ];

  return (
    <div className="p-5 max-w-[1600px] mx-auto">
      <div className="flex items-end justify-between mb-5">
        <div>
          <div className="text-[11px] uppercase tracking-[.2em] text-ink-400 font-semibold">สร้างคำขอจัดซื้อใหม่</div>
          <h1 className="text-[26px] font-bold tracking-tight mt-1 text-ink-900">Purchase Request — {data.pr_number_preview}</h1>
          <p className="text-[13px] text-ink-500 mt-1">กรอกข้อมูลให้ครบทั้ง 5 ขั้นตอน · ระบบจะดึงข้อมูลผู้ขอจาก Employee Mapping อัตโนมัติ</p>
        </div>
        <div className="flex items-center gap-2">
          <Button variant="secondary" icon="chevronLeft"
            onClick={() => step > 1 ? setStep(s => Math.max(1, s-1)) : onCancel()}>
            กลับ
          </Button>
          {step === 5
            ? <Button icon="send" disabled={busy || !stepValid[1] || !stepValid[2] || !stepValid[4]} onClick={()=>doSave(true)}>ส่งคำขออนุมัติ</Button>
            : <Button icon="chevronRight" iconRight disabled={!stepValid[step]} onClick={()=>setStep(s => Math.min(5, s+1))}>ถัดไป</Button>}
        </div>
      </div>

      {/* Stepper — only allow forward jumps when every step in between is valid */}
      <div className="flex items-center gap-2 mb-5">
        {stepDef.map((s, i) => {
          // Determine whether the user can jump directly to step `s.n`
          let canJump = true;
          if (s.n > step) {
            for (let k = step; k < s.n; k++) {
              if (!stepValid[k]) { canJump = false; break; }
            }
          }
          const tip = canJump ? null : `กรอกข้อมูล Step ${step} ให้ครบก่อน`;
          return (
            <React.Fragment key={s.n}>
              <button
                onClick={() => { if (canJump) setStep(s.n); }}
                disabled={!canJump}
                title={tip}
                className={`flex items-center gap-2 px-3 py-2 rounded-lg text-left text-[12px] font-medium transition
                  ${step === s.n ? "bg-brand-50 text-brand-700 border border-brand-200"
                    : step > s.n ? "text-emerald-700 hover:bg-emerald-50"
                    : canJump ? "text-ink-500 hover:bg-ink-50"
                    : "text-ink-300 cursor-not-allowed"}`}>
                <div className={`w-6 h-6 rounded-full flex items-center justify-center text-[11px] font-bold
                  ${step === s.n ? "bg-brand-500 text-white"
                    : step > s.n ? "bg-emerald-500 text-white"
                    : canJump ? "bg-ink-200 text-ink-500"
                    : "bg-ink-100 text-ink-300"}`}>{step > s.n ? "✓" : s.n}</div>
                <div><div className="text-[10px] uppercase tracking-wider">{s.title}</div><div>{s.label}</div></div>
              </button>
              {i < 4 && <div className="flex-1 h-px bg-ink-200 min-w-[20px]"/>}
            </React.Fragment>
          );
        })}
      </div>

      <div className="grid grid-cols-4 gap-4">
        {/* Main step content */}
        <div className="col-span-3 bg-white border border-ink-200 rounded-2xl p-5 space-y-4">
          {step === 1 && <Step1 data={data} setData={setData} currentUser={currentUser} requesterDept={requesterDept} requesterEmpCode={requesterEmpCode}/>}
          {step === 2 && <Step2 data={data} updateLine={updateLine} addLine={addLine} removeLine={removeLine} items={items}/>}
          {step === 3 && <Step3 data={data} addFiles={addFiles} removeAttachment={removeAttachment}/>}
          {step === 4 && <Step4 data={data} setData={setData} users={users} currentUser={currentUser}/>}
          {step === 5 && <Step5 data={data} subtotal={subtotal} vat={vat} vatRate={vatRate} total={total} users={users} requesterDept={requesterDept}/>}

          {step > 1 && (
            <div className="pt-3 border-t border-ink-100 flex">
              <Button variant="secondary" icon="chevronLeft" onClick={()=>setStep(s => Math.max(1, s-1))}>ย้อนกลับ</Button>
            </div>
          )}
        </div>

        {/* Summary sidebar */}
        <div className="col-span-1">
          <div className="bg-white border border-ink-200 rounded-2xl p-4 sticky top-4">
            <div className="text-[12px] font-bold text-ink-800 mb-2">สรุปคำขอ</div>
            <div className="text-[11px] uppercase tracking-wider text-ink-500 mb-1 mt-3">ผู้ขอ <span className="font-normal normal-case text-ink-400">(จาก EMPLOYEE MAPPING)</span></div>
            <div className="flex items-center gap-2"><Avatar name={currentUser?.full_name} size={26}/>
              <div className="min-w-0"><div className="text-[12px] font-semibold text-ink-800 truncate">{currentUser?.full_name || "—"}</div>
              <div className="text-[10.5px] text-ink-500 truncate">{myPos?.name || "ยังไม่มีตำแหน่ง"}</div></div>
            </div>
            <div className="text-[10.5px] text-ink-500 mt-1">{requesterDept || "—"} · {currentUser?.email || "—"}</div>

            <div className="text-[11px] uppercase tracking-wider text-ink-500 mb-1 mt-3">ผู้อนุมัติ</div>
            {data.approver_id
              ? (() => { const a = getUserDisplay(data.approver_id, users); return <div className="text-[12px] text-ink-800 font-medium">{a.name}<div className="text-[10.5px] text-ink-500">{a.position}</div></div>; })()
              : <button onClick={()=>setStep(4)} className="text-[12px] text-brand-600 hover:underline">ยังไม่ได้เลือก เลือกผู้อนุมัติ</button>}

            <div className="border-t border-ink-100 mt-3 pt-3 flex items-center justify-between text-[12px]"><span className="text-ink-500">รายการสินค้า</span><span className="font-semibold text-ink-800">{data.line_items.length} รายการ</span></div>
            <div className="flex items-center justify-between text-[12px] mt-1"><span className="text-ink-500">กำหนดต้องการ</span><span className="font-medium text-ink-700">{data.required_date ? formatThaiDate(data.required_date) : "—"}</span></div>

            <div className="border-t border-ink-100 mt-3 pt-3"><div className="text-[11px] text-ink-500">มูลค่ารวมโดยประมาณ</div>
              <div className="text-[22px] font-bold text-brand-700 font-mono mt-0.5">{fmtMoney(total)}</div>
              <div className="text-[10.5px] text-ink-500">มูลค่ารวมทั้งสิ้น</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

// --- Step 1: Header info ---
const Step1 = ({ data, setData, currentUser, requesterDept, requesterEmpCode }) => {
  const set = (k, v) => setData(d => ({ ...d, [k]: v }));
  return (
    <div className="space-y-4">
      <div className="text-[14px] font-bold text-ink-800">ข้อมูลคำขอจัดซื้อ (PR Header) <span className="text-[11px] font-normal text-ink-500">· ข้อมูลผู้ขอดึงจาก Employee Mapping โดยอัตโนมัติ</span></div>

      <div className="px-4 py-3 rounded-lg border border-blue-200 bg-blue-50/40">
        <div className="text-[11.5px] font-semibold text-blue-700 mb-2 flex items-center gap-1.5"><Icon name="info" size={13}/>ข้อมูลผู้ขอ (Auto-fill จาก Employee Mapping)</div>
        <div className="flex items-center gap-3"><Avatar name={currentUser?.full_name} size={36}/>
          <div className="text-[12.5px]">
            <div className="font-semibold text-ink-900">{currentUser?.full_name}</div>
            <div className="text-ink-700">แผนก: <strong>{requesterDept || "—"}</strong></div>
            <div className="text-ink-500">· รหัสพนักงาน: <span className="font-mono">{requesterEmpCode || "—"}</span></div>
          </div></div>
      </div>

      <div className="grid grid-cols-3 gap-3">
        <Field label="PR Number" hint="ออกเลขอัตโนมัติโดยระบบ"><Input value={data.pr_number_preview} disabled className="font-mono"/></Field>
        <Field label="PR Date"><Input value={formatThaiDate(data.pr_date)} disabled/></Field>
        <Field label="กำหนดวันที่ต้องการ" required>
          <ThaiDateInput value={data.required_date || ""} onChange={v=>set("required_date", v)}/>
        </Field>
      </div>

      <Field label="วัตถุประสงค์ / เหตุผลในการจัดซื้อ" required>
        <textarea value={data.purpose} onChange={e=>set("purpose", e.target.value)} rows={3}
          placeholder="เช่น จัดซื้อโน๊ตบุ๊คทดแทนเครื่องเก่าที่หมดอายุการใช้งานสำหรับทีมจัดซื้อ"
          className="w-full px-3 py-2 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus"/>
      </Field>

      <div className="grid grid-cols-3 gap-3">
        <Field label="Budget / Cost Center" hint="ถ้ามี — ใช้สำหรับการแยกหมวดบัญชี">
          <Input value={data.budget_code} onChange={e=>set("budget_code", e.target.value)} placeholder="เช่น OPEX-PRC-2026"/>
        </Field>
        <Field label="Project Code">
          <Input value={data.project_code} onChange={e=>set("project_code", e.target.value)} placeholder="เช่น REFRESH-NB-26"/>
        </Field>
        <Field label="สกุลเงิน" hint="สามารถสั่งซื้อเป็นสกุลเงินอื่น ๆ ได้">
          <select value={data.currency} onChange={e=>set("currency", e.target.value)} className="w-full h-9 px-2.5 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus">
            {["THB","USD","EUR","JPY","SGD","CNY"].map(c => <option key={c}>{c}</option>)}
          </select>
        </Field>
      </div>

      <div className="grid grid-cols-2 gap-3">
        <Field label="ระดับความสำคัญ">
          <Segmented value={data.priority} onChange={v=>set("priority", v)} options={[
            { value:"normal", label:"ปกติ (Normal)" },
            { value:"urgent", label:"⚠ ด่วน (Urgent)" },
          ]}/>
        </Field>
        <Field label="หมายเหตุทั่วไป">
          <Input value={data.notes} onChange={e=>set("notes", e.target.value)} placeholder="หมายเหตุเพิ่มเติม (ถ้ามี)"/>
        </Field>
      </div>
    </div>
  );
};

// Inline autocomplete on a line item cell — pops up suggestions filtered from Item Master.
// Used for both the code and name columns: typing in either filters by both fields.
// Picking a suggestion fills the entire row (code, name, desc, unit, price, supplier, master_id).
// Strict autocomplete: input shows linked master value when idle. Typing switches to "search"
// mode (popup with filtered items). Only picking from the dropdown commits to the line —
// freeform input is reverted on blur. This guarantees every line ties back to an Item Master row.
const LineItemAutocomplete = ({ field, line, lineIdx, updateLine, items, placeholder, inputClass }) => {
  const [mode, setMode] = useState("display");      // "display" | "search"
  const [searchText, setSearchText] = useState(""); // active only in search mode
  const [open, setOpen] = useState(false);
  const [coords, setCoords] = useState(null);
  const wrapRef = useRef(null);
  const popupRef = useRef(null);

  const linkedMaster = line.item_master_id ? items.find(it => it.id === line.item_master_id) : null;
  const displayValue = linkedMaster
    ? (field === "item_code" ? linkedMaster.item_code : linkedMaster.name)
    : "";
  const inputValue = mode === "search" ? searchText : displayValue;

  const recomputePos = () => {
    if (!wrapRef.current) return;
    const r = wrapRef.current.getBoundingClientRect();
    setCoords({ left: r.left, top: r.bottom + 4, width: Math.max(380, r.width) });
  };
  useEffect(() => {
    if (!open) return;
    recomputePos();
    window.addEventListener("scroll", recomputePos, true);
    window.addEventListener("resize", recomputePos);
    return () => {
      window.removeEventListener("scroll", recomputePos, true);
      window.removeEventListener("resize", recomputePos);
    };
  }, [open]);

  // Outside click: close popup AND revert to display mode (drop unconfirmed search text)
  useEffect(() => {
    const close = (e) => {
      if (wrapRef.current?.contains(e.target)) return;
      if (popupRef.current?.contains(e.target)) return;
      setOpen(false);
      setMode("display");
      setSearchText("");
    };
    document.addEventListener("mousedown", close);
    return () => document.removeEventListener("mousedown", close);
  }, []);

  // Build suggestion list — empty search shows top items so users can browse
  const ql = mode === "search" ? searchText.trim().toLowerCase() : "";
  const suggestions = ql.length > 0
    ? items.filter(it => (it.item_code || "").toLowerCase().includes(ql) || (it.name || "").toLowerCase().includes(ql)).slice(0, 8)
    : items.slice(0, 12);

  const onFocus = () => {
    setMode("search");
    setSearchText(displayValue);  // pre-fill so user can edit current value as starting point
    setOpen(true);
  };
  const onChangeText = (v) => {
    setSearchText(field === "item_code" ? v.toUpperCase() : v);
    setOpen(true);
  };
  const onPick = (it) => {
    updateLine(lineIdx, {
      item_code: it.item_code,
      item_master_id: it.id,
      item_name: it.name,
      description: it.description || "",
      category: it.category || "",
      unit: it.unit || "",
      unit_price: Number(it.base_price) || 0,
      supplier_name: it.supplier_name || "",
    });
    setMode("display");
    setSearchText("");
    setOpen(false);
  };

  return (
    <div ref={wrapRef} className="relative">
      <input
        className={inputClass}
        value={inputValue}
        onChange={e => onChangeText(e.target.value)}
        onFocus={onFocus}
        placeholder={placeholder}
        autoComplete="off"
      />
      {open && coords && (
        <div ref={popupRef}
             style={{ position: "fixed", left: coords.left, top: coords.top, width: coords.width, zIndex: 60 }}
             className="bg-white border border-ink-200 rounded-lg shadow-xl max-h-72 overflow-y-auto">
          <div className="px-2.5 py-1.5 text-[10.5px] uppercase tracking-wider text-ink-500 bg-ink-50 border-b border-ink-100 sticky top-0">
            {ql.length > 0
              ? (suggestions.length > 0 ? `พบ ${suggestions.length} รายการตรงเงื่อนไข` : "ไม่พบรายการที่ตรง")
              : "พิมพ์เพื่อค้นหา · เลือกได้เฉพาะรายการจาก Item Master"}
          </div>
          {suggestions.length === 0 ? (
            <div className="px-4 py-5 text-[11.5px] text-rose-600 text-center">
              ⚠ รหัส/ชื่อนี้ไม่มีใน Item Master<br/>
              <span className="text-ink-500 text-[10.5px]">กรุณาเพิ่มสินค้าใหม่ผ่านเมนู Item Master ก่อน</span>
            </div>
          ) : suggestions.map(it => (
            <button key={it.id} type="button" onMouseDown={(e)=>e.preventDefault()} onClick={()=>onPick(it)}
              className="w-full flex items-center gap-2 px-2.5 py-2 hover:bg-brand-50 text-left border-b border-ink-100 last:border-0">
              <span className="font-mono text-[11px] text-ink-600 w-[110px] shrink-0">{it.item_code}</span>
              <div className="flex-1 min-w-0">
                <div className="text-[12px] text-ink-800 truncate">{it.name}</div>
                {(it.category || it.unit) && (
                  <div className="text-[10.5px] text-ink-500 truncate">
                    {it.category || ""}{it.category && it.unit ? " · " : ""}{it.unit || ""}
                  </div>
                )}
              </div>
              <span className="font-mono text-[11px] font-semibold text-brand-700 shrink-0 whitespace-nowrap">
                ฿{Number(it.base_price||0).toLocaleString("th-TH",{minimumFractionDigits:0, maximumFractionDigits:0})}
              </span>
            </button>
          ))}
        </div>
      )}
    </div>
  );
};

// --- Step 2: Line items ---
const Step2 = ({ data, updateLine, addLine, removeLine, items }) => {
  const [pickerOpen, setPickerOpen] = useState(false);

  return (
    <div className="space-y-3">
      <div className="flex items-center justify-between">
        <div className="text-[14px] font-bold text-ink-800">รายการสินค้า / บริการ</div>
        <div className="flex items-center gap-2">
          <Button variant="secondary" icon="package" onClick={()=>setPickerOpen(true)}>เลือกจาก Item Master</Button>
          <Button icon="plus" onClick={()=>addLine()}>เพิ่มแถวว่าง</Button>
        </div>
      </div>
      {data.line_items.length === 0 && (
        <div className="px-6 py-12 text-center border-2 border-dashed border-ink-200 rounded-xl text-ink-400">ยังไม่มีรายการสินค้า — กด "เลือกจาก Item Master" หรือ "เพิ่มแถวว่าง" แล้วเลือกสินค้าจาก dropdown</div>
      )}
      {data.line_items.length > 0 && data.line_items.some(l => !l.item_master_id) && (
        <div className="px-3 py-2 rounded-md bg-amber-50 border border-amber-200 text-amber-800 text-[11.5px] flex items-start gap-2">
          <Icon name="info" size={13} className="mt-0.5 shrink-0"/>
          <span>แถวที่มีสีพื้นเหลืองยังไม่ได้เลือกสินค้าจาก Item Master · คลิกในช่องรหัสหรือชื่อแล้วเลือกจาก dropdown</span>
        </div>
      )}
      {data.line_items.length > 0 && (
        <div className="rounded-lg border border-ink-200 overflow-x-auto">
          <table className="w-full text-[12px] min-w-[900px]">
            <thead className="bg-ink-50 text-ink-500 text-[11px] uppercase">
              <tr>
                <th className="text-left px-2 py-2 w-[110px]">รหัส</th>
                <th className="text-left px-2 py-2">ชื่อสินค้า *</th>
                <th className="text-right px-2 py-2 w-[90px]">จำนวน *</th>
                <th className="text-left px-2 py-2 w-[90px]">หน่วย</th>
                <th className="text-right px-2 py-2 w-[120px]">ราคา/หน่วย *</th>
                <th className="text-right px-2 py-2 w-[110px]">รวม</th>
                <th className="w-[40px]"></th>
              </tr>
            </thead>
            <tbody>
              {data.line_items.map((l, idx) => {
                const lineTotal = (Number(l.quantity)||0) * (Number(l.unit_price)||0);
                const isIncomplete = !l.item_master_id;
                return (
                  <tr key={idx} className={`border-t border-ink-100 align-top ${isIncomplete ? "bg-amber-50/40" : ""}`}>
                    <td className="px-2 py-1.5">
                      <LineItemAutocomplete field="item_code" line={l} lineIdx={idx} updateLine={updateLine} items={items}
                        placeholder="พิมพ์รหัส..."
                        inputClass="w-full px-2 py-1 text-[11.5px] font-mono bg-transparent border border-transparent hover:border-ink-200 focus:border-brand-500 rounded ring-focus"/>
                    </td>
                    <td className="px-2 py-1.5">
                      <LineItemAutocomplete field="item_name" line={l} lineIdx={idx} updateLine={updateLine} items={items}
                        placeholder="พิมพ์ชื่อสินค้า / บริการ..."
                        inputClass="w-full px-2 py-1 text-[12px] bg-transparent border border-transparent hover:border-ink-200 focus:border-brand-500 rounded ring-focus"/>
                      {l.description && <div className="text-[10.5px] text-ink-500 px-2 mt-0.5">{l.description}</div>}
                    </td>
                    <td className="px-2 py-1.5"><input type="number" min="0" step="1" className="w-full px-2 py-1 text-[12px] text-right font-mono bg-transparent border border-transparent hover:border-ink-200 focus:border-brand-500 rounded ring-focus" value={l.quantity || ""} placeholder="0" onChange={e=>updateLine(idx,{ quantity: e.target.value.replace(/^0+(?=\d)/, "") })}/></td>
                    <td className="px-2 py-1.5"><input className="w-full px-2 py-1 text-[12px] bg-transparent border border-transparent hover:border-ink-200 focus:border-brand-500 rounded ring-focus" value={l.unit||""} onChange={e=>updateLine(idx,{ unit:e.target.value })} placeholder="—"/></td>
                    <td className="px-2 py-1.5"><input type="number" min="0" step="0.01" className="w-full px-2 py-1 text-[12px] text-right font-mono bg-transparent border border-transparent hover:border-ink-200 focus:border-brand-500 rounded ring-focus" value={l.unit_price || ""} placeholder="0.00" onChange={e=>updateLine(idx,{ unit_price: e.target.value.replace(/^0+(?=\d)/, "") })}/></td>
                    <td className="px-2 py-1.5 text-right font-mono font-semibold text-ink-800">{fmtMoney(lineTotal)}</td>
                    <td className="px-2 py-1.5 text-center"><IconBtn icon="trash" tip="ลบรายการ" danger onClick={()=>removeLine(idx)}/></td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      <ItemPickerModal open={pickerOpen} items={items} onClose={()=>setPickerOpen(false)}
        onPick={(it)=>{ addLine({
          item_code: it.item_code, item_master_id: it.id, item_name: it.name,
          description: it.description || "", category: it.category, unit: it.unit,
          quantity: 1, unit_price: Number(it.base_price)||0, supplier_name: it.supplier_name || "",
        }); }}/>
    </div>
  );
};

const ItemPickerModal = ({ open, items, onClose, onPick }) => {
  const [q, setQ] = useState("");
  useEffect(() => { if (open) setQ(""); }, [open]);
  if (!open) return null;
  const ql = q.trim().toLowerCase();
  const filtered = items.filter(it =>
    !ql || (it.item_code||"").toLowerCase().includes(ql) || (it.name||"").toLowerCase().includes(ql) || (it.category||"").toLowerCase().includes(ql)
  );
  return (
    <Modal open onClose={onClose} title="เลือกสินค้าจาก Item Master" subtitle="ค้นหาจากรหัสหรือชื่อสินค้า" width={760}>
      <div className="relative mb-3">
        <Icon name="search" size={13} className="absolute left-3 top-1/2 -translate-y-1/2 text-ink-400"/>
        <input value={q} onChange={e=>setQ(e.target.value)} autoFocus placeholder="ค้นหา..."
          className="w-full h-9 pl-9 pr-3 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus"/>
      </div>
      <div className="max-h-[440px] overflow-y-auto rounded-lg border border-ink-200">
        {filtered.length === 0 && <div className="text-center py-10 text-ink-400 text-[12px]">ไม่พบรายการ</div>}
        {filtered.map(it => (
          <button key={it.id} onClick={()=>{ onPick(it); onClose(); }} className="w-full flex items-center gap-3 px-3 py-2.5 border-b border-ink-100 last:border-0 hover:bg-brand-50 text-left">
            <div className="font-mono text-[11.5px] text-ink-600 w-[110px] shrink-0">{it.item_code}</div>
            <div className="flex-1 min-w-0">
              <div className="text-[12.5px] font-medium text-ink-800 truncate">{it.name}</div>
              <div className="text-[10.5px] text-ink-500 truncate">{it.category||"—"} · {it.unit||"—"}{it.supplier_name?" · "+it.supplier_name:""}</div>
            </div>
            <div className="font-mono text-[12px] font-semibold text-brand-700 whitespace-nowrap">{fmtMoney(it.base_price)}</div>
          </button>
        ))}
      </div>
    </Modal>
  );
};

// --- Step 3: Attachments ---
const Step3 = ({ data, addFiles, removeAttachment }) => {
  const inputRef = useRef(null);
  const MAX_FILES = 3;
  const reached = data.attachments.length >= MAX_FILES;
  return (
    <div className="space-y-3">
      <div className="flex items-end justify-between">
        <div className="text-[14px] font-bold text-ink-800">เอกสารแนบ</div>
        <div className={`text-[11.5px] font-medium ${reached ? "text-rose-600" : "text-ink-500"}`}>
          {data.attachments.length} / {MAX_FILES} ไฟล์
        </div>
      </div>
      <div className="text-[12px] text-ink-500">ไฟล์ที่รองรับ: PDF, รูปภาพ (JPG/PNG), Excel, Word · ขนาดสูงสุด <strong>10MB</strong>/ไฟล์ · อัปโหลดได้สูงสุด <strong>{MAX_FILES}</strong> ไฟล์</div>
      <div
        onClick={() => { if (!reached) inputRef.current?.click(); }}
        onDragOver={e=>{ e.preventDefault(); }}
        onDrop={e=>{ e.preventDefault(); if (!reached) addFiles(e.dataTransfer.files); }}
        className={`border-2 border-dashed rounded-xl px-6 py-10 text-center transition
          ${reached
            ? "border-ink-200 bg-ink-50/40 cursor-not-allowed opacity-60"
            : "border-ink-200 cursor-pointer hover:border-brand-400 hover:bg-brand-50/40"}`}>
        <Icon name={reached ? "ban" : "upload"} size={24} className={`mx-auto mb-2 ${reached ? "text-rose-400" : "text-ink-400"}`}/>
        {reached ? (
          <>
            <div className="text-[13px] text-rose-600 font-medium">ครบ {MAX_FILES} ไฟล์แล้ว</div>
            <div className="text-[11px] text-ink-500 mt-1">หากต้องการเพิ่มไฟล์ใหม่ กรุณาลบไฟล์เดิมก่อน</div>
          </>
        ) : (
          <>
            <div className="text-[13px] text-ink-700 font-medium">คลิกเพื่อเลือกไฟล์ หรือลากไฟล์มาวางที่นี่</div>
            <div className="text-[11px] text-ink-400 mt-1">เพิ่มได้อีก {MAX_FILES - data.attachments.length} ไฟล์</div>
          </>
        )}
        <input ref={inputRef} type="file" multiple className="hidden" onChange={e=>addFiles(e.target.files)}/>
      </div>
      {data.attachments.length > 0 && (
        <div className="space-y-1.5">
          {data.attachments.map(a => (
            <div key={a._id || a.id} className="flex items-center gap-2 px-3 py-2 rounded-md border border-ink-200 bg-ink-50/40">
              <Icon name="paperclip" size={14} className="text-ink-500"/>
              <span className="flex-1 text-[12px] text-ink-800 truncate">{a.filename}</span>
              <span className="text-[10.5px] text-ink-500 font-mono">{((a.size||0)/1024).toFixed(1)} KB</span>
              <IconBtn icon="x" tip="ลบไฟล์" danger onClick={()=>removeAttachment(a._id || a.id)}/>
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

// --- Step 4: Choose approver ---
const Step4 = ({ data, setData, users, currentUser }) => {
  const [q, setQ] = useState("");
  const ql = q.trim().toLowerCase();
  // exclude self from approver list
  const candidates = (users || []).filter(u => u.id !== currentUser?.id && (u.status === "active" || !u.status));
  const filtered = candidates.filter(u =>
    !ql || (u.full_name||"").toLowerCase().includes(ql) || (u.email||"").toLowerCase().includes(ql)
  );
  return (
    <div className="space-y-3">
      <div className="text-[14px] font-bold text-ink-800">เลือกผู้อนุมัติ</div>
      <div className="text-[12px] text-ink-500">เลือก 1 คน ที่จะได้รับคำขอนี้เพื่ออนุมัติ — ผู้อนุมัติจะเห็นคำขอใน "My Approvals" ของพวกเขา</div>

      <div className="relative">
        <Icon name="search" size={13} className="absolute left-3 top-1/2 -translate-y-1/2 text-ink-400"/>
        <input value={q} onChange={e=>setQ(e.target.value)} placeholder="ค้นหาชื่อ / อีเมล..."
          className="w-full h-9 pl-9 pr-3 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus"/>
      </div>

      <div className="max-h-[440px] overflow-y-auto space-y-1">
        {filtered.length === 0 && <div className="text-center py-10 text-ink-400 text-[12px]">ไม่พบผู้ใช้</div>}
        {filtered.map(u => {
          const selected = data.approver_id === u.id;
          return (
            <button key={u.id} onClick={()=>setData(d=>({ ...d, approver_id: u.id }))} className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg border text-left transition
              ${selected ? "border-brand-400 bg-brand-50" : "border-ink-200 hover:bg-ink-50"}`}>
              <Avatar name={u.full_name} size={32}/>
              <div className="flex-1 min-w-0">
                <div className="text-[12.5px] font-semibold text-ink-900 truncate">{u.full_name}</div>
                <div className="text-[11px] text-ink-500 truncate">{u.email}{u.position_name?" · "+u.position_name:""}</div>
              </div>
              {selected && <Icon name="check" size={16} className="text-brand-600"/>}
            </button>
          );
        })}
      </div>
    </div>
  );
};

// --- Step 5: Review & submit ---
const Step5 = ({ data, subtotal, vat, vatRate, total, users, requesterDept }) => {
  const apprU = data.approver_id ? getUserDisplay(data.approver_id, users) : null;
  return (
    <div className="space-y-4">
      <div className="text-[14px] font-bold text-ink-800">ตรวจสอบรายละเอียดก่อนส่งคำขอ</div>

      <div className="px-3 py-2 rounded-md bg-amber-50 border border-amber-200 text-amber-800 text-[11.5px] flex items-start gap-2">
        <Icon name="info" size={13} className="mt-0.5 shrink-0"/>
        <span>เมื่อกด <strong>ส่งคำขออนุมัติ</strong> ระบบจะส่งคำขอให้ผู้อนุมัติทันที — ผู้ขอจะแก้ไขคำขอเองได้เฉพาะตอนยังเป็นแบบร่างเท่านั้น</span>
      </div>

      <div className="grid grid-cols-2 gap-3 text-[12px]">
        <Kv label="วัตถุประสงค์" value={data.purpose || "—"}/>
        <Kv label="กำหนดต้องการ" value={data.required_date ? formatThaiDate(data.required_date) : "—"}/>
        <Kv label="Budget / Cost Center" value={data.budget_code || "—"}/>
        <Kv label="Project Code" value={data.project_code || "—"}/>
        <Kv label="ระดับความสำคัญ" value={data.priority === "urgent" ? "⚠ ด่วน" : "ปกติ"}/>
        <Kv label="ผู้อนุมัติ" value={apprU ? apprU.name : "— (ยังไม่ได้เลือก)"}/>
      </div>

      <div>
        <div className="text-[12px] font-semibold text-ink-700 mb-1.5">รายการสินค้า ({data.line_items.length})</div>
        <div className="rounded-lg border border-ink-200 overflow-hidden">
          <table className="w-full text-[11.5px]">
            <thead className="bg-ink-50 text-ink-500 text-[10.5px] uppercase">
              <tr><th className="text-left px-2 py-1.5">รหัส</th><th className="text-left px-2 py-1.5">ชื่อ</th><th className="text-right px-2 py-1.5">จำนวน</th><th className="text-right px-2 py-1.5">ราคา</th><th className="text-right px-2 py-1.5">รวม</th></tr>
            </thead>
            <tbody>
              {data.line_items.map((l, i) => {
                const lt = (Number(l.quantity)||0) * (Number(l.unit_price)||0);
                return <tr key={i} className="border-t border-ink-100"><td className="px-2 py-1.5 font-mono">{l.item_code||"—"}</td><td className="px-2 py-1.5">{l.item_name}</td><td className="px-2 py-1.5 text-right font-mono">{Number(l.quantity).toLocaleString()} {l.unit||""}</td><td className="px-2 py-1.5 text-right font-mono">{fmtMoney(l.unit_price)}</td><td className="px-2 py-1.5 text-right font-mono font-semibold">{fmtMoney(lt)}</td></tr>;
              })}
            </tbody>
            <tfoot className="bg-ink-50/60 text-[12px]">
              <tr className="border-t border-ink-200"><td colSpan={4} className="px-2 py-1.5 text-right font-semibold">มูลค่ารวม</td><td className="px-2 py-1.5 text-right font-mono font-bold text-brand-700">{fmtMoney(total)}</td></tr>
            </tfoot>
          </table>
        </div>
      </div>

      {data.attachments.length > 0 && (
        <div>
          <div className="text-[12px] font-semibold text-ink-700 mb-1.5">เอกสารแนบ ({data.attachments.length})</div>
          <div className="space-y-1">{data.attachments.map(a => <div key={a._id||a.id} className="text-[12px] text-ink-700 flex items-center gap-2"><Icon name="paperclip" size={12}/>{a.filename}</div>)}</div>
        </div>
      )}
    </div>
  );
};

// =========================================================================
// MY APPROVALS PAGE
// =========================================================================
const MyApprovalsPage = ({ tenant, currentUser, currentRole, users }) => {
  const toast = useToast();
  const [requests, setRequests] = useState([]);
  const [loading, setLoading] = useState(false);
  const [tab, setTab] = useState("pending");  // pending | approved | rejected | all
  const [detailFor, setDetailFor] = useState(null);

  const reload = async () => {
    if (!tenant?.id || !currentUser?.id) return;
    setLoading(true);
    try {
      const rows = await window.apiClient.prListRequests(tenant.id, { approver_id: currentUser.id });
      setRequests(Array.isArray(rows) ? rows : []);
    } catch (e) {
      toast({ kind:"error", msg: e.message || "โหลดรายการไม่สำเร็จ" });
    } finally { setLoading(false); }
  };
  useEffect(() => { reload(); /* eslint-disable-next-line */ }, [tenant?.id, currentUser?.id]);

  // Bucketize
  const byTab = {
    pending: requests.filter(r => r.status === "pending"),
    approved: requests.filter(r => r.status === "approved" || r.status === "purchased"),
    rejected: requests.filter(r => r.status === "rejected"),
    all: requests,
  };

  // KPI (current month focus — keep simple: count by status across all months in approver inbox)
  const pendingTotal = byTab.pending.reduce((s,r) => s + (Number(r.total_amount)||0), 0);

  const rows = byTab[tab] || [];

  return (
    <div className="p-5 max-w-[1600px] mx-auto">
      <div className="mb-5">
        <div className="text-[11px] uppercase tracking-[.2em] text-ink-400 font-semibold">MY APPROVALS · ที่อยู่ในความรับผิดชอบของคุณ</div>
        <h1 className="text-[26px] font-bold tracking-tight mt-1 text-ink-900">คำขอที่รออนุมัติ (Approver Review)</h1>
        <p className="text-[13px] text-ink-500 mt-1">รายการคำขอจัดซื้อที่ <strong>{currentUser?.full_name || "คุณ"}</strong> ถูกเลือกเป็นผู้อนุมัติ</p>
      </div>

      <div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-5">
        <KpiCard icon="clock" tone="amber" label="รอดำเนินการ" value={byTab.pending.length} trend="ต้องอนุมัติหรือปฏิเสธ"/>
        <KpiCard icon="check" tone="emerald" label="อนุมัติแล้ว" value={byTab.approved.length} trend="รวมที่จัดซื้อแล้ว"/>
        <KpiCard icon="ban" tone="rose" label="ปฏิเสธ" value={byTab.rejected.length} trend="ทั้งหมด"/>
        <KpiCard icon="bar" tone="indigo" label="มูลค่ารวม รออนุมัติ" value={fmtMoney(pendingTotal)} trend="THB · มูลค่ารวมทั้งสิ้น"/>
      </div>

      <div className="flex items-center gap-1 mb-3 border-b border-ink-200">
        {[["pending","รออนุมัติ"],["approved","อนุมัติแล้ว"],["rejected","ปฏิเสธ"],["all","ทั้งหมด"]].map(([k,l]) => (
          <button key={k} onClick={()=>setTab(k)} className={`relative px-3 py-2 text-[12.5px] font-medium ${tab===k?"text-brand-700":"text-ink-500 hover:text-ink-800"}`}>
            {l}<span className={`ml-1.5 px-1.5 py-0.5 rounded-md text-[10.5px] ${tab===k?"bg-brand-100 text-brand-700":"bg-ink-100 text-ink-500"}`}>{byTab[k]?.length||0}</span>
            {tab===k && <span className="absolute bottom-0 left-0 right-0 h-0.5 bg-brand-500"/>}
          </button>
        ))}
      </div>

      <div className="rounded-2xl border border-ink-200 bg-white overflow-x-auto">
        <table className="w-full text-[12.5px] min-w-[1000px]">
          <thead className="bg-ink-50 text-ink-500 text-[11px] uppercase tracking-wider">
            <tr>{["PR Number","วันที่สร้าง","ผู้ขอ","แผนกผู้ขอ","มูลค่ารวม","กำหนดส่ง","ความสำคัญ","สถานะ","การกระทำ"].map(h => <th key={h} className="text-left font-semibold px-3 py-2.5 border-b border-ink-200">{h}</th>)}</tr>
          </thead>
          <tbody>
            {loading && <tr><td colSpan={9} className="text-center py-10 text-ink-400">กำลังโหลด…</td></tr>}
            {!loading && rows.length === 0 && (
              <tr><td colSpan={9} className="text-center py-16">
                <div className="w-14 h-14 mx-auto mb-3 rounded-2xl bg-ink-100 flex items-center justify-center"><Icon name="inbox" size={26} className="text-ink-400"/></div>
                <div className="text-[14px] font-semibold text-ink-700">ไม่มีคำขอรออนุมัติ</div>
                <div className="text-[12px] text-ink-500 mt-1">ขณะนี้ไม่มีคำขอจัดซื้อที่รอการอนุมัติจากคุณ</div>
              </td></tr>
            )}
            {!loading && rows.map(r => {
              const reqU = getUserDisplay(r.requester_id, users);
              return (
                <tr key={r.id} className="hover:bg-ink-50/60 border-b border-ink-100 last:border-0">
                  <td className="px-3 py-3"><button onClick={()=>setDetailFor(r.id)} className="text-brand-700 hover:underline font-mono font-semibold">{r.pr_number}</button>{r.purpose && <div className="text-[11px] text-ink-500 truncate-1 max-w-[200px]" title={r.purpose}>{r.purpose}</div>}</td>
                  <td className="px-3 py-3 text-ink-700">{formatThaiDate(r.pr_date)}</td>
                  <td className="px-3 py-3"><div className="flex items-center gap-2"><Avatar name={reqU.name} size={24}/><div className="min-w-0"><div className="font-medium text-ink-800 truncate">{reqU.name}</div>{reqU.position && <div className="text-[10.5px] text-ink-500 truncate">{reqU.position}</div>}</div></div></td>
                  <td className="px-3 py-3 text-ink-700">{r.requester_dept_snapshot || reqU.dept || "—"}</td>
                  <td className="px-3 py-3 font-mono text-ink-800 text-right">{fmtMoney(r.total_amount)}</td>
                  <td className="px-3 py-3 text-ink-700">{formatThaiDate(r.required_date)}</td>
                  <td className="px-3 py-3">{r.priority==="urgent" ? <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded-md bg-rose-50 text-rose-700 text-[11px] font-medium"><Icon name="warning" size={11}/>ด่วน</span> : <span className="text-ink-500 text-[11px]">ปกติ</span>}</td>
                  <td className="px-3 py-3"><PRStatusPill status={r.status}/></td>
                  <td className="px-3 py-3"><Button size="sm" icon="search" onClick={()=>setDetailFor(r.id)}>ตรวจสอบ</Button></td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {detailFor && <PRDetailModal tenant={tenant} prId={detailFor} onClose={()=>setDetailFor(null)} onChanged={reload} users={users} currentUser={currentUser} currentRole={currentRole}/>}
    </div>
  );
};

// =========================================================================
// REPORTS & EXPORT PAGE
// =========================================================================
const PRReportsPage = ({ tenant, users, departments }) => {
  const toast = useToast();
  const [requests, setRequests] = useState([]);
  const [loading, setLoading] = useState(false);
  const [filter, setFilter] = useState({
    status: "__all__",
    date_from: "",
    date_to: "",
    requester_dept: "__all__",
    category: "__all__",
    requester_name: "",
    amount_from: "",
    amount_to: "",
  });
  const [level, setLevel] = useState("header"); // header | lines
  const [allLines, setAllLines] = useState({});  // pr_id → line_items array (lazy loaded)

  const reload = async () => {
    if (!tenant?.id) return;
    setLoading(true);
    try {
      const rows = await window.apiClient.prListRequests(tenant.id);
      setRequests(Array.isArray(rows) ? rows : []);
    } catch (e) { toast({ kind:"error", msg: e.message }); }
    finally { setLoading(false); }
  };
  useEffect(() => { reload(); /* eslint-disable-next-line */ }, [tenant?.id]);

  // Lazy load line items only when needed (line level export)
  useEffect(() => {
    if (level !== "lines" || requests.length === 0) return;
    const missing = requests.filter(r => !allLines[r.id]);
    if (missing.length === 0) return;
    (async () => {
      const updates = {};
      for (const r of missing.slice(0, 30)) {  // batch limit to avoid hammering
        try {
          const detail = await window.apiClient.prGetRequest(tenant.id, r.id);
          updates[r.id] = detail.line_items || [];
        } catch { updates[r.id] = []; }
      }
      setAllLines(prev => ({ ...prev, ...updates }));
    })();
  }, [level, requests, allLines, tenant?.id]);

  // Apply filters
  const filtered = useMemo(() => {
    const f = filter;
    return requests.filter(r => {
      if (f.status !== "__all__" && r.status !== f.status) return false;
      if (f.date_from && r.pr_date < f.date_from) return false;
      if (f.date_to && r.pr_date > f.date_to) return false;
      if (f.requester_dept !== "__all__" && (r.requester_dept_snapshot || "") !== f.requester_dept) return false;
      if (f.requester_name) {
        const ql = f.requester_name.toLowerCase();
        const name = getUserDisplay(r.requester_id, users).name.toLowerCase();
        if (!name.includes(ql)) return false;
      }
      if (f.amount_from && Number(r.total_amount) < Number(f.amount_from)) return false;
      if (f.amount_to && Number(r.total_amount) > Number(f.amount_to)) return false;
      return true;
    });
  }, [requests, filter, users]);

  // Build flat rows for preview / export
  const previewRows = useMemo(() => {
    if (level === "header") {
      return filtered.map(r => {
        const reqU = getUserDisplay(r.requester_id, users);
        const apprU = getUserDisplay(r.approver_id, users);
        return {
          pr_number: r.pr_number,
          pr_date: r.pr_date,
          requester: reqU.name,
          requester_dept: r.requester_dept_snapshot || reqU.dept,
          approver: apprU.name,
          purpose: r.purpose,
          required_date: r.required_date,
          priority: r.priority,
          subtotal: r.subtotal,
          vat_amount: r.vat_amount,
          total_amount: r.total_amount,
          status: PR_STATUS_META[r.status]?.label || r.status,
          ordering_status: PR_LINE_STATUS_META[r.ordering_status]?.label || (r.ordering_status || "—"),
        };
      });
    } else {
      // Line level — one row per (pr × line item)
      const out = [];
      filtered.forEach(r => {
        const reqU = getUserDisplay(r.requester_id, users);
        const apprU = getUserDisplay(r.approver_id, users);
        const lines = allLines[r.id] || [];
        if (lines.length === 0) {
          out.push({
            pr_number: r.pr_number, pr_date: r.pr_date, requester: reqU.name,
            requester_dept: r.requester_dept_snapshot || reqU.dept, approver: apprU.name,
            item_code: "—", item_name: "(ไม่มีรายการ)", quantity: "", unit: "", unit_price: "",
            line_total: r.total_amount, status: PR_STATUS_META[r.status]?.label,
          });
        } else lines.forEach(l => {
          out.push({
            pr_number: r.pr_number, pr_date: r.pr_date, requester: reqU.name,
            requester_dept: r.requester_dept_snapshot || reqU.dept, approver: apprU.name,
            item_code: l.item_code || "—", item_name: l.item_name,
            quantity: l.quantity, unit: l.unit || "",
            unit_price: l.unit_price, line_total: l.line_total,
            status: PR_STATUS_META[r.status]?.label || r.status,
          });
        });
      });
      return out;
    }
  }, [filtered, level, users, allLines]);

  const onExport = () => {
    const headers = level === "header"
      ? ["PR Number","วันที่","ผู้ขอ","แผนก","ผู้อนุมัติ","วัตถุประสงค์","กำหนดต้องการ","ความสำคัญ","มูลค่ารวม","สถานะ PR","Ordering Status"]
      : ["PR Number","วันที่","ผู้ขอ","แผนก","ผู้อนุมัติ","Item Code","Item Name","จำนวน","หน่วย","ราคา/หน่วย","รวม","สถานะ"];
    const lines = [headers.join(",")];
    previewRows.forEach(r => {
      const vals = level === "header"
        ? [r.pr_number, r.pr_date, r.requester, r.requester_dept, r.approver, r.purpose, r.required_date, r.priority==="urgent"?"ด่วน":"ปกติ", r.total_amount, r.status, r.ordering_status]
        : [r.pr_number, r.pr_date, r.requester, r.requester_dept, r.approver, r.item_code, r.item_name, r.quantity, r.unit, r.unit_price, r.line_total, r.status];
      lines.push(vals.map(v => {
        const s = String(v ?? "");
        return s.includes(",") || s.includes('"') || s.includes("\n") ? `"${s.replace(/"/g,'""')}"` : s;
      }).join(","));
    });
    const csv = "﻿" + lines.join("\r\n");
    const blob = new Blob([csv], { type:"text/csv;charset=utf-8" });
    const a = document.createElement("a");
    a.href = URL.createObjectURL(blob);
    a.download = `PR_Report_${tenant?.tenant_code || "tenant"}_${level}_${new Date().toISOString().slice(0,10)}.csv`;
    a.click();
    URL.revokeObjectURL(a.href);
    toast({ kind:"success", msg:`ส่งออก ${previewRows.length} แถว` });
  };

  const reset = () => setFilter({ status:"__all__", date_from:"", date_to:"", requester_dept:"__all__", category:"__all__", requester_name:"", amount_from:"", amount_to:"" });

  const deptOptions = [...new Set(requests.map(r => r.requester_dept_snapshot).filter(Boolean))];

  return (
    <div className="p-5 max-w-[1600px] mx-auto">
      <div className="flex items-end justify-between mb-5 flex-wrap gap-3">
        <div>
          <div className="text-[11px] uppercase tracking-[.2em] text-ink-400 font-semibold">รายงาน · REPORTS & EXPORT</div>
          <h1 className="text-[26px] font-bold tracking-tight mt-1 text-ink-900">ส่งออกรายงาน Purchase Request</h1>
          <p className="text-[13px] text-ink-500 mt-1">กรองข้อมูล ตรวจสอบ Preview แล้วดาวน์โหลดเป็น Excel</p>
        </div>
        <Button icon="download" onClick={onExport} disabled={previewRows.length === 0}>
          ส่งออก Excel ({previewRows.length} แถว)
        </Button>
      </div>

      <div className="grid grid-cols-4 gap-4">
        {/* Left: Filter panel */}
        <div className="col-span-1 bg-white border border-ink-200 rounded-2xl p-4 self-start sticky top-4">
          <div className="text-[13px] font-bold text-ink-800 mb-3">ตัวเลือกการส่งออก</div>

          <div className="text-[10.5px] uppercase tracking-wider text-ink-500 font-semibold mb-1">ขอบเขต</div>
          <div className="space-y-1 mb-3 text-[12px] text-ink-700"><div>· ส่งออกทั้งหมด (All PR)</div><div>· ตามตัวกรองด้านล่าง</div><div>· ตามสถานะที่เลือก</div><div>· ตามช่วงวันที่</div></div>

          <div className="text-[10.5px] uppercase tracking-wider text-ink-500 font-semibold mb-1.5">ระดับข้อมูล</div>
          <Segmented value={level} onChange={setLevel} options={[
            { value:"header", label:"PR Header" }, { value:"lines", label:"PR Line Items" }
          ]}/>

          <div className="mt-4 text-[10.5px] uppercase tracking-wider text-ink-500 font-semibold mb-1.5">ตัวกรอง</div>

          <div className="space-y-2.5 text-[12px]">
            <div>
              <div className="text-[11px] text-ink-500 mb-0.5">สถานะ</div>
              <select value={filter.status} onChange={e=>setFilter(f=>({ ...f, status:e.target.value }))} className="w-full h-9 px-2.5 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus">
                <option value="__all__">ทุกสถานะ</option>
                {Object.entries(PR_STATUS_META).map(([k,m]) => <option key={k} value={k}>{m.label}</option>)}
              </select>
            </div>
            <div className="grid grid-cols-2 gap-2">
              <div><div className="text-[11px] text-ink-500 mb-0.5">ตั้งแต่</div><ThaiDateInput value={filter.date_from} onChange={v=>setFilter(f=>({...f, date_from:v}))}/></div>
              <div><div className="text-[11px] text-ink-500 mb-0.5">ถึง</div><ThaiDateInput value={filter.date_to} onChange={v=>setFilter(f=>({...f, date_to:v}))}/></div>
            </div>
            <div>
              <div className="text-[11px] text-ink-500 mb-0.5">แผนกผู้ขอ</div>
              <select value={filter.requester_dept} onChange={e=>setFilter(f=>({ ...f, requester_dept:e.target.value }))} className="w-full h-9 px-2.5 text-[12.5px] bg-white border border-ink-200 rounded-lg focus:border-brand-500 ring-focus">
                <option value="__all__">ทุกแผนก</option>
                {deptOptions.map(d => <option key={d}>{d}</option>)}
              </select>
            </div>
            <div>
              <div className="text-[11px] text-ink-500 mb-0.5">ชื่อผู้ขอ (ค้นหา)</div>
              <Input value={filter.requester_name} onChange={e=>setFilter(f=>({...f, requester_name:e.target.value}))} placeholder="ค้นหา..."/>
            </div>
            <div className="grid grid-cols-2 gap-2">
              <div><div className="text-[11px] text-ink-500 mb-0.5">มูลค่าตั้งแต่</div><Input type="number" min="0" value={filter.amount_from} onChange={e=>setFilter(f=>({...f, amount_from:e.target.value}))} className="font-mono"/></div>
              <div><div className="text-[11px] text-ink-500 mb-0.5">ถึง</div><Input type="number" min="0" value={filter.amount_to} onChange={e=>setFilter(f=>({...f, amount_to:e.target.value}))} className="font-mono"/></div>
            </div>
          </div>

          <Button variant="secondary" icon="refresh" className="mt-4 w-full" onClick={reset}>รีเซ็ตตัวกรอง</Button>
        </div>

        {/* Right: Preview */}
        <div className="col-span-3">
          <div className="bg-white border border-ink-200 rounded-2xl overflow-hidden">
            <div className="flex items-center justify-between px-4 py-3 border-b border-ink-100">
              <div>
                <div className="text-[13px] font-bold text-ink-800">Preview รายงาน</div>
                <div className="text-[11.5px] text-ink-500">ตัวอย่าง {Math.min(20, previewRows.length)} แถวแรกของรายงาน · ระดับ {level === "header" ? "PR Header" : "PR Line Items"}</div>
              </div>
              <div className="text-[11px] text-ink-500">{previewRows.length} แถว</div>
            </div>
            <div className="overflow-x-auto">
              <table className="w-full text-[11.5px]">
                <thead className="bg-ink-50 text-ink-500 text-[10.5px] uppercase">
                  <tr>
                    {level === "header"
                      ? ["PR NO","วันที่","ผู้ขอ","แผนก","ผู้อนุมัติ","วัตถุประสงค์","กำหนดต้องการ","มูลค่ารวม","สถานะ"].map(h => <th key={h} className="text-left px-3 py-2 whitespace-nowrap">{h}</th>)
                      : ["PR NO","วันที่","ผู้ขอ","แผนก","ผู้อนุมัติ","ITEM CODE","ITEM NAME","จำนวน","หน่วย","ราคา","รวม","สถานะ"].map(h => <th key={h} className="text-left px-3 py-2 whitespace-nowrap">{h}</th>)
                    }
                  </tr>
                </thead>
                <tbody>
                  {loading && <tr><td colSpan={12} className="text-center py-10 text-ink-400">กำลังโหลด…</td></tr>}
                  {!loading && previewRows.length === 0 && <tr><td colSpan={12} className="text-center py-10 text-ink-400">ไม่พบข้อมูลตามเงื่อนไข</td></tr>}
                  {!loading && previewRows.slice(0, 20).map((r, i) => (
                    <tr key={i} className="border-t border-ink-100 hover:bg-ink-50/60">
                      {level === "header" ? (
                        <>
                          <td className="px-3 py-2 font-mono text-brand-700">{r.pr_number}</td>
                          <td className="px-3 py-2">{formatThaiDate(r.pr_date)}</td>
                          <td className="px-3 py-2">{r.requester}</td>
                          <td className="px-3 py-2">{r.requester_dept}</td>
                          <td className="px-3 py-2">{r.approver}</td>
                          <td className="px-3 py-2 truncate-1 max-w-[160px]" title={r.purpose}>{r.purpose}</td>
                          <td className="px-3 py-2">{formatThaiDate(r.required_date)}</td>
                          <td className="px-3 py-2 text-right font-mono font-semibold">{fmtMoney(r.total_amount)}</td>
                          <td className="px-3 py-2"><PRStatusPill status={Object.keys(PR_STATUS_META).find(k => PR_STATUS_META[k].label === r.status) || "draft"}/></td>
                        </>
                      ) : (
                        <>
                          <td className="px-3 py-2 font-mono text-brand-700">{r.pr_number}</td>
                          <td className="px-3 py-2">{formatThaiDate(r.pr_date)}</td>
                          <td className="px-3 py-2">{r.requester}</td>
                          <td className="px-3 py-2">{r.requester_dept}</td>
                          <td className="px-3 py-2">{r.approver}</td>
                          <td className="px-3 py-2 font-mono">{r.item_code}</td>
                          <td className="px-3 py-2 truncate-1 max-w-[160px]">{r.item_name}</td>
                          <td className="px-3 py-2 text-right font-mono">{Number(r.quantity||0).toLocaleString()}</td>
                          <td className="px-3 py-2">{r.unit}</td>
                          <td className="px-3 py-2 text-right font-mono">{fmtMoney(r.unit_price)}</td>
                          <td className="px-3 py-2 text-right font-mono font-semibold">{fmtMoney(r.line_total)}</td>
                          <td className="px-3 py-2"><PRStatusPill status={Object.keys(PR_STATUS_META).find(k => PR_STATUS_META[k].label === r.status) || "draft"}/></td>
                        </>
                      )}
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

// Expose pages on window for workspace.jsx to render lazily
window.ItemMasterPage = ItemMasterPage;
window.PurchaseRequestListPage = PurchaseRequestListPage;
window.CreatePRPage = CreatePRPage;
window.MyApprovalsPage = MyApprovalsPage;
window.PRReportsPage = PRReportsPage;
