/* global React, I, UI, SSSData */
const { useState: useStateP2, useEffect: useEffectP2 } = React;

// ============ Storage helpers ============
// ย่อชื่อพนักงานแบบสั้น (สอดคล้องรูปแบบ seed)
function prShortName(name) { const p = String(name || "").trim().split(/\s+/); return p.length > 1 ? `${p[0]} ${p[1][0]}.` : (p[0] || "—"); }
// วันที่ปัจจุบันจริง (พ.ศ.) — กันใช้วันที่ hardcode
const PR_MONTHS_TH = ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."];
function prTodayThai() { const d = new Date(); return `${d.getDate()} ${PR_MONTHS_TH[d.getMonth()]} ${d.getFullYear() + 543}`; }
function prThaiPeriod() { const d = new Date(); return `${PR_MONTHS_TH[d.getMonth()]} ${d.getFullYear() + 543}`; }
function prTodayISO() { const d = new Date(); d.setHours(12, 0, 0, 0); return d.toISOString().slice(0, 10); }
function prIsoToThai(iso) { if (!iso) return ""; const [y, m, d] = iso.split("-").map(Number); return `${d} ${PR_MONTHS_TH[m - 1]} ${y + 543}`; }
// สร้างแถวเงินเดือนตั้งต้นจากข้อมูลพนักงาน (สำหรับคนที่ยังไม่มีใน payroll)
function basePayrollRow(e) {
  const base = e.salary || 0;
  const hourly = e.hourly || 0;
  const stdHours = base ? 0 : (hourly ? 176 : 0);
  const gross = base || (hourly * stdHours);
  const sso = e.sso ? Math.min(Math.round(gross * 0.05), 750) : 0;
  return { emp: e.id, name: prShortName(e.name), base, hours: stdHours, otHours: 0, gross, advance: 0, late: 0, sso, tax: 0, net: gross - sso };
}
// โหลดรายการเงินเดือน + เติมพนักงานที่เพิ่มใหม่ให้มีแถวเสมอ (พนักงานใหม่เข้าระบบคำนวณเงินเดือน)
function loadPayroll() {
  let seed;
  try { seed = JSON.parse(localStorage.getItem("sss-payroll") || "null"); } catch {}
  seed = seed || window.SSSData.PayrollRows || [];
  const emps = (window.SSSData.Employees || []).filter(e => e.id !== "EMP-001" && e.status !== "ลาออก");
  const byId = {}; seed.forEach(r => { byId[r.emp] = r; });
  return emps.map(e => byId[e.id] || basePayrollRow(e));
}
function savePayroll(rows) { try { localStorage.setItem("sss-payroll", JSON.stringify(rows)); } catch {} window.SSSData.PayrollRows = rows; }
function loadTimeRecords() { try { return JSON.parse(localStorage.getItem("sss-timerecords") || "null") || window.SSSData.TimeRecords; } catch { return window.SSSData.TimeRecords; } }
function saveTimeRecords(rows) { try { localStorage.setItem("sss-timerecords", JSON.stringify(rows)); } catch {} window.SSSData.TimeRecords = rows; }
const advLogicalKey = (a) => String(((a && (a.empId || a.emp)) || "") + "|" + ((a && a.date) || "") + "|" + ((a && a.amount) || "") + "|" + ((a && a.reason) || ""));
function loadAdvances() {
  let list = [];
  try { list = JSON.parse(localStorage.getItem("sss-advances") || "null") || []; } catch {}
  // ล้างรายการซ้ำจากบั๊กเก่า (กดจ่ายแล้วเกิดสำเนาสถานะเดิม) — เก็บตัวที่สถานะไปไกลสุด
  const rank = (st) => st === "จ่ายแล้ว" ? 3 : st === "อนุมัติแล้ว" ? 2 : 1;
  const seen = new Map();
  list.forEach(a => {
    const k = advLogicalKey(a);
    const cur = seen.get(k);
    if (!cur || rank(a.status) > rank(cur.status)) seen.set(k, a);
  });
  const out = [...seen.values()];
  if (out.length !== list.length) { try { localStorage.setItem("sss-advances", JSON.stringify(out)); } catch {} }
  return out;
}
function saveAdvances(list) { try { localStorage.setItem("sss-advances", JSON.stringify(list)); } catch {} }
function loadPayHistory() {
  try { return JSON.parse(localStorage.getItem("sss-pay-history") || "null") || []; } catch { return []; }
}
function savePayHistory(list) { try { localStorage.setItem("sss-pay-history", JSON.stringify(list)); } catch {} }

// วันที่คำนวนล่าสุด (ประทับบนเอกสารทุกฉบับ)
function thaiNowStamp() {
  const d = new Date();
  return d.toLocaleDateString("th-TH", { day: "numeric", month: "short", year: "numeric" }) + " " + d.toLocaleTimeString("th-TH", { hour: "2-digit", minute: "2-digit" }) + " น.";
}
function loadCalcDate() { try { return localStorage.getItem("sss-payroll-calcdate") || thaiNowStamp(); } catch { return thaiNowStamp(); } }
function saveCalcDate(s) { try { localStorage.setItem("sss-payroll-calcdate", s); } catch {} }

// ============ Payroll ============
function Payroll({ navigate }) {
  const D = window.SSSData;
  const { Btn, Badge, Card, PageHead, Tabs, Drawer, fmt0, fmtM, bahtText } = window.UI;
  const [tab, setTab] = useStateP2("calc");
  const [active, setActive] = useStateP2(null);
  const [rows, setRows] = useStateP2(loadPayroll);
  const [timeRecs, setTimeRecs] = useStateP2(loadTimeRecords);
  const [advances, setAdvances] = useStateP2(loadAdvances);
  const [showTimeAdd, setShowTimeAdd] = useStateP2(false);
  const [showAdvAdd, setShowAdvAdd] = useStateP2(false);
  const [historyDetail, setHistoryDetail] = useStateP2(null);
  const [selectedAdv, setSelectedAdv] = useStateP2(new Set());
  const [advPay, setAdvPay] = useStateP2(null); // { items: [...] } — อนุมัติ+จ่าย เลือกบัญชี
  const [advCollapsed, setAdvCollapsed] = useStateP2(new Set()); // วันที่ถูกพับ
  const [payRound, setPayRound] = useStateP2("full"); // full | first | second
  const [month, setMonth] = useStateP2(() => new Date().toISOString().slice(0, 7)); // ตัวกรองเดือน — ดีฟอลต์เดือนปัจจุบัน
  const [calcDate, setCalcDate] = useStateP2(loadCalcDate); // วันที่คำนวนล่าสุด
  const [ssoPct, setSsoPct] = useStateP2(() => { try { const v = parseFloat(localStorage.getItem("sss-sso-pct")); return isNaN(v) ? 5 : v; } catch { return 5; } });
  const setSsoPctSaved = (v) => { setSsoPct(v); try { localStorage.setItem("sss-sso-pct", String(v)); } catch {} };
  // SSO แบบ "กำหนดยอดเอง" — ยอดคงที่รวม (ssoFixed) หรือกำหนดรายคน (ssoEmp[empId]); ว่าง/0 = คิด % (สูงสุด 750)
  const [ssoFixed, setSsoFixed] = useStateP2(() => { try { const v = parseFloat(localStorage.getItem("sss-sso-fixed")); return isNaN(v) ? 0 : v; } catch { return 0; } });
  const setSsoFixedSaved = (v) => { const n = parseFloat(v) || 0; setSsoFixed(n); try { localStorage.setItem("sss-sso-fixed", String(n)); } catch {} };
  const [ssoEmp, setSsoEmp] = useStateP2(() => { try { return JSON.parse(localStorage.getItem("sss-sso-emp") || "{}"); } catch { return {}; } });
  const setSsoEmpSaved = (empId, v) => { setSsoEmp(prev => { const next = { ...prev }; if (v === "" || v == null) delete next[empId]; else next[empId] = parseFloat(v) || 0; try { localStorage.setItem("sss-sso-emp", JSON.stringify(next)); } catch {} return next; }); };
  // หักภาษี ณ ที่จ่าย รายพนักงาน — กำหนดยอดเอง (เว้นว่าง = ใช้ค่าเดิมของแถว/ไม่หัก) · ซิงค์ทุกเครื่อง
  const [whtEmp, setWhtEmp] = useStateP2(() => { try { return JSON.parse(localStorage.getItem("sss-wht-emp") || "{}"); } catch { return {}; } });
  const setWhtEmpSaved = (empId, v) => { setWhtEmp(prev => { const next = { ...prev }; if (v === "" || v == null) delete next[empId]; else next[empId] = parseFloat(v) || 0; try { localStorage.setItem("sss-wht-emp", JSON.stringify(next)); } catch {} return next; }); };
  const whtOf = (empId, fallback) => (whtEmp[empId] != null ? (Number(whtEmp[empId]) || 0) : (Number(fallback) || 0));
  const ssoAmount = (gross, enrolled, empId) => {
    if (!enrolled) return 0;
    if (empId && ssoEmp[empId] != null && ssoEmp[empId] !== "") return Math.min(Math.round(Number(ssoEmp[empId]) || 0), Math.round(gross));
    if (ssoFixed > 0) return Math.min(Math.round(ssoFixed), Math.round(gross));
    return Math.min(Math.round(gross * (Number(ssoPct) || 0) / 100), 750);
  };
  const [payAccountId, setPayAccountId] = useStateP2("SCB"); // บัญชีที่จ่ายค่าแรง
  const [payHistory, setPayHistory] = useStateP2(loadPayHistory);
  const [slogan, setSlogan] = useStateP2(() => { try { return localStorage.getItem("sss-payslip-slogan") || "ขยัน อดทน ซื่อสัตย์ — ทีมแข็งแรง บริษัทเติบโตไปด้วยกัน 💪"; } catch { return ""; } });
  useEffectP2(() => { try { localStorage.setItem("sss-payslip-slogan", slogan); } catch {} }, [slogan]);

  // ===== ตัวกรองเดือน =====
  const TH_M_P = ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."];
  const monthLabelOf = (ym) => { const [y, m] = ym.split("-").map(Number); return `${TH_M_P[m - 1]} ${y + 543}`; };
  const _curYear = new Date().getFullYear();
  const MONTH_OPTIONS = [_curYear - 1, _curYear].flatMap(y => Array.from({ length: 12 }, (_, i) => `${y}-${String(i + 1).padStart(2, "0")}`));
  const [mYear, mMon] = month.split("-").map(Number);
  const ML = monthLabelOf(month);
  const NML = monthLabelOf(mMon === 12 ? `${mYear + 1}-01` : `${mYear}-${String(mMon + 1).padStart(2, "0")}`);
  const lastD = new Date(mYear, mMon, 0).getDate();
  const isoOfRec = (t) => t.iso || (window.DocDates ? window.DocDates.toISO(t.date) : null) || "";
  const timeRecsMonth = timeRecs.filter(t => isoOfRec(t).startsWith(month));

  // ===== Semi-monthly pay rounds (จ่ายวันที่ 1 และ 16) =====
  const ROUND_INFO = {
    full:   { label: "ทั้งเดือน (2 รอบ)",      range: `1–${lastD} ${ML}`,  pay: `จ่าย 2 รอบ · 16 ${ML} และ 1 ${NML}`, payDate: `16 ${ML} / 1 ${NML}`, workdays: 22, slipPeriod: ML },
    first:  { label: "งวดต้นเดือน (1–15)",     range: `1–15 ${ML}`,  pay: `จ่ายวันที่ 16 ${ML}`,          payDate: `16 ${ML}`,          workdays: 11, slipPeriod: `1–15 ${ML}` },
    second: { label: `งวดท้ายเดือน (16–${lastD})`,   range: `16–${lastD} ${ML}`, pay: `จ่ายวันที่ 1 ${NML}`,          payDate: `1 ${NML}`,          workdays: 11, slipPeriod: `16–${lastD} ${ML}` },
  };
  const dayOf = (d) => { const m = String(d || "").match(/(\d{1,2})/); return m ? +m[1] : 0; };
  const advInRound = (a, round) => {
    if (round === "full") return true;
    const day = dayOf(a.date);
    return round === "first" ? day <= 15 : day >= 16;
  };
  // ===== คำนวนแถวเงินเดือนจาก "การลงเวลาจริง" ของเดือนที่เลือก =====
  // พนักงานรายชั่วโมง: ชม.ทำงาน + OT มาจากบันทึกลงเวลาของเดือนนั้น (ไม่มีลงเวลา = 0 — ไม่คิดเต็ม 176)
  // พนักงานเงินเดือนประจำ: ได้เงินเดือนเต็ม + OT ตามที่ลงเวลา (วันเงินออกตาม payDay ของแต่ละคน)
  const empById = {}; (D.Employees || []).forEach(e => { empById[e.id] = e; });
  // บางแถวเก่าอ้างพนักงานด้วยชื่อ/ชื่อย่อ (ไม่ใช่ id) → หาไม่เจอ เงินเดือนใหม่เลยไม่อัพเดท — เพิ่ม fallback จับคู่ด้วยชื่อ
  const empByName = {}; (D.Employees || []).forEach(e => { empByName[String(e.name || "").trim()] = e; empByName[prShortName(e.name)] = e; });
  const empOfRow = (r) => empById[r.emp] || empByName[String(r.name || "").trim()] || {};
  // ค่าเงินอาจถูกบันทึกเป็นข้อความมีคอมม่า ("15,000") → แปลงเป็นตัวเลขก่อนคำนวณเสมอ
  const numv = (v) => Number(String(v == null ? "" : v).replace(/[,\s฿]/g, "")) || 0;
  const timeAgg = {};
  const addAgg = (id, work, ot, lateMin) => { const a = timeAgg[id] || { work: 0, ot: 0, lateMin: 0 }; a.work += work || 0; a.ot += ot || 0; a.lateMin += lateMin || 0; timeAgg[id] = a; };
  const aggDays = {}; // empId|iso ที่นับแล้ว — กันนับซ้ำระหว่างลงเวลามือ + QR
  timeRecsMonth.forEach(t => {
    if (!t.emp) return;
    const iso = isoOfRec(t); const key = t.emp + "|" + iso;
    aggDays[key] = true;
    addAgg(t.emp, t.work, t.ot, t.late);
  });
  // รวมเวลาจาก QR ลงเวลา (ถ้ามี) ของเดือนนั้นด้วย — ถือเป็น "การลงเวลาจริง"
  try {
    const QD = window.QRTimeData, QC = window.QRClockData;
    const clocks = (QC && QC.clocks ? QC.clocks() : []) || [];
    const seen = {};
    clocks.forEach(c => {
      if (!c.empId || !c.date || !String(c.date).startsWith(month)) return;
      const key = c.empId + "|" + c.date;
      if (seen[key] || aggDays[key]) return; // ข้ามถ้ามีลงเวลามือของวันนั้นแล้ว
      seen[key] = true;
      const rec = QD && QD.dayRecord ? QD.dayRecord(c.empId, c.date) : null;
      if (rec && rec.found) addAgg(c.empId, rec.work, rec.ot, rec.late);
    });
  } catch (e) {}
  // เบิกล่วงหน้าของพนักงานแต่ละคน "ในเดือนที่เลือก" (อนุมัติแล้ว/จ่ายแล้ว) — ใช้หักจากเงินเดือนของเดือนนั้น
  const advIsoOf = (a) => a.iso || (window.DocDates ? window.DocDates.toISO(a.date) : "") || "";
  const monthAdvByEmp = {};
  advances.forEach(a => {
    if (!a.empId) return;
    if (a.status !== "อนุมัติแล้ว" && a.status !== "จ่ายแล้ว") return;
    const iso = advIsoOf(a);
    const periodMatch = !!(a.period && String(a.period).includes(ML));   // เทียบเดือนแบบไทย เช่น "มิ.ย. 2569"
    const isoMatch = iso ? iso.startsWith(month) : false;
    if (iso && !isoMatch && !periodMatch) return;      // มีวันที่ แต่ไม่ตรงเดือน (และ period ก็ไม่ตรง)
    if (!iso && a.period && !periodMatch) return;       // ไม่มีวันที่ แต่มี period และไม่ตรง
    monthAdvByEmp[a.empId] = (monthAdvByEmp[a.empId] || 0) + (a.amount || 0);
  });
  const isHourlyEmp = (e) => numv(e.salary) === 0 && numv(e.hourly) > 0;
  const calcRows = rows.map(r => {
    const e = empOfRow(r);
    const agg = timeAgg[(e.id || r.emp)] || timeAgg[r.emp] || { work: 0, ot: 0, lateMin: 0 };
    const otRate = numv(e.otRate);
    const isHourly = isHourlyEmp(e);
    const otHours = Math.round(agg.ot * 10) / 10;
    let base, hours, gross;
    if (isHourly) {
      base = 0;
      hours = Math.round(agg.work * 10) / 10;
      gross = Math.round(hours * numv(e.hourly) + otHours * otRate);
    } else {
      base = numv(e.salary) || numv(r.base);
      hours = 0;
      gross = Math.round(base + otHours * otRate);
    }
    const sso = ssoAmount(gross, (e.id ? e.sso : r.sso), r.emp);
    const advance = monthAdvByEmp[r.emp] || 0, late = r.late || 0, tax = whtOf(r.emp, r.tax);
    return { ...r, base, hours, otHours, gross, sso, advance, late, tax, payDay: e.payDay || r.payDay, net: gross - advance - late - sso - tax };
  });

  // Build the rows shown for the selected round.
  // • พนักงานเงินเดือนประจำ: จ่ายเต็มเดือน ณ "วันเงินออก" (ปกติสิ้นเดือน) — หักเบิกล่วงหน้าทั้งเดือน
  //   ไม่หารครึ่งตามรอบ (เงินออกวันที่ 31 = เงินเดือนเต็ม − เบิกวันที่ 1–31)
  // • พนักงานรายชั่วโมง: คิดตามชั่วโมงจริง แบ่งครึ่งตามรอบได้ (ต้น/ท้ายเดือน)
  const roundRows = (round) => {
    return calcRows.map(r => {
      const e = empOfRow(r);
      const monthAdv = monthAdvByEmp[r.emp] || 0;
      if (!isHourlyEmp(e)) {
        // เงินเดือนประจำ — จ่ายงวดเดียวตอนสิ้นเดือน (โผล่ในรอบ "ทั้งเดือน" และ "ท้ายเดือน")
        const paid = round === "full" || round === "second";
        const base = paid ? (r.base || 0) : 0;
        const gross = paid ? (r.gross || 0) : 0;
        const advance = paid ? monthAdv : 0;
        const sso = paid ? (r.sso || 0) : 0;
        const tax = paid ? (r.tax || 0) : 0;
        const late = paid ? (r.late || 0) : 0;
        return { ...r, base, gross, otHours: paid ? r.otHours : 0, advance, sso, tax, late, net: gross - advance - late - sso - tax };
      }
      // รายชั่วโมง
      if (round === "full") {
        const net = (r.gross || 0) - monthAdv - (r.late || 0) - (r.sso || 0) - (r.tax || 0);
        return { ...r, advance: monthAdv, net };
      }
      const base = Math.round((r.base || 0) / 2);
      const hours = Math.round((r.hours || 0) / 2);
      const otHours = Math.round(((r.otHours || 0) / 2) * 10) / 10;
      const gross = Math.round((r.gross || 0) / 2);
      const late = Math.round((r.late || 0) / 2);
      const advance = advances
        .filter(a => a.empId === r.emp && (a.status === "อนุมัติแล้ว" || a.status === "จ่ายแล้ว") && (advIsoOf(a) ? advIsoOf(a).startsWith(month) : true) && advInRound(a, round))
        .reduce((s, a) => s + a.amount, 0);
      const sso = round === "second" ? r.sso : 0;
      const tax = round === "second" ? r.tax : 0;
      const net = gross - advance - late - sso - tax;
      return { ...r, base, hours, otHours, gross, late, advance, sso, tax, net };
    });
  };
  const viewRows = roundRows(payRound);
  const RI = ROUND_INFO[payRound];

  // Bulk print advance withdrawal slip(s)
  const printAdvancesBulk = (items) => {
    if (!items || items.length === 0) return;
    const C = D.Company;
    const empById = {}; (D.Employees || []).forEach(e => { empById[e.id] = e; });
    const firstName = s => String(s || "").trim().split(/\s+/)[0];
    const findEmp = (a) => empById[a.empId]
      || (D.Employees || []).find(e => e.name === a.emp)
      || (D.Employees || []).find(e => firstName(e.name) && firstName(e.name) === firstName(a.emp));
    const bankOf = (a) => { const e = findEmp(a); return e && e.bankAcc ? e.bankAcc : "—"; };
    const bankName = (a) => { const e = findEmp(a); return e && e.bank ? e.bank : ""; };
    const totalAmount = items.reduce((s, a) => s + a.amount, 0);
    const docNo = "ADV-2569-" + String(Math.floor(Math.random() * 9000) + 1000);
    const today = prTodayThai();
    const preparer = (window.Session && window.Session.get && window.Session.get() && window.Session.get().name) || (D.Company && D.Company.currentUser && D.Company.currentUser.name) || "";

    const html = `<div style="background:white;color:#0c0a09;padding:32px 40px;min-height:90vh;border-top:5px solid #9f1239">
      <div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:22px">
        <div style="display:flex;gap:14px;align-items:center">
          <div style="width:54px;height:54px;background:#0c0a09;color:white;display:grid;place-items:center;font-weight:700;font-size:17px;border-radius:5px">SSS</div>
          <div>
            <div style="font-weight:700;font-size:14px">${C.name}</div>
            <div style="font-size:10.5px;color:#57534e;margin-top:3px;max-width:320px">${C.address}</div>
            <div style="font-size:10.5px;color:#57534e">โทร ${C.phone} · เลขผู้เสียภาษี ${C.taxId}</div>
          </div>
        </div>
        <div style="text-align:right">
          <h1 style="margin:0;font-size:24px;color:#9f1239;font-weight:700">ใบเบิกเงินล่วงหน้า</h1>
          <div style="font-size:10.5px;color:#78716c;letter-spacing:0.08em;margin-top:2px">ADVANCE WITHDRAWAL FORM</div>
          <div style="margin-top:12px;padding:8px 14px;background:rgba(159,19,57,0.08);border-radius:4px;font-size:11px">
            <div>เลขที่ <b style="font-family:monospace">${docNo}</b></div>
            <div>วันที่ <b>${today}</b></div>
            <div>จำนวนรายการ <b>${items.length} คน</b></div>
          </div>
        </div>
      </div>

      <table style="width:100%;border-collapse:collapse;margin-top:14px">
        <thead>
          <tr style="background:#9f1239;color:white">
            <th style="padding:10px 8px;font-size:10.5px;text-align:center;width:30px;border-radius:4px 0 0 0">#</th>
            <th style="padding:10px 12px;font-size:10.5px;text-align:left">วันที่ขอเบิก</th>
            <th style="padding:10px 12px;font-size:10.5px;text-align:left">ผู้ขอเบิก</th>
            <th style="padding:10px 12px;font-size:10.5px;text-align:left">ธนาคาร</th>
            <th style="padding:10px 12px;font-size:10.5px;text-align:left">เลขที่บัญชี</th>
            <th style="padding:10px 12px;font-size:10.5px;text-align:left">เหตุผล / รายละเอียด</th>
            <th style="padding:10px 12px;font-size:10.5px;text-align:right;width:120px;border-radius:0 4px 0 0">จำนวนเงิน (บาท)</th>
          </tr>
        </thead>
        <tbody>
          ${items.map((a, i) => `
            <tr style="${i % 2 === 0 ? 'background:white' : 'background:#fafaf9'}">
              <td style="padding:11px 8px;border-bottom:1px solid #f1efeb;text-align:center;font-size:11.5px;color:#78716c">${i+1}</td>
              <td style="padding:11px 12px;border-bottom:1px solid #f1efeb;font-size:11.5px">${a.date}</td>
              <td style="padding:11px 12px;border-bottom:1px solid #f1efeb;font-size:12px;font-weight:500">${a.emp}</td>
              <td style="padding:11px 12px;border-bottom:1px solid #f1efeb;font-size:11px;color:#44403c">${bankName(a) || "—"}</td>
              <td style="padding:11px 12px;border-bottom:1px solid #f1efeb;font-size:11px;font-family:monospace;color:#0c0a09">${bankOf(a)}</td>
              <td style="padding:11px 12px;border-bottom:1px solid #f1efeb;font-size:11.5px;color:#44403c">${a.reason}</td>
              <td style="padding:11px 12px;border-bottom:1px solid #f1efeb;text-align:right;font-size:12px;font-weight:600">${a.amount.toLocaleString()}</td>
            </tr>
          `).join("")}
          <tr style="background:#f7f6f4">
            <td colspan="6" style="padding:12px;text-align:right;font-weight:700;font-size:13px">รวมเป็นเงิน</td>
            <td style="padding:12px;text-align:right;font-weight:700;font-size:14px">${totalAmount.toLocaleString()}</td>
          </tr>
        </tbody>
      </table>

      <div style="margin-top:18px;padding:10px 14px;background:#9f1239;color:white;border-radius:5px;display:flex;justify-content:space-between;align-items:center">
        <span style="font-size:12px">จำนวนเงินรวมทั้งสิ้น</span>
        <span style="font-size:18px;font-weight:700;font-variant-numeric:tabular-nums">฿ ${totalAmount.toLocaleString()}</span>
      </div>
      <div style="padding:6px 14px;font-size:10.5px;color:#57534e;font-style:italic;text-align:right">(${bahtText(totalAmount)})</div>

      <div style="margin-top:18px;padding:10px 14px;background:#fefdf9;border:1px solid #f1efeb;border-radius:4px;font-size:11px;color:#44403c;line-height:1.6">
        <b style="color:#0c0a09">เงื่อนไข:</b> ยอดเบิกล่วงหน้าทั้งหมดจะถูกหักจากเงินเดือนของพนักงานในงวดที่ระบุ · พนักงานที่เบิกขอรับเงินสด/โอน หลังจากเอกสารได้รับอนุมัติเรียบร้อย
      </div>

      <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:30px;margin-top:54px;font-size:11px">
        <div style="text-align:center"><div style="border-top:1px dashed #57534e;padding-top:6px;margin-top:40px"><b>ผู้จัดทำ</b><div style="color:#78716c;font-size:10px;margin-top:2px">${preparer ? preparer + " · " : ""}${today}</div></div></div>
        <div style="text-align:center"><div style="border-top:1px dashed #57534e;padding-top:6px;margin-top:40px"><b>หัวหน้าฝ่าย</b><div style="color:#78716c;font-size:10px;margin-top:2px">วันที่ ____________</div></div></div>
        <div style="text-align:center"><div style="border-top:1px dashed #57534e;padding-top:6px;margin-top:40px"><b>ผู้อนุมัติ</b><div style="color:#78716c;font-size:10px;margin-top:2px">วันที่ ____________</div></div></div>
      </div>

      <div style="margin-top:30px;padding-top:8px;border-top:2px solid #9f1239;font-size:9.5px;color:#78716c;display:flex;justify-content:space-between">
        <span>${C.name} · ${C.website}</span>
        <span>${docNo} · ออกโดยระบบ SSS</span>
      </div>
    </div>`;

    document.getElementById("__print_modal")?.remove();
    document.body.classList.remove("printing-modal");
    const modal = document.createElement("div");
    modal.id = "__print_modal";
    modal.className = "print-modal";
    modal.innerHTML = `
      <div class="print-modal-bar no-print">
        <div style="font-weight:600;font-size:14px;flex:1">พิมพ์ใบเบิกเงินล่วงหน้า — ${items.length} รายการ · ฿${totalAmount.toLocaleString()}</div>
        <button id="__print_close" class="pm-btn pm-btn-ghost">ปิด</button>
        <button id="__print_btn" class="pm-btn pm-btn-primary">🖨 พิมพ์</button>
      </div>
      <div class="print-modal-paper">${html}</div>
    `;
    document.body.appendChild(modal);
    document.body.classList.add("printing-modal");
    const cleanup = () => { modal.remove(); document.body.classList.remove("printing-modal"); };
    modal.addEventListener("click", e => { if (e.target === modal) cleanup(); });
    document.getElementById("__print_btn").addEventListener("click", () => window.print());
    document.getElementById("__print_close").addEventListener("click", cleanup);
  };

  useEffectP2(() => savePayroll(rows), [rows]);
  useEffectP2(() => saveTimeRecords(timeRecs), [timeRecs]);
  useEffectP2(() => saveAdvances(advances), [advances]);

  // อนุมัติ + จ่ายเบิกล่วงหน้า: หักจากบัญชีที่เลือก + สร้างใบสำคัญรับเงินอัตโนมัติ
  const approveAndPay = (items, accountId) => {
    const acc = (window.CompanyCashStore && window.CompanyCashStore.ACCOUNTS || []).find(a => a.id === accountId);
    const accLabel = acc ? (acc.kind === "เงินสด" ? "💵 เงินสด" : "🏦 โอน · " + acc.short) : "";
    const keys = new Set(items.map(it => it.empId + "_" + it.date));
    // กันจ่าย/สร้างเอกสารซ้ำ — ใบเบิกที่มีใบสำคัญรับเงินหรือรายการหักบัญชีอยู่แล้ว จะไม่ทำซ้ำ
    const existingRVKeys = new Set((D.ReceiptVouchers || []).map(rv => rv.fromAdvance).filter(Boolean));
    const existingMvRefs = new Set((((window.CompanyCashStore && window.CompanyCashStore.load()) || {}).movements || []).map(m => m.ref).filter(Boolean));
    let total = 0, made = 0, skipped = 0;
    const next = advances.map(a => {
      const key = a.empId + "_" + a.date;
      if (!keys.has(key) || a.status !== "รออนุมัติ") return a;
      if (a.rvNo || existingRVKeys.has(key) || existingMvRefs.has("ADV-" + key)) {
        // เคยจ่าย/มีเอกสารแล้ว — แค่ปรับสถานะ ไม่สร้างซ้ำ
        skipped++;
        return { ...a, status: "จ่ายแล้ว", accountId: a.accountId || accountId, accountName: (a.accountName || (acc ? acc.name : "")) };
      }
      total += a.amount; made++;
      let mvId = null, rvNo = null;
      if (window.CompanyCashStore) {
        mvId = window.CompanyCashStore.addMovement({ accountId, direction: "out", amount: a.amount, desc: `เบิกล่วงหน้า ${a.emp}`, ref: "ADV-" + key, source: "เบิกล่วงหน้า" });
      }
      const purpose = `เบิกเงินล่วงหน้า · ${a.reason || a.emp}`.replace(/ · $/, "");
      if (window.DocCreateStore && window.nextRVNo) {
        rvNo = window.nextRVNo();
        window.DocCreateStore.add("ReceiptVouchers", {
          no: rvNo, date: a.date, payee: a.emp, method: accLabel, accountId,
          payer: (window.Session && window.Session.get() && window.Session.get().name) || (D.Company.currentUser && D.Company.currentUser.name) || "",
          status: "จ่ายแล้ว", amount: a.amount, fromAdvance: key, purpose,
          lines: [{ desc: purpose, amount: a.amount }]
        });
      }
      return { ...a, status: "จ่ายแล้ว", accountId, accountName: acc ? acc.name : "", mvId, rvNo };
    });
    setAdvances(next);
    if (window.CompanyCashStore) window.dispatchEvent(new Event("sss-company-pay-changed"));
    window.logActivity && window.logActivity("อนุมัติ+จ่ายเบิกล่วงหน้า", `${made} รายการ · ฿${fmt0(total)} หักจาก ${acc ? acc.name : ""}`, "approve");
    window.toast && window.toast(`อนุมัติ ${made} รายการ · หัก ฿${fmt0(total)} จาก ${acc ? acc.short : ""}${skipped ? ` · ข้ามที่จ่ายแล้ว ${skipped}` : ""}`);
    setSelectedAdv(new Set());
    setAdvPay(null);
  };

  // กู้คืนใบเบิกจากใบสำคัญรับเงินที่ผูกไว้ (ใช้ตอนใบเบิกถูกลบ แต่ใบสำคัญรับเงินยังอยู่/กู้กลับมาแล้ว)
  const reconstructAdvances = () => {
    const rvs = (D.ReceiptVouchers || []).filter(rv => rv.fromAdvance);
    const have = new Set(advances.map(a => a.empId + "_" + a.date));
    const add = [];
    rvs.forEach(rv => {
      const key = rv.fromAdvance;
      if (have.has(key)) return;
      const sep = key.indexOf("_");
      const empId = sep >= 0 ? key.slice(0, sep) : "";
      const date = sep >= 0 ? key.slice(sep + 1) : (rv.date || "");
      const reason = String(rv.purpose || "").replace(/^เบิกเงินล่วงหน้า ·\s?/, "").trim() || "เบิกเงินล่วงหน้า";
      const iso = window.DocDates ? (window.DocDates.toISO(date) || "") : "";
      const period = iso ? `${PR_MONTHS_TH[(+iso.slice(5, 7)) - 1]} ${(+iso.slice(0, 4)) + 543}` : prThaiPeriod();
      add.push({ id: "ADV-" + Date.now().toString(36) + Math.random().toString(36).slice(2, 5), empId, emp: rv.payee, amount: rv.amount, date, iso, reason, status: "จ่ายแล้ว", accountId: rv.accountId, accountName: rv.accountName || "", rvNo: rv.no, period });
      have.add(key);
    });
    if (add.length === 0) { window.toast && window.toast("ไม่พบใบเบิกที่หาย — ลองกู้ใบสำคัญรับเงินจากคลาวด์ก่อน (เมนู \"กู้คืนเอกสาร\")"); return; }
    setAdvances([...add, ...advances]);
    window.logActivity && window.logActivity("กู้คืนใบเบิกจากใบสำคัญรับเงิน", `${add.length} รายการ`, "create");
    window.toast && window.toast(`กู้คืนใบเบิก ${add.length} รายการจากใบสำคัญรับเงินแล้ว`);
  };

  // Generic print modal for official payroll reports (ภ.ง.ด.1 / สปส.1-10)
  const printReport = (kind, period) => {
    const C = D.Company;
    const per = period || prThaiPeriod();
    const today = prTodayThai();
    const preparer = (window.Session && window.Session.get && window.Session.get() && window.Session.get().name) || (C.currentUser && C.currentUser.name) || "";
    const accent = kind === "pnd1" ? "#1e3a5f" : "#1f5f3a";
    const title = kind === "pnd1" ? "แบบ ภ.ง.ด.1" : "แบบ สปส.1-10";
    const subtitle = kind === "pnd1"
      ? "รายการภาษีเงินได้หัก ณ ที่จ่าย ตามมาตรา 59 (เงินเดือน/ค่าจ้าง)"
      : "รายการแสดงการส่งเงินสมทบกองทุนประกันสังคม";
    const docNo = (kind === "pnd1" ? "PND1-2569-" : "SPS-2569-") + String(Math.floor(Math.random() * 9000) + 1000);

    let headCols, bodyRows, totals;
    if (kind === "pnd1") {
      headCols = ["#", "ชื่อ-สกุล", "เลขประจำตัวผู้เสียภาษี", "เงินได้ (บาท)", "ภาษีหัก ณ ที่จ่าย (บาท)"];
      const totIncome = rows.reduce((s, r) => s + r.gross, 0);
      const totTax = rows.reduce((s, r) => s + r.tax, 0);
      bodyRows = rows.map((r, i) => {
        const emp = D.Employees.find(e => e.id === r.emp);
        const taxId = (emp && emp.taxId) || ("3-" + (1000 + i) + "-XXXXX-XX-" + (10 + i));
        return [i + 1, r.name, taxId, r.gross.toLocaleString(), r.tax > 0 ? r.tax.toLocaleString() : "0.00", i % 2];
      });
      totals = ["", "รวม " + rows.length + " ราย", "", totIncome.toLocaleString(), totTax.toLocaleString()];
    } else {
      headCols = ["#", "ชื่อ-สกุล", "ค่าจ้าง (บาท)", "สมทบลูกจ้าง 5%", "สมทบนายจ้าง 5%", "รวม (บาท)"];
      let tWage = 0, tEmp = 0, tEr = 0;
      bodyRows = rows.map((r, i) => {
        const wage = r.gross;
        const empC = r.sso;
        const erC = r.sso; // employer matches 5% (capped 750)
        tWage += wage; tEmp += empC; tEr += erC;
        return [i + 1, r.name, wage.toLocaleString(), empC.toLocaleString(), erC.toLocaleString(), (empC + erC).toLocaleString(), i % 2];
      });
      totals = ["", "รวม " + rows.length + " ราย", tWage.toLocaleString(), tEmp.toLocaleString(), tEr.toLocaleString(), (tEmp + tEr).toLocaleString()];
    }

    const colAlign = (idx) => idx === 0 ? "center" : (idx >= (kind === "pnd1" ? 3 : 2) ? "right" : "left");

    const html = `<div style="background:white;color:#0c0a09;padding:32px 40px;min-height:90vh;border-top:5px solid ${accent}">
      <div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:22px">
        <div style="display:flex;gap:14px;align-items:center">
          <div style="width:54px;height:54px;background:#0c0a09;color:white;display:grid;place-items:center;font-weight:700;font-size:17px;border-radius:5px">SSS</div>
          <div>
            <div style="font-weight:700;font-size:14px">${C.name}</div>
            <div style="font-size:10.5px;color:#57534e;margin-top:3px;max-width:340px">${C.address}</div>
            <div style="font-size:10.5px;color:#57534e">เลขประจำตัวผู้เสียภาษี ${C.taxId}</div>
          </div>
        </div>
        <div style="text-align:right">
          <h1 style="margin:0;font-size:23px;color:${accent};font-weight:700">${title}</h1>
          <div style="font-size:10.5px;color:#78716c;margin-top:2px;max-width:280px">${subtitle}</div>
          <div style="margin-top:12px;padding:8px 14px;background:${accent}14;border-radius:4px;font-size:11px">
            <div>เลขที่ <b style="font-family:monospace">${docNo}</b></div>
            <div>งวด <b>${per}</b></div>
            <div>คำนวนเมื่อ <b>${calcDate}</b></div>
            <div>ยื่นเมื่อ <b>${today}</b></div>
          </div>
        </div>
      </div>

      <table style="width:100%;border-collapse:collapse;margin-top:8px">
        <thead>
          <tr style="background:${accent};color:white">
            ${headCols.map((h, i) => `<th style="padding:9px 10px;font-size:10.5px;text-align:${colAlign(i)}">${h}</th>`).join("")}
          </tr>
        </thead>
        <tbody>
          ${bodyRows.map(r => `<tr style="${r[r.length-1] === 0 ? 'background:white' : 'background:#fafaf9'}">
            ${r.slice(0, -1).map((c, i) => `<td style="padding:9px 10px;border-bottom:1px solid #f1efeb;font-size:11.5px;text-align:${colAlign(i)};${i===1?'font-weight:500':''}">${c}</td>`).join("")}
          </tr>`).join("")}
          <tr style="background:#f3f1ee;font-weight:700">
            ${totals.map((c, i) => `<td style="padding:11px 10px;font-size:12px;text-align:${colAlign(i)}">${c}</td>`).join("")}
          </tr>
        </tbody>
      </table>

      <div style="display:grid;grid-template-columns:1fr 1fr;gap:40px;margin-top:54px;font-size:11px">
        <div style="text-align:center"><div style="border-top:1px dashed #57534e;padding-top:6px;margin-top:40px"><b>ผู้จัดทำ</b><div style="color:#78716c;font-size:10px;margin-top:2px">${preparer ? preparer + " · " : ""}${today}</div></div></div>
        <div style="text-align:center"><div style="border-top:1px dashed #57534e;padding-top:6px;margin-top:40px"><b>ผู้มีอำนาจลงนาม</b><div style="color:#78716c;font-size:10px;margin-top:2px">วันที่ ____________</div></div></div>
      </div>

      <div style="margin-top:30px;padding-top:8px;border-top:2px solid ${accent};font-size:9.5px;color:#78716c;display:flex;justify-content:space-between">
        <span>${C.name} · ${C.website || ""}</span>
        <span>${docNo} · ออกโดยระบบ SSS</span>
      </div>
    </div>`;

    document.getElementById("__print_modal")?.remove();
    document.body.classList.remove("printing-modal");
    const modal = document.createElement("div");
    modal.id = "__print_modal";
    modal.className = "print-modal";
    modal.innerHTML = `
      <div class="print-modal-bar no-print">
        <div style="font-weight:600;font-size:14px;flex:1">${title} — งวด ${per}</div>
        <button id="__print_close" class="pm-btn pm-btn-ghost">ปิด</button>
        <button id="__print_btn" class="pm-btn pm-btn-primary">🖨 พิมพ์ / บันทึก PDF</button>
      </div>
      <div class="print-modal-paper">${html}</div>
    `;
    document.body.appendChild(modal);
    document.body.classList.add("printing-modal");
    const cleanup = () => { modal.remove(); document.body.classList.remove("printing-modal"); };
    modal.addEventListener("click", e => { if (e.target === modal) cleanup(); });
    document.getElementById("__print_btn").addEventListener("click", () => window.print());
    document.getElementById("__print_close").addEventListener("click", cleanup);
    window.toast && window.toast(`ออก${title} งวด ${per} แล้ว`);
  };

  const totalGross = viewRows.reduce((s, r) => s + r.gross, 0);
  const totalNet = viewRows.reduce((s, r) => s + r.net, 0);
  const totalSSO = viewRows.reduce((s, r) => s + r.sso, 0);
  const totalTax = viewRows.reduce((s, r) => s + r.tax, 0);
  const totalAdvance = viewRows.reduce((s, r) => s + r.advance, 0);
  const totalLate = viewRows.reduce((s, r) => s + r.late, 0);

  // Recalculate all payroll rows
  const recalculate = async () => {
    const ok = await window.confirmDialog({
      title: "คำนวนเงินเดือนใหม่",
      message: "ระบบจะดึงข้อมูลล่าสุดมาคำนวน",
      bullets: [
        `ชั่วโมงทำงานรวม OT จากการลงเวลา (${timeRecs.length} วัน)`,
        "เบิกเงินล่วงหน้าที่อนุมัติแล้ว",
        "หักประกันสังคม 5% (สูงสุด 750 บาท)",
        "หัก ณ ที่จ่าย ภ.ง.ด.1"
      ],
      confirmText: "คำนวนใหม่"
    });
    if (!ok) return;
    const next = rows.map(r => {
      const emp = D.Employees.find(e => e.id === r.emp);
      if (!emp) return r;
      // Sum hours from time records
      const myTime = timeRecs.filter(t => t.emp === r.emp);
      const hours = myTime.reduce((s, t) => s + (t.work || 0), 0);
      const otHours = myTime.reduce((s, t) => s + (t.ot || 0), 0);
      const lateMin = myTime.reduce((s, t) => s + (t.late || 0), 0);
      // Calculate gross
      let gross;
      if (emp.salary > 0) {
        gross = emp.salary + otHours * (emp.otRate || 0);
      } else {
        gross = (hours > 0 ? hours : r.hours) * (emp.hourly || 0) + otHours * (emp.otRate || 0);
      }
      // ประกันสังคม — กำหนดยอดเอง หรือคิด % (สูงสุด 750)
      const sso = ssoAmount(gross, emp.sso, r.emp);
      // Late deduction = lateMin / 60 × hourly
      const lateAmount = lateMin > 0 ? Math.round((lateMin / 60) * (emp.hourly || (emp.salary / 22 / 8))) : r.late;
      // Advance = อนุมัติในงวด + ยอดเบิกที่กรอกในตารางลงเวลา
      const periodAdv = advances.filter(a => a.empId === r.emp && (a.status === "อนุมัติแล้ว" || a.status === "จ่ายแล้ว") && ((advIsoOf(a) ? advIsoOf(a).startsWith(month) : false) || (a.period && String(a.period).includes(ML)))).reduce((s, a) => s + a.amount, 0);
      const timeAdv = myTime.reduce((s, t) => s + (Number(t.advance) || 0), 0);
      const advAmount = periodAdv + timeAdv;
      const tax = whtOf(r.emp, r.tax);
      const net = gross - sso - tax - advAmount - lateAmount;
      return { ...r, hours: hours || r.hours, otHours: otHours || r.otHours, gross, sso, advance: advAmount, late: lateAmount, net };
    });
    setRows(next);
    const stamp = thaiNowStamp();
    setCalcDate(stamp);
    saveCalcDate(stamp);
    window.logActivity && window.logActivity("คำนวนเงินเดือน", `งวด ${ML} · คำนวนเมื่อ ${stamp}`, "update");
    window.toast && window.toast("คำนวนเงินเดือนใหม่แล้ว · " + stamp);
  };

  const bulkTransfer = async () => {
    const payAccts = (window.CompanyCashStore && window.CompanyCashStore.ACCOUNTS) || [];
    const acc = payAccts.find(a => a.id === payAccountId) || { name: "ธ.ไทยพาณิชย์", short: "SCB" };
    const ok = await window.confirmDialog({
      title: `จ่ายเงินเดือน — ${RI.label}`,
      message: `<b class="mono">จ่ายรวม ฿${fmt0(totalNet)} ไปยังพนักงาน ${viewRows.length} คน</b><br/>รอบ ${RI.range} · จ่ายจาก <b>${acc.name}</b>`,
      bullets: [
        `ตัดยอดเงินออกจากบัญชี ${acc.short} ในหน้าบัญชีธนาคาร`,
        "ดาวน์โหลดไฟล์ Bulk Transfer (.xlsx) สำหรับอัปโหลดเข้า K-Cyber Banking",
        "บันทึกใบสำคัญจ่าย PV-2569-XXXX อัตโนมัติ",
        "ส่ง pay slip ให้พนักงานทุกคนทางอีเมล",
        "อัปเดตสถานะรอบเป็น 'จ่ายแล้ว'"
      ],
      confirmText: "จ่ายเงินเดือน",
      cancelText: "ยกเลิก"
    });
    if (!ok) return;
    if (window.CompanyCashStore && window.CompanyCashStore.addMovement) {
      window.CompanyCashStore.addMovement({
        accountId: payAccountId, direction: "out", amount: totalNet,
        desc: `จ่ายเงินเดือน ${RI.label} — พนักงาน ${viewRows.length} คน`, ref: "PAYROLL", source: "คำนวนเงินเดือน"
      });
    }
    const histEntry = {
      id: "PAY-" + Date.now(),
      month, monthLabel: ML, round: payRound, roundLabel: RI.label,
      payDate: RI.payDate, paidAt: thaiNowStamp(),
      count: viewRows.length, gross: totalGross,
      deduct: totalSSO + totalTax + totalAdvance + totalLate,
      net: totalNet, accountId: payAccountId, accountName: acc.short,
    };
    const nextHist = [histEntry, ...payHistory];
    setPayHistory(nextHist);
    savePayHistory(nextHist);
    window.logActivity && window.logActivity("จ่ายเงินเดือน", `${RI.label} ฿${fmt0(totalNet)} จาก${acc.short}`, "approve");
    window.toast && window.toast(`จ่ายเงินเดือน ฿${fmt0(totalNet)} จาก${acc.name} (${RI.label}) แล้ว — ตัดยอดบัญชีให้อัตโนมัติ`);
  };

  const exportExcel = () => {
    // Generate CSV
    const headers = ["รหัส", "ชื่อ", "เงินเดือน", "ชม.ทำงาน", "ชม. OT", "รวมรายได้", "เบิกล่วงหน้า", "มาสาย", "SSO", "หักภาษี", "สุทธิ"];
    const csvRows = [headers.join(",")];
    viewRows.forEach(r => {
      csvRows.push([r.emp, r.name, r.base, r.hours, r.otHours, r.gross, r.advance, r.late, r.sso, r.tax, r.net].join(","));
    });
    const blob = new Blob(["\uFEFF" + csvRows.join("\n")], { type: "text/csv;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a"); a.href = url; a.download = `payroll-${payRound}-${new Date().toISOString().slice(0,10)}.csv`; a.click();
    URL.revokeObjectURL(url);
    window.toast && window.toast(`ส่งออก Excel (${RI.label}) แล้ว`);
  };

  const printAllSlips = () => {
    if (viewRows.length === 0) return;
    // Render all slips into a modal
    const C = D.Company;
    const slipsHTML = viewRows.map((row, i) => {
      const emp = D.Employees.find(e => e.id === row.emp);
      return `
        <div style="${i > 0 ? 'page-break-before:always;' : ''}background:white;color:#0c0a09;padding:30px 36px;min-height:90vh">
          <div style="display:flex;justify-content:space-between;border-bottom:1px solid #e7e5e4;padding-bottom:12px;margin-bottom:16px">
            <div style="display:flex;align-items:center;gap:10px">
              <div style="width:36px;height:36px;background:#0c0a09;color:white;display:grid;place-items:center;font-weight:700;border-radius:5px">SSS</div>
              <div><div style="font-weight:600;font-size:13px">${C.name}</div><div style="font-size:10.5px;color:#78716c">เลขผู้เสียภาษี ${C.taxId}</div></div>
            </div>
            <div style="text-align:right"><h1 style="margin:0;font-size:18px">ใบจ่ายเงินเดือน</h1><div style="font-size:11px;color:#57534e">PAY SLIP · งวด ${RI.slipPeriod}</div><div style="font-size:10px;color:#78716c;margin-top:2px">คำนวนเมื่อ ${calcDate} · พิมพ์เมื่อ ${thaiNowStamp()}</div></div>
          </div>
          <div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:14px;font-size:12px">
            <div><div style="font-size:10px;color:#78716c">พนักงาน</div><div style="font-weight:600">${emp?.name}</div></div>
            <div><div style="font-size:10px;color:#78716c">รหัส / แผนก</div><div>${emp?.id} · ${emp?.dept}</div></div>
            <div><div style="font-size:10px;color:#78716c">ตำแหน่ง</div><div>${emp?.role}</div></div>
            <div><div style="font-size:10px;color:#78716c">วันจ่าย</div><div>${RI.payDate}</div></div>
            <div><div style="font-size:10px;color:#78716c">วันที่คำนวน</div><div>${calcDate}</div></div>
          </div>
          <div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px">
            <div>
              <div style="font-size:11px;font-weight:600;text-transform:uppercase;margin-bottom:6px">รายได้</div>
              <table style="width:100%;font-size:12px">
                <tr><td>เงินเดือน/ค่าจ้าง</td><td style="text-align:right">${(row.base > 0 ? row.base : row.hours * (emp?.hourly || 0)).toLocaleString()}</td></tr>
                <tr><td>OT (${row.otHours} ชม.)</td><td style="text-align:right">${(row.otHours * (emp?.otRate || 0)).toLocaleString()}</td></tr>
                <tr style="border-top:1px solid #e7e5e4;font-weight:600"><td style="padding:6px 0">รวม</td><td style="text-align:right">${row.gross.toLocaleString()}</td></tr>
              </table>
            </div>
            <div>
              <div style="font-size:11px;font-weight:600;text-transform:uppercase;margin-bottom:6px">รายการหัก</div>
              <table style="width:100%;font-size:12px">
                <tr><td>SSO 5%</td><td style="text-align:right">−${row.sso.toLocaleString()}</td></tr>
                <tr><td>ภ.ง.ด.1</td><td style="text-align:right">${row.tax > 0 ? '−'+row.tax.toLocaleString() : '—'}</td></tr>
                <tr><td>เบิกล่วงหน้า</td><td style="text-align:right">${row.advance > 0 ? '−'+row.advance.toLocaleString() : '—'}</td></tr>
                <tr><td>มาสาย</td><td style="text-align:right">${row.late > 0 ? '−'+row.late.toLocaleString() : '—'}</td></tr>
                <tr style="border-top:1px solid #e7e5e4;font-weight:600"><td style="padding:6px 0">รวม</td><td style="text-align:right">−${(row.sso+row.tax+row.advance+row.late).toLocaleString()}</td></tr>
              </table>
            </div>
          </div>
          <div style="border-top:2px solid #0c0a09;padding:12px 0;display:flex;justify-content:space-between;align-items:center">
            <div style="font-size:11px;color:#78716c">ยอดสุทธิจ่าย</div>
            <div style="font-size:22px;font-weight:600">฿${row.net.toLocaleString()}</div>
          </div>
        </div>
      `;
    }).join("");

    document.getElementById("__print_modal")?.remove();
    document.body.classList.remove("printing-modal");
    const modal = document.createElement("div");
    modal.id = "__print_modal";
    modal.className = "print-modal";
    modal.innerHTML = `
      <div class="print-modal-bar no-print">
        <div style="font-weight:600;font-size:14px;flex:1">พิมพ์ Pay Slip — ${rows.length} ใบ</div>
        <button id="__print_close" class="pm-btn pm-btn-ghost">ปิด</button>
        <button id="__print_btn" class="pm-btn pm-btn-primary">🖨 พิมพ์</button>
      </div>
      <div class="print-modal-paper">${slipsHTML}</div>
    `;
    document.body.appendChild(modal);
    document.body.classList.add("printing-modal");
    const cleanup = () => { modal.remove(); document.body.classList.remove("printing-modal"); };
    modal.addEventListener("click", e => { if (e.target === modal) cleanup(); });
    document.getElementById("__print_btn").addEventListener("click", () => window.print());
    document.getElementById("__print_close").addEventListener("click", cleanup);
  };

  const editLate = (empId, delta) => {
    setRows(rs => rs.map(r => r.emp === empId ? { ...r, late: Math.max(0, r.late + delta), net: r.net - delta } : r));
  };

  return (
    <>
      <PageHead title="คำนวนเงินเดือน · Payroll"
        sub={`เดือน ${ML} · ${RI.label} · ${RI.pay} · คำนวนล่าสุด ${calcDate}`}
        right={<>
          <select className="input" style={{width: 130, height: 34, fontSize: 13}} value={month} onChange={e => setMonth(e.target.value)} title="เลือกเดือน">
            {MONTH_OPTIONS.map(m => <option key={m} value={m}>{monthLabelOf(m)}</option>)}
          </select>
          <select className="input" style={{ width: 168, height: 34, fontSize: 12.5 }} value={payAccountId} onChange={e => setPayAccountId(e.target.value)} title="จ่ายค่าแรงจากบัญชี">
            {((window.CompanyCashStore && window.CompanyCashStore.ACCOUNTS) || []).map(a => <option key={a.id} value={a.id}>จ่ายจาก: {a.short}</option>)}
          </select>
          <label title="เปอร์เซ็นต์หักประกันสังคม (สูงสุด 750) — ปรับได้แล้วกดคำนวนใหม่" style={{ display: "flex", alignItems: "center", gap: 5, fontSize: 12.5, color: "var(--ink-2)", border: "1px solid var(--line)", borderRadius: 7, padding: "0 8px", height: 34, opacity: ssoFixed > 0 ? 0.5 : 1 }}>
            ปกส.
            <input className="input" type="number" step="0.1" min="0" value={ssoPct} onChange={e => setSsoPctSaved(e.target.value)} disabled={ssoFixed > 0} style={{ width: 52, height: 26, textAlign: "right", padding: "0 6px" }} />
            %
          </label>
          <label title="กำหนดยอดประกันสังคมเอง (บาท/คน) — ใส่ 0 เพื่อกลับไปคิดเป็น %" style={{ display: "flex", alignItems: "center", gap: 5, fontSize: 12.5, color: "var(--ink-2)", border: "1px solid var(--line)", borderRadius: 7, padding: "0 8px", height: 34 }}>
            หรือกำหนดเอง ฿
            <input className="input" type="number" step="1" min="0" value={ssoFixed || ""} placeholder="0" onChange={e => setSsoFixedSaved(e.target.value)} style={{ width: 64, height: 26, textAlign: "right", padding: "0 6px" }} />
          </label>
          <Btn icon={I.calc} kind="ghost" onClick={recalculate}>คำนวนใหม่</Btn>
          <Btn icon={I.send} kind="primary" onClick={bulkTransfer}>จ่ายเงินเดือน</Btn>
        </>}/>

      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 14, padding: "8px 12px", background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: 8 }}>
        <span style={{ fontSize: 13 }}>📢</span>
        <span style={{ fontSize: 12.5, color: "var(--ink-3)", whiteSpace: "nowrap" }}>คำขวัญปลุกใจ (พิมพ์บนใบจ่ายเงิน)</span>
        <input className="input" value={slogan} onChange={e => setSlogan(e.target.value)} placeholder="เช่น ขยันวันนี้ เพื่อพรุ่งนี้ที่ดีกว่า" style={{ flex: 1, height: 32, fontSize: 12.5 }}></input>
      </div>

      <div className="grid cols-5 mb-lg">
        <window.UI.Stat label="พนักงาน" value={`${rows.length} คน`} sub="ใน 5 แผนก" icon={I.user}/>
        <window.UI.Stat label="ค่าจ้างขั้นต้น" value={`฿${fmt0(totalGross)}`} sub="รวม OT" icon={I.payroll}/>
        <window.UI.Stat label="หักประกันสังคม" value={`฿${fmt0(totalSSO)}`} sub="นายจ้างสมทบเท่ากัน" icon={I.shield}/>
        <window.UI.Stat label="หัก ณ ที่จ่าย" value={`฿${fmt0(totalTax)}`} sub="ส่งกรมสรรพากร" icon={I.tax}/>
        <window.UI.Stat label="ยอดสุทธิจ่าย" value={`฿${fmt0(totalNet)}`} sub="โอนเข้าบัญชีพนักงาน" icon={I.money}/>
      </div>

      <Tabs items={[
        { key: "calc", label: "คำนวนเงินเดือน" },
        { key: "time", label: "ลงเวลา / OT", count: timeRecsMonth.length },
        { key: "daily", label: "ลงเวลารายวัน" },
        { key: "late", label: "การมาสาย / ขาดงาน" },
        { key: "advance", label: "เบิกล่วงหน้า", count: advances.filter(a => { const iso = advIsoOf(a); return !iso || iso.startsWith(month); }).length },
        { key: "history", label: "ประวัติการจ่าย" }
      ]} active={tab} onChange={setTab}/>

      {tab === "calc" && (
        <Card flush>
          <div style={{padding: 12, borderBottom: "1px solid var(--line)", display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap"}}>
            <div style={{display: "flex", alignItems: "center", gap: 8}}>
              <span className="label" style={{color: "var(--ink-3)"}}>รอบจ่าย:</span>
              <div className="payseg">
                {[["full", "ทั้งเดือน"], ["first", "ต้นเดือน (1–15)"], ["second", "ท้ายเดือน (16–31)"]].map(([k, lbl]) => (
                  <button key={k} className={"payseg-btn" + (payRound === k ? " active" : "")} onClick={() => setPayRound(k)}>{lbl}</button>
                ))}
              </div>
            </div>
            <div className="label" style={{color: "var(--ink-3)"}}>ช่วง <b style={{color: "var(--ink-1)"}}>{RI.range}</b> · วันทำงาน <b style={{color: "var(--ink-1)"}}>{RI.workdays} วัน</b> · {RI.pay}</div>
            <span className="spacer"/>
            <span style={{fontSize: 11.5, color: "var(--ink-3)", display: "inline-flex", alignItems: "center", gap: 5, padding: "4px 10px", background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: 99}}>
              <I.clock size={12}/>คำนวนล่าสุด <b style={{color: "var(--ink-1)"}}>{calcDate}</b>
            </span>
            <Btn size="sm" kind="ghost" icon={I.download} onClick={exportExcel}>ส่งออก Excel</Btn>
            <Btn size="sm" kind="ghost" icon={I.print} onClick={printAllSlips}>พิมพ์ Slip ทั้งหมด</Btn>
          </div>
          <div className="table-wrap">
            <table className="t">
              <thead>
                <tr>
                  <th>รหัส</th><th>ชื่อ</th>
                  <th className="right">เงินเดือน</th>
                  <th className="right">ชม.ทำงาน</th>
                  <th className="right">ชม. OT</th>
                  <th className="right">รวมรายได้</th>
                  <th className="right">เบิกล่วงหน้า</th>
                  <th className="right">มาสาย</th>
                  <th className="right">SSO</th>
                  <th className="right">หัก ณ ที่จ่าย</th>
                  <th className="right">สุทธิ</th>
                  <th></th>
                </tr>
              </thead>
              <tbody>
                {viewRows.map(r => (
                  <tr key={r.emp} className="row-clickable" onClick={() => setActive(r)}>
                    <td className="mono">{r.emp}</td>
                    <td>{r.name}</td>
                    <td className="right amount muted">{r.base > 0 ? `฿${fmt0(r.base)}` : `${D.Employees.find(e=>e.id===r.emp)?.hourly}/ชม.`}</td>
                    <td className="right amount">{r.hours || "—"}</td>
                    <td className="right amount">{r.otHours || "—"}</td>
                    <td className="right amount">฿{fmt0(r.gross)}</td>
                    <td className="right amount muted">{r.advance > 0 ? `−฿${fmt0(r.advance)}` : "—"}</td>
                    <td className="right amount muted" style={{color: r.late > 0 ? "var(--danger)" : "inherit"}}>{r.late > 0 ? `−฿${fmt0(r.late)}` : "—"}</td>
                    <td className="right" onClick={e => e.stopPropagation()}>
                      <input type="number" min="0" value={ssoEmp[r.emp] != null ? ssoEmp[r.emp] : ""} placeholder={fmt0(r.sso)}
                        onChange={e => setSsoEmpSaved(r.emp, e.target.value)} title="กำหนดยอดประกันสังคมเอง (เว้นว่าง = คิดอัตโนมัติ)"
                        style={{ width: 66, height: 26, textAlign: "right", border: "1px solid var(--line)", borderRadius: 6, padding: "0 6px", fontSize: 12.5, background: ssoEmp[r.emp] != null ? "color-mix(in oklab, var(--accent) 10%, var(--surface))" : "var(--surface)" }}/>
                    </td>
                    <td className="right" onClick={e => e.stopPropagation()}>
                      <input type="number" min="0" value={whtEmp[r.emp] != null ? whtEmp[r.emp] : ""} placeholder={r.tax > 0 ? fmt0(r.tax) : "0"}
                        onChange={e => setWhtEmpSaved(r.emp, e.target.value)} title="หักภาษี ณ ที่จ่าย (เว้นว่าง = ไม่หัก)"
                        style={{ width: 66, height: 26, textAlign: "right", border: "1px solid var(--line)", borderRadius: 6, padding: "0 6px", fontSize: 12.5, background: whtEmp[r.emp] != null ? "color-mix(in oklab, var(--warning) 12%, var(--surface))" : "var(--surface)" }}/>
                    </td>
                    <td className="right amount" style={{fontWeight: 600}}>฿{fmt0(r.net)}</td>
                    <td onClick={e=>e.stopPropagation()}><Btn kind="ghost" size="sm" icon={I.print} onClick={() => setActive(r)}/></td>
                  </tr>
                ))}
                <tr style={{background: "var(--surface-2)", fontWeight: 600}}>
                  <td colSpan={5} style={{textAlign: "right"}}>รวมทั้งหมด</td>
                  <td className="right amount">฿{fmt0(totalGross)}</td>
                  <td className="right amount">−฿{fmt0(totalAdvance)}</td>
                  <td className="right amount">−฿{fmt0(totalLate)}</td>
                  <td className="right amount">−฿{fmt0(totalSSO)}</td>
                  <td className="right amount">−฿{fmt0(totalTax)}</td>
                  <td className="right amount" style={{fontSize: 15}}>฿{fmt0(totalNet)}</td>
                  <td></td>
                </tr>
              </tbody>
            </table>
          </div>
        </Card>
      )}

      {tab === "time" && (
        <>
          {window.PayrollQRImport && <window.PayrollQRImport timeRecs={timeRecs} setTimeRecs={setTimeRecs} month={month} setMonth={setMonth}/>}
          {window.PayrollTimeTab
            ? <window.PayrollTimeTab timeRecs={timeRecs} setTimeRecs={setTimeRecs} month={month}/>
            : <TimeScheduleBuilder timeRecs={timeRecs} setTimeRecs={setTimeRecs}/>}
        </>
      )}

      {tab === "daily" && <PayrollDailyTab/>}

      {tab === "late" && window.PayrollAttendanceTab && (
        <window.PayrollAttendanceTab timeRecs={timeRecs} month={month}/>
      )}

      {tab === "advance" && (() => {
        // แสดงเฉพาะใบเบิกของ "เดือนที่เลือก" (ให้ตรงกับตัวเลือกเดือนด้านบน) — อ่านวันที่ไม่ออกก็แสดงไว้ก่อน
        const monthAdvances = advances.filter(a => { const iso = advIsoOf(a); return !iso || iso.startsWith(month); });
        const selItems = monthAdvances.filter(a => selectedAdv.has(a.empId + "_" + a.date));
        const selPending = selItems.filter(a => a.status === "รออนุมัติ");
        // จัดกลุ่มตามวัน (เรียงตามลำดับที่พบ)
        const dayGroups = [];
        monthAdvances.forEach(a => {
          let g = dayGroups.find(x => x.date === a.date);
          if (!g) { g = { date: a.date, rows: [] }; dayGroups.push(g); }
          g.rows.push(a);
        });
        const delAdv = async (a) => {
          const ok = await window.confirmDelete(`ใบเบิก ${a.emp}`, `จำนวน ฿${fmt0(a.amount)} · เหตุผล: ${a.reason}${a.rvNo ? " · ลบใบสำคัญรับเงิน " + a.rvNo + " + คืนยอดบัญชีด้วย" : ""}`);
          if (!ok) return;
          // ลบให้ลิงค์กันทั้งระบบ: คืนยอดบัญชี (movement) + ลบใบสำคัญรับเงินที่ผูกไว้
          if (a.mvId && window.CompanyCashStore) { window.CompanyCashStore.removeMovement(a.mvId); window.dispatchEvent(new Event("sss-company-pay-changed")); }
          if (a.rvNo && window.DocCreateStore && window.DocCreateStore.remove) { window.DocCreateStore.remove("ReceiptVouchers", a.rvNo); window.dispatchEvent(new Event("sss-docs-changed")); }
          setAdvances(advances.filter(x => !(x.empId === a.empId && x.date === a.date)));
        };
        return (
        <Card title={`คำขอเบิกเงินล่วงหน้า — ${ML}`} flush right={<>
          {selItems.length > 0 ? (
            <>
              <span style={{fontSize: 12, color: "var(--ink-3)", padding: "0 6px"}}>เลือก {selItems.length} รายการ</span>
              <Btn size="sm" kind="ghost" onClick={() => setSelectedAdv(new Set())}>ยกเลิก</Btn>
              {selPending.length > 0 && <Btn size="sm" kind="primary" icon={I.check} onClick={() => setAdvPay({ items: selPending })}>อนุมัติ+จ่าย ({selPending.length})</Btn>}
              <Btn size="sm" icon={I.print} kind="ghost" onClick={() => printAdvancesBulk(selItems)}>พิมพ์ที่เลือก ({selItems.length})</Btn>
            </>
          ) : <>
              {(() => {
                const have = new Set(advances.map(a => a.empId + "_" + a.date));
                const missing = (D.ReceiptVouchers || []).filter(rv => rv.fromAdvance && !have.has(rv.fromAdvance)).length;
                return missing > 0 ? <Btn size="sm" icon={I.download} kind="ghost" onClick={reconstructAdvances}>กู้ใบเบิกจากใบสำคัญรับเงิน ({missing})</Btn> : null;
              })()}
              <Btn size="sm" icon={I.print} kind="ghost" onClick={() => printAdvancesBulk(monthAdvances)} disabled={monthAdvances.length === 0}>พิมพ์ทั้งหมด</Btn>
              <Btn size="sm" icon={I.plus} kind="primary" onClick={() => setShowAdvAdd(true)}>บันทึกการเบิก</Btn>
            </>}
        </>}>
          <div style={{ display: "flex", flexDirection: "column", gap: 10, padding: 12 }}>
            {monthAdvances.length === 0 && <div style={{padding: 26, textAlign: "center", color: "var(--ink-3)", fontSize: 13}}>ยังไม่มีคำขอเบิกของ {ML} — กด "บันทึกการเบิก"</div>}
            {dayGroups.map(g => {
              const dayTotal = g.rows.reduce((s, r) => s + r.amount, 0);
              const dayKeys = g.rows.map(r => r.empId + "_" + r.date);
              const allSel = dayKeys.every(k => selectedAdv.has(k));
              const pend = g.rows.filter(r => r.status === "รออนุมัติ");
              const collapsed = advCollapsed.has(g.date);
              return (
                <div key={g.date} style={{ border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden", background: "var(--surface)" }}>
                  {/* หัวกลุ่มวัน — คลิกเพื่อพับ/ขยาย */}
                  <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 14px", background: "var(--surface-2)", cursor: "pointer" }}
                    onClick={() => { const n = new Set(advCollapsed); collapsed ? n.delete(g.date) : n.add(g.date); setAdvCollapsed(n); }}>
                    <input type="checkbox" checked={allSel} onClick={e => e.stopPropagation()} onChange={e => {
                      const next = new Set(selectedAdv);
                      if (e.target.checked) dayKeys.forEach(k => next.add(k)); else dayKeys.forEach(k => next.delete(k));
                      setSelectedAdv(next);
                    }}/>
                    <I.chevronDown size={15} style={{ transform: collapsed ? "rotate(-90deg)" : "none", transition: "transform .15s", color: "var(--ink-3)", flexShrink: 0 }}/>
                    <span style={{ fontWeight: 700, fontSize: 13 }}>📅 {g.date}</span>
                    <span style={{ fontSize: 11.5, color: "var(--ink-3)" }}>· {g.rows.length} รายการ</span>
                    {pend.length > 0 && <span className="badge warning" style={{ fontSize: 10 }}>{pend.length} รออนุมัติ</span>}
                    <span style={{ flex: 1 }}/>
                    <b className="amount" style={{ fontSize: 14 }}>฿{fmt0(dayTotal)}</b>
                    {pend.length > 0 && <Btn size="sm" kind="primary" icon={I.check} onClick={e => { e.stopPropagation(); setAdvPay({ items: pend }); }}>อนุมัติ+จ่ายทั้งวัน</Btn>}
                  </div>
                  {/* รายการพนักงานในวัน */}
                  {!collapsed && g.rows.map((a, i) => {
                    const key = a.empId + "_" + a.date;
                    return (
                      <div key={key + i} style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 14px", borderTop: "1px solid var(--line-soft)" }}>
                        <input type="checkbox" checked={selectedAdv.has(key)} onChange={() => {
                          const next = new Set(selectedAdv);
                          if (next.has(key)) next.delete(key); else next.add(key);
                          setSelectedAdv(next);
                        }}/>
                        {window.RankAvatar ? <window.RankAvatar name={a.emp} size={28}/> : null}
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ fontSize: 13, fontWeight: 500 }}>{a.emp}</div>
                          <div style={{ fontSize: 11, color: "var(--ink-3)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                            {a.reason}
                            {a.accountId && window.CompanyCashStore ? " · หัก " + window.CompanyCashStore.accShort(a.accountId) : ""}
                            {a.rvNo ? <> · <span className="mono" style={{ color: "var(--brand)", cursor: "pointer" }} onClick={() => navigate("receipt-vouchers/" + a.rvNo)}>{a.rvNo}</span></> : null}
                          </div>
                        </div>
                        <b className="amount" style={{ fontSize: 13.5, minWidth: 78, textAlign: "right" }}>฿{fmt0(a.amount)}</b>
                        <div style={{ minWidth: 150, display: "flex", justifyContent: "flex-end" }}>
                          {a.status === "รออนุมัติ"
                            ? <div style={{ display: "flex", gap: 4 }}>
                                <Btn size="sm" kind="primary" onClick={() => setAdvPay({ items: [a] })}>อนุมัติ+จ่าย</Btn>
                                <Btn size="sm" kind="ghost" onClick={() => { setAdvances(advances.map(x => (x.empId === a.empId && x.date === a.date) ? { ...x, status: "ปฏิเสธ" } : x)); window.logActivity && window.logActivity("ปฏิเสธ", `ใบเบิก ${a.emp}`, "approve"); }}>ปฏิเสธ</Btn>
                              </div>
                            : <Badge tone={(a.status === "อนุมัติแล้ว" || a.status === "จ่ายแล้ว") ? "success" : a.status === "ปฏิเสธ" ? "danger" : "outline"} dot>{a.status}{a.status === "จ่ายแล้ว" && a.accountName ? " · " + (window.CompanyCashStore ? window.CompanyCashStore.accShort(a.accountId) : a.accountName) : ""}</Badge>}
                        </div>
                        <Btn size="sm" kind="ghost" icon={I.print} onClick={() => printAdvancesBulk([a])} title="พิมพ์ใบเบิก"/>
                        <Btn size="sm" kind="ghost" icon={I.trash} onClick={() => delAdv(a)}/>
                      </div>
                    );
                  })}
                </div>
              );
            })}
          </div>
        </Card>
        );
      })()}

      {tab === "history" && (
        <Card title="ประวัติการจ่ายเงินเดือน — แยกตามใบจ่าย (ต้นเดือน / ท้ายเดือน)" sub="บริษัทจ่าย 2 รอบ · งวด 1–15 จ่ายวันที่ 16 · งวด 16–สิ้นเดือน จ่ายวันที่ 1 ของเดือนถัดไป" flush>
          {payHistory.length === 0 ? (
            <div style={{ padding: 40, textAlign: "center", color: "var(--ink-3)" }}>
              <div style={{ fontSize: 32, marginBottom: 10 }}>📋</div>
              <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 6 }}>ยังไม่มีประวัติการจ่ายเงิน</div>
              <div style={{ fontSize: 12.5 }}>กด "จ่ายเงินเดือน" ในแท็บคำนวนเงินเดือน เพื่อบันทึกรายการ</div>
            </div>
          ) : (
            <div className="table-wrap">
              <table className="t">
                <thead><tr><th>เดือน</th><th>รอบ</th><th>วันจ่าย</th><th>บัญชี</th><th className="right">จำนวนคน</th><th className="right">ยอดรวม</th><th className="right">หักรวม</th><th className="right">สุทธิ</th><th>สถานะ</th><th></th></tr></thead>
                <tbody>
                  {payHistory.map((h) => (
                    <tr key={h.id} className="row-clickable" onClick={() => setHistoryDetail({ period: `${h.roundLabel} · ${h.monthLabel}`, total: h.gross, net: h.net, deduct: h.deduct, count: h.count, payDate: h.paidAt })}>
                      <td style={{ fontWeight: 600 }}>{h.monthLabel}</td>
                      <td><span className={`badge ${h.round === "first" ? "info" : ""}`}>{h.roundLabel}</span></td>
                      <td>{h.payDate}</td>
                      <td className="muted">{h.accountName}</td>
                      <td className="right">{h.count}</td>
                      <td className="right amount">฿{fmt0(h.gross)}</td>
                      <td className="right amount">−฿{fmt0(h.deduct)}</td>
                      <td className="right amount" style={{ fontWeight: 600 }}>฿{fmt0(h.net)}</td>
                      <td><Badge tone="success">จ่ายแล้ว</Badge></td>
                      <td><Btn size="sm" kind="ghost" icon={I.search}>ดู</Btn></td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </Card>
      )}

      {/* Pay slip drawer */}
      <Drawer open={!!active} onClose={() => setActive(null)} title={active ? `ใบจ่ายเงินเดือน · ${active.name}` : ""} wide
        footer={<><Btn icon={I.send} kind="ghost" onClick={() => window.toast && window.toast("ส่งอีเมล pay slip ไปยังพนักงานแล้ว")}>ส่งทางอีเมล</Btn><Btn icon={I.print} kind="primary" onClick={() => window.printDocPaperWithOptions()}>พิมพ์</Btn></>}>
        {active && <PaySlip row={active} period={RI.slipPeriod} payDate={RI.payDate} calcDate={calcDate} slogan={slogan} timeRecs={timeRecs} advances={advances} month={month} round={payRound}/>}
      </Drawer>

      {showTimeAdd && <TimeAddModal onClose={() => setShowTimeAdd(false)} onSave={(t) => { setTimeRecs([t, ...timeRecs]); setShowTimeAdd(false); window.toast && window.toast("บันทึกเวลาแล้ว"); }}/>}
      {showAdvAdd && <AdvanceAddModal onClose={() => setShowAdvAdd(false)} onSave={async (a) => {
        // กันบันทึกซ้ำ: มีใบเบิกของพนักงานคนนี้ จำนวนเท่ากัน ที่ยังไม่จ่าย/วันเดียวกันอยู่แล้ว
        const dup = advances.find(x => x.empId === a.empId && x.amount === a.amount && (x.date === a.date || x.status === "รออนุมัติ"));
        if (dup) {
          const ok = await window.confirmDialog({ title: "อาจเป็นรายการซ้ำ", message: `มีใบเบิกของ <b>${a.emp}</b> จำนวน <b>฿${fmt0(a.amount)}</b> อยู่แล้ว (${dup.date} · ${dup.status})<br>ต้องการบันทึกเพิ่มอีกหรือไม่?`, confirmText: "บันทึกเพิ่ม", cancelText: "ยกเลิก" });
          if (!ok) return;
        }
        setAdvances([{ id: "ADV-" + Date.now().toString(36) + Math.random().toString(36).slice(2, 5), ...a, status: "รออนุมัติ", period: prThaiPeriod() }, ...advances]); setShowAdvAdd(false); window.toast && window.toast("บันทึกใบเบิกแล้ว");
      }}/>}
      {advPay && <AdvancePayModal items={advPay.items} onClose={() => setAdvPay(null)} onConfirm={approveAndPay}/>}

      <Drawer open={!!historyDetail} onClose={() => setHistoryDetail(null)} title={historyDetail ? "งวด " + historyDetail.period : ""}
        footer={<Btn kind="ghost" onClick={() => setHistoryDetail(null)}>ปิด</Btn>}>
        {historyDetail && (
          <div style={{display: "flex", flexDirection: "column", gap: 12}}>
            <div className="grid cols-2" style={{gap: 8}}>
              <div className="stat"><div className="label">วันจ่าย</div><div className="value" style={{fontSize: 14}}>{historyDetail.payDate}</div></div>
              <div className="stat"><div className="label">จำนวนพนักงาน</div><div className="value">{historyDetail.count} คน</div></div>
              <div className="stat"><div className="label">ยอดรวม (Gross)</div><div className="value">฿{fmt0(historyDetail.total)}</div></div>
              <div className="stat"><div className="label">หักรวม</div><div className="value">฿{fmt0(historyDetail.deduct)}</div></div>
            </div>
            <div className="stat" style={{background: "var(--success-bg)", border: "1px solid var(--success)"}}>
              <div className="label">ยอดสุทธิที่จ่าย</div>
              <div className="value" style={{color: "var(--success)"}}>฿{fmt0(historyDetail.net)}</div>
            </div>
            <Btn icon={I.download} onClick={() => { printAllSlips(); }}>ดาวน์โหลด pay slip รวม</Btn>
            <Btn icon={I.doc} onClick={() => printReport("pnd1", historyDetail.period)}>ออก ภ.ง.ด.1</Btn>
            <Btn icon={I.book} onClick={() => printReport("sps110", historyDetail.period)}>ออก สปส.1-10</Btn>
          </div>
        )}
      </Drawer>
    </>
  );
}

function TimeScheduleBuilder({ timeRecs, setTimeRecs }) {
  const D = window.SSSData;
  const { Btn, Badge, Card } = window.UI;
  const monthsTh = ["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค."];
  const dayNames = ["อา","จ","อ","พ","พฤ","ศ","ส"];

  // Time policy defaults — persisted
  const loadPolicy = () => {
    try { return JSON.parse(localStorage.getItem("sss-time-policy") || "null") || {
      defaultIn: "08:30",
      breakStart: "12:00",
      breakEnd: "13:00",
      defaultOut: "17:30",
      standardHours: 8,
      otMultiplier: 1.5,
      lateGraceMin: 5,
      lateDeductPerMin: 5
    }; } catch { return {}; }
  };
  const [policy, setPolicy] = useStateP2(loadPolicy);
  const [showPolicy, setShowPolicy] = useStateP2(false);

  React.useEffect(() => { localStorage.setItem("sss-time-policy", JSON.stringify(policy)); }, [policy]);

  const [empId, setEmpId] = useStateP2(D.Employees[2]?.id || D.Employees[0]?.id || "");
  const [startDate, setStartDate] = useStateP2("2026-05-01");
  const [endDate, setEndDate] = useStateP2("2026-05-31");
  const [schedule, setSchedule] = useStateP2([]);

  // กัน state ค้างจากรายชื่อพนักงานที่ถูกแก้/ลบ — ถ้า id ไม่อยู่ในลิสต์แล้ว รีเซ็ตเป็นคนแรก
  React.useEffect(() => {
    if (D.Employees.length && !D.Employees.some(e => e.id === empId)) {
      setEmpId(D.Employees[0].id);
    }
  }, [D.Employees.length]);

  const emp = D.Employees.find(e => e.id === empId);

  const STATUSES = [
    { key: "ทำงาน", emoji: "💼" },
    { key: "OT", emoji: "⏰" },
    { key: "วันหยุด", emoji: "🏖️" },
    { key: "ลา", emoji: "🌴" },
    { key: "ขาด", emoji: "❌" },
    { key: "นอกสถานที่", emoji: "🚗" }
  ];

  const fmtThai = (iso) => {
    const [y, m, d] = iso.split("-").map(Number);
    return `${d} ${monthsTh[m-1]} ${y + 543}`;
  };

  // Helpers
  const toMin = (t) => { if (!t) return 0; const [h, m] = t.split(":").map(Number); return h*60+m; };
  const breakMin = () => toMin(policy.breakEnd) - toMin(policy.breakStart);

  // Compute work/OT/late from in-out times, applying policy
  const computeFromTimes = (inT, outT) => {
    if (!inT || !outT) return { work: 0, ot: 0, late: 0, lateDeduct: 0 };
    const inM = toMin(inT), outM = toMin(outT);
    const stdInM = toMin(policy.defaultIn);
    let lateRaw = Math.max(0, inM - stdInM);
    // Grace period
    const lateMin = lateRaw > policy.lateGraceMin ? lateRaw : 0;
    const lateDeduct = lateMin * policy.lateDeductPerMin;
    const total = Math.max(0, outM - inM - breakMin()) / 60;
    let work = Math.min(total, policy.standardHours);
    let ot = Math.max(0, total - policy.standardHours);
    return { work: Math.round(work * 100) / 100, ot: Math.round(ot * 100) / 100, late: lateMin, lateDeduct };
  };

  const generateSchedule = () => {
    const effEmpId = D.Employees.some(e => e.id === empId) ? empId : (D.Employees[0]?.id || "");
    if (!effEmpId || !startDate || !endDate) { window.toast && window.toast("กรุณาเลือกพนักงานและช่วงวันที่"); return; }
    if (effEmpId !== empId) setEmpId(effEmpId);
    const effEmp = D.Employees.find(e => e.id === effEmpId);
    const s = new Date(startDate);
    const e = new Date(endDate);
    if (e < s) { window.toast && window.toast("วันสิ้นสุดต้องหลังวันเริ่ม"); return; }
    const days = [];
    const cur = new Date(s);
    while (cur <= e) {
      const dow = cur.getDay();
      const iso = cur.toISOString().slice(0, 10);
      const existing = timeRecs.find(t => t.iso === iso && t.emp === effEmpId);
      const isWeekend = dow === 0 || dow === 6;
      if (existing) {
        days.push(existing);
      } else {
        const calc = isWeekend ? { work: 0, ot: 0, late: 0 } : computeFromTimes(policy.defaultIn, policy.defaultOut);
        days.push({
          iso, emp: effEmpId, name: effEmp?.name,
          date: fmtThai(iso), dow,
          status: isWeekend ? "วันหยุด" : "ทำงาน",
          in: isWeekend ? "" : policy.defaultIn,
          out: isWeekend ? "" : policy.defaultOut,
          break: breakMin(),
          work: calc.work, ot: calc.ot, late: calc.late,
          offsiteDays: 0, note: ""
        });
      }
      cur.setDate(cur.getDate() + 1);
    }
    setSchedule(days);
    window.toast && window.toast(`สร้างตาราง ${days.length} วันแล้ว`);
  };

  const updateRow = (idx, patch) => {
    setSchedule(s => s.map((r, i) => {
      if (i !== idx) return r;
      const next = { ...r, ...patch };
      // Auto-recalc if in/out changed and status is ทำงาน or OT
      if ((patch.in !== undefined || patch.out !== undefined) && (next.status === "ทำงาน" || next.status === "OT")) {
        const calc = computeFromTimes(next.in, next.out);
        next.work = calc.work; next.ot = calc.ot; next.late = calc.late;
        if (next.ot > 0 && next.status === "ทำงาน") next.status = "OT";
      }
      return next;
    }));
  };

  const onStatusChange = (idx, status) => {
    const cur = schedule[idx];
    const patches = { status };
    if (status === "วันหยุด" || status === "ลา" || status === "ขาด") {
      patches.in = ""; patches.out = ""; patches.work = 0; patches.ot = 0; patches.late = 0;
    } else if (status === "นอกสถานที่") {
      patches.in = ""; patches.out = ""; patches.work = 0; patches.late = 0; patches.ot = 0;
      if (!cur.offsiteDays) patches.offsiteDays = 1;
    } else if (status === "OT") {
      const inT = cur.in || policy.defaultIn;
      const outT = cur.out || "20:00";
      patches.in = inT; patches.out = outT;
      const c = computeFromTimes(inT, outT);
      patches.work = c.work; patches.ot = c.ot; patches.late = c.late;
    } else if (status === "ทำงาน") {
      const inT = cur.in || policy.defaultIn;
      const outT = cur.out || policy.defaultOut;
      patches.in = inT; patches.out = outT;
      const c = computeFromTimes(inT, outT);
      patches.work = c.work; patches.ot = c.ot; patches.late = c.late;
    }
    updateRow(idx, patches);
  };

  const saveSchedule = () => {
    const merged = [...timeRecs];
    schedule.forEach(s => {
      const idx = merged.findIndex(t => t.iso === s.iso && t.emp === s.emp);
      if (idx >= 0) merged[idx] = s; else merged.unshift(s);
    });
    setTimeRecs(merged);
    window.toast && window.toast(`บันทึก ${schedule.length} วันของ ${emp?.name}`);
  };

  const summary = {
    workDays: schedule.filter(s => s.status === "ทำงาน" || s.status === "OT").length,
    otHours: schedule.reduce((a, s) => a + (s.ot || 0), 0),
    totalWork: schedule.reduce((a, s) => a + (s.work || 0), 0),
    leave: schedule.filter(s => s.status === "ลา").length,
    absent: schedule.filter(s => s.status === "ขาด").length,
    holiday: schedule.filter(s => s.status === "วันหยุด").length,
    offsite: schedule.reduce((a, s) => a + (s.offsiteDays || 0), 0),
    lateMin: schedule.reduce((a, s) => a + (s.late || 0), 0)
  };

  return (
    <>
      <Card title="สร้างตารางเวลาทำงานรายช่วง" sub="เลือกพนักงานและช่วงวันที่ → ระบบสร้างตารางมาให้กรอก" right={<Btn size="sm" kind="ghost" icon={I.cog} onClick={() => setShowPolicy(true)}>ตั้งค่าเวลา & OT</Btn>}>
        <div className="field-row cols-4">
          <div className="field"><label>พนักงาน</label>
            <select className="input" value={empId} onChange={e=>setEmpId(e.target.value)}>
              {D.Employees.map(e => <option key={e.id} value={e.id}>{e.id} · {e.name}</option>)}
            </select>
          </div>
          <div className="field"><label>วันที่เริ่ม</label><input className="input" type="date" value={startDate} onChange={e=>setStartDate(e.target.value)}/></div>
          <div className="field"><label>วันที่สิ้นสุด</label><input className="input" type="date" value={endDate} onChange={e=>setEndDate(e.target.value)}/></div>
          <div className="field" style={{display: "flex", flexDirection: "column", justifyContent: "flex-end"}}><Btn kind="primary" icon={I.calc} onClick={generateSchedule}>สร้างตาราง</Btn></div>
        </div>
        <div style={{marginTop: 10, padding: "8px 12px", background: "var(--info-bg)", color: "var(--info)", borderRadius: 6, fontSize: 12.5, display: "flex", gap: 14, flexWrap: "wrap"}}>
          <span>⚙️ <b>นโยบาย:</b></span>
          <span>เข้า {policy.defaultIn} · ออก {policy.defaultOut}</span>
          <span>พัก {policy.breakStart}-{policy.breakEnd}</span>
          <span>เกิน {policy.standardHours} ชม. = OT (×{policy.otMultiplier})</span>
          <span>สาย: อนุโลม {policy.lateGraceMin} นาที · เกิน หัก ฿{policy.lateDeductPerMin}/นาที</span>
        </div>
      </Card>

      {schedule.length > 0 && (
        <>
          <div className="grid cols-4" style={{gap: 8, margin: "14px 0"}}>
            <div className="stat"><div className="label">วันทำงาน</div><div className="value">{summary.workDays} วัน</div></div>
            <div className="stat"><div className="label">ชม.ทำงานรวม</div><div className="value">{summary.totalWork.toFixed(1)} ชม.</div></div>
            <div className="stat"><div className="label">OT รวม · เป็นเงิน</div><div className="value" style={{fontSize: 16}}>{summary.otHours.toFixed(1)} ชม. <span style={{fontSize: 12, color: "var(--ink-3)"}}>(×{policy.otMultiplier})</span></div></div>
            <div className="stat"><div className="label">ลา / ขาด / หยุด</div><div className="value" style={{fontSize: 14}}>{summary.leave} / {summary.absent} / {summary.holiday}</div></div>
          </div>
          {(summary.offsite > 0 || summary.lateMin > 0) && (
            <div style={{padding: "8px 12px", background: "var(--info-bg)", color: "var(--info)", borderRadius: 6, fontSize: 13, marginBottom: 14, display: "flex", gap: 16, flexWrap: "wrap"}}>
              {summary.offsite > 0 && <span>🚗 <b>นอกสถานที่:</b> {summary.offsite} วัน</span>}
              {summary.lateMin > 0 && <span>⏰ <b>มาสายรวม:</b> {summary.lateMin} นาที · หัก ฿{(summary.lateMin * policy.lateDeductPerMin).toLocaleString()}</span>}
            </div>
          )}

          <Card flush title={`ตารางเวลา · ${emp?.name} · ${schedule.length} วัน`}
            right={<>
              <Btn size="sm" kind="ghost" onClick={() => setSchedule([])}>ล้างตาราง</Btn>
              <Btn size="sm" kind="primary" icon={I.check} onClick={saveSchedule}>บันทึกตาราง</Btn>
            </>}>
            <div className="table-wrap">
              <table className="t" style={{fontSize: 13}}>
                <thead>
                  <tr>
                    <th style={{width: 40}}>วัน</th>
                    <th style={{width: 110}}>วันที่</th>
                    <th style={{width: 160}}>สถานะ</th>
                    <th style={{width: 95}}>เข้างาน</th>
                    <th style={{width: 95}}>เลิกงาน</th>
                    <th className="right" style={{width: 72}}>พัก<div style={{fontSize: 9, fontWeight: 400, color: "var(--ink-4)"}}>(นาที)</div></th>
                    <th className="right" style={{width: 80}}>ชม.</th>
                    <th className="right" style={{width: 78}}>OT</th>
                    <th className="right" style={{width: 78}}>สาย<div style={{fontSize: 9, fontWeight: 400, color: "var(--ink-4)"}}>(นาที)</div></th>
                    <th className="right" style={{width: 90}}>นอกสถานที่<div style={{fontSize: 9, fontWeight: 400, color: "var(--ink-4)"}}>(วัน)</div></th>
                  </tr>
                </thead>
                <tbody>
                  {schedule.map((r, i) => {
                    const isWeekend = r.dow === 0 || r.dow === 6;
                    const isOffsite = r.status === "นอกสถานที่";
                    const noTime = r.status === "วันหยุด" || r.status === "ลา" || r.status === "ขาด" || r.status === "นอกสถานที่";
                    const cellStyle = { height: 32, padding: "0 8px", fontSize: 12 };
                    const numCellStyle = { ...cellStyle, textAlign: "right" };
                    return (
                      <tr key={i} style={{background: isWeekend ? "var(--surface-2)" : "transparent"}}>
                        <td style={{textAlign: "center", color: isWeekend ? "var(--danger)" : "var(--ink-3)", fontWeight: isWeekend ? 600 : 400}}>{dayNames[r.dow]}</td>
                        <td style={{fontSize: 12}}>{r.date}</td>
                        <td>
                          <select className="input" style={cellStyle} value={r.status} onChange={e=>onStatusChange(i, e.target.value)}>
                            {STATUSES.map(s => <option key={s.key} value={s.key}>{s.emoji} {s.key}</option>)}
                          </select>
                        </td>
                        <td><input className="input mono" type="time" style={cellStyle} disabled={noTime} value={r.in} onChange={e=>updateRow(i, { in: e.target.value })}/></td>
                        <td><input className="input mono" type="time" style={cellStyle} disabled={noTime} value={r.out} onChange={e=>updateRow(i, { out: e.target.value })}/></td>
                        <td><input className="input" type="number" style={numCellStyle} disabled={noTime} value={r.break} onChange={e=>updateRow(i, { break: +e.target.value })}/></td>
                        <td><input className="input" type="number" step="0.25" style={numCellStyle} disabled={noTime} value={r.work} onChange={e=>updateRow(i, { work: +e.target.value })}/></td>
                        <td><input className="input" type="number" step="0.25" style={{...numCellStyle, color: r.ot > 0 ? "var(--info)" : "inherit", fontWeight: r.ot > 0 ? 600 : 400}} disabled={noTime} value={r.ot} onChange={e=>updateRow(i, { ot: +e.target.value })}/></td>
                        <td><input className="input" type="number" style={{...numCellStyle, color: r.late > 0 ? "var(--danger)" : "inherit"}} disabled={noTime} value={r.late} onChange={e=>updateRow(i, { late: +e.target.value })}/></td>
                        <td>
                          {isOffsite ? (
                            <input className="input" type="number" step="0.5" min="0" style={numCellStyle}
                              value={r.offsiteDays || 1} onChange={e=>updateRow(i, { offsiteDays: +e.target.value })}/>
                          ) : <div style={{color: "var(--ink-4)", fontSize: 12, textAlign: "right", paddingRight: 8}}>—</div>}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </Card>
        </>
      )}

      {schedule.length === 0 && (
        <Card title="ตารางเวลาที่บันทึกแล้ว" sub={`${timeRecs.length} รายการ`} flush>
          <div className="table-wrap">
            <table className="t">
              <thead><tr><th>วันที่</th><th>พนักงาน</th><th>สถานะ</th><th>เข้า</th><th>ออก</th><th className="right">ชม.</th><th className="right">OT</th><th className="right">สาย</th><th></th></tr></thead>
              <tbody>
                {timeRecs.slice(0, 30).map((t, i) => (
                  <tr key={i}>
                    <td>{t.date}</td>
                    <td>{t.name}</td>
                    <td><Badge>{t.status}</Badge></td>
                    <td className="mono">{t.in || "—"}</td>
                    <td className="mono">{t.out || "—"}</td>
                    <td className="right amount">{(t.work || 0).toFixed(1)}</td>
                    <td className="right amount">{t.ot > 0 ? t.ot.toFixed(1) : "—"}</td>
                    <td className="right amount" style={{color: t.late > 0 ? "var(--danger)" : "inherit"}}>{t.late > 0 ? t.late : "—"}</td>
                    <td><Btn size="sm" kind="ghost" icon={I.trash} onClick={async () => {
        const ok = await window.confirmDelete("ตารางเวลา " + t.date, t.name);
        if (!ok) return;
        setTimeRecs(timeRecs.filter((_, j) => j !== i));
        window.logActivity && window.logActivity("ลบ", "ตารางเวลา " + t.date + " ของ " + t.name, "delete");
      }}/></td>
                  </tr>
                ))}
                {timeRecs.length === 0 && <tr><td colSpan={9} style={{padding: 20, textAlign: "center", color: "var(--ink-3)"}}>ยังไม่มีตารางเวลา — สร้างตารางด้านบน</td></tr>}
              </tbody>
            </table>
          </div>
        </Card>
      )}

      {showPolicy && <PolicyModal policy={policy} setPolicy={setPolicy} onClose={() => setShowPolicy(false)}/>}
    </>
  );
}

function PolicyModal({ policy, setPolicy, onClose }) {
  const { Btn } = window.UI;
  const [f, setF] = useStateP2(policy);
  const upd = (k, v) => setF(p => ({ ...p, [k]: v }));
  return (
    <div className="scrim" style={{display:"flex",alignItems:"center",justifyContent:"center",padding:24,zIndex:200}} onClick={onClose}>
      <div style={{background: "var(--surface)", borderRadius: 12, padding: 20, width: 480, maxWidth: "94vw", boxShadow: "var(--shadow-lg)"}} onClick={e => e.stopPropagation()}>
        <div style={{fontSize: 15, fontWeight: 600, marginBottom: 4}}>⚙️ ตั้งค่าเวลาทำงาน & OT</div>
        <div style={{fontSize: 12, color: "var(--ink-3)", marginBottom: 16}}>ใช้เป็นค่า default เมื่อสร้างตารางใหม่ และคำนวน OT/มาสายอัตโนมัติ</div>

        <div style={{fontSize: 12, fontWeight: 600, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: 6}}>เวลาทำงานปกติ</div>
        <div className="field-row cols-2 mb">
          <div className="field"><label>เข้างาน</label><window.UI.TimeField value={f.defaultIn} onChange={v=>upd("defaultIn", v)}/></div>
          <div className="field"><label>เลิกงาน</label><window.UI.TimeField value={f.defaultOut} onChange={v=>upd("defaultOut", v)}/></div>
        </div>
        <div className="field-row cols-2 mb">
          <div className="field"><label>เริ่มพักเที่ยง</label><window.UI.TimeField value={f.breakStart} onChange={v=>upd("breakStart", v)}/></div>
          <div className="field"><label>เลิกพักเที่ยง</label><window.UI.TimeField value={f.breakEnd} onChange={v=>upd("breakEnd", v)}/></div>
        </div>

        <div style={{fontSize: 12, fontWeight: 600, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.04em", marginTop: 16, marginBottom: 6}}>OT (ล่วงเวลา)</div>
        <div className="field-row cols-2 mb">
          <div className="field"><label>ชั่วโมงทำงานมาตรฐาน (ต่อวัน)</label><input className="input" type="number" min="1" max="12" value={f.standardHours} onChange={e=>upd("standardHours", +e.target.value)}/></div>
          <div className="field"><label>OT คูณค่าแรง (เท่า)</label><input className="input" type="number" min="1" step="0.25" value={f.otMultiplier} onChange={e=>upd("otMultiplier", +e.target.value)}/></div>
        </div>
        <div style={{padding: "8px 10px", background: "var(--surface-2)", borderRadius: 6, fontSize: 11.5, color: "var(--ink-3)"}}>
          💡 ทำงานเกิน <b>{f.standardHours} ชม./วัน</b> → ส่วนเกินคิดเป็น OT (×{f.otMultiplier})
        </div>

        <div style={{fontSize: 12, fontWeight: 600, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.04em", marginTop: 16, marginBottom: 6}}>การมาสาย</div>
        <div className="field-row cols-2 mb">
          <div className="field"><label>อนุโลม (นาที)</label><input className="input" type="number" min="0" value={f.lateGraceMin} onChange={e=>upd("lateGraceMin", +e.target.value)}/></div>
          <div className="field"><label>หักนาทีละ (บาท)</label><input className="input" type="number" min="0" value={f.lateDeductPerMin} onChange={e=>upd("lateDeductPerMin", +e.target.value)}/></div>
        </div>
        <div style={{padding: "8px 10px", background: "var(--surface-2)", borderRadius: 6, fontSize: 11.5, color: "var(--ink-3)"}}>
          💡 มาสายไม่เกิน <b>{f.lateGraceMin} นาที</b> → ไม่หัก · เกินกว่านั้นหัก <b>฿{f.lateDeductPerMin}/นาที</b>
        </div>

        <div style={{display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 18}}>
          <Btn kind="ghost" onClick={onClose}>ยกเลิก</Btn>
          <Btn kind="primary" icon={I.check} onClick={() => { setPolicy(f); window.toast && window.toast("บันทึกการตั้งค่าแล้ว"); onClose(); }}>บันทึก</Btn>
        </div>
      </div>
    </div>
  );
}

function TimeAddModal({ onClose, onSave }) {
  const D = window.SSSData;
  const { Btn } = window.UI;
  const [f, setF] = useStateP2({ date: "22 พ.ค. 2569", emp: D.Employees[2]?.id, name: D.Employees[2]?.name, in: "08:00", out: "17:00", break: 60, work: 8, ot: 0, late: 0, status: "ปกติ" });
  const setEmp = (id) => {
    const e = D.Employees.find(emp => emp.id === id);
    setF(p => ({ ...p, emp: id, name: e?.name }));
  };
  return (
    <div className="scrim" style={{display:"flex",alignItems:"center",justifyContent:"center",padding:24,zIndex:200}} onClick={onClose}>
      <div style={{background: "var(--surface)", borderRadius: 12, padding: 18, width: 480, maxWidth: "92vw"}} onClick={e => e.stopPropagation()}>
        <div style={{fontSize: 15, fontWeight: 600, marginBottom: 14}}>บันทึกเวลาทำงาน</div>
        <div style={{display: "flex", flexDirection: "column", gap: 10}}>
          <div className="field-row cols-2">
            <div className="field"><label>วันที่</label><input className="input" value={f.date} onChange={e=>setF(p=>({...p, date: e.target.value}))}/></div>
            <div className="field"><label>พนักงาน</label>
              <select className="input" value={f.emp} onChange={e=>setEmp(e.target.value)}>
                {D.Employees.map(e => <option key={e.id} value={e.id}>{e.name}</option>)}
              </select>
            </div>
          </div>
          <div className="field-row cols-3">
            <div className="field"><label>เข้างาน</label><input className="input mono" value={f.in} onChange={e=>setF(p=>({...p, in: e.target.value}))}/></div>
            <div className="field"><label>เลิกงาน</label><input className="input mono" value={f.out} onChange={e=>setF(p=>({...p, out: e.target.value}))}/></div>
            <div className="field"><label>พัก (นาที)</label><input className="input" type="number" value={f.break} onChange={e=>setF(p=>({...p, break: +e.target.value}))}/></div>
          </div>
          <div className="field-row cols-3">
            <div className="field"><label>ชม.ทำงาน</label><input className="input" type="number" step="0.5" value={f.work} onChange={e=>setF(p=>({...p, work: +e.target.value}))}/></div>
            <div className="field"><label>OT (ชม.)</label><input className="input" type="number" step="0.5" value={f.ot} onChange={e=>setF(p=>({...p, ot: +e.target.value}))}/></div>
            <div className="field"><label>สาย (นาที)</label><input className="input" type="number" value={f.late} onChange={e=>setF(p=>({...p, late: +e.target.value, status: +e.target.value > 0 ? "สาย" : "ปกติ"}))}/></div>
          </div>
        </div>
        <div style={{display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 16}}>
          <Btn kind="ghost" onClick={onClose}>ยกเลิก</Btn>
          <Btn kind="primary" icon={I.check} onClick={() => onSave(f)}>บันทึก</Btn>
        </div>
      </div>
    </div>
  );
}

// ── สรุปการลงเวลารายวัน (ดึงจาก QR อัตโนมัติ) — เลือกช่วงวัน + พับได้ ──
function PayrollDailyTab() {
  const D = window.SSSData;
  const { Card, Badge, fmt0 } = window.UI;
  const [preset, setPreset] = useStateP2("today");
  const [expanded, setExpanded] = useStateP2(null); // Set ของวันที่ขยาย (null = ยังไม่ตั้ง)
  const [editRow, setEditRow] = useStateP2(null); // { emp, iso, st } กำลังแก้ไข
  const [, force] = useStateP2(0);
  useEffectP2(() => {
    const h = () => force(n => n + 1);
    const evts = ["sss-qrclock-polled", "sss-data-synced", "sss-clock-saved", "sss-timereq-polled"];
    evts.forEach(e => window.addEventListener(e, h));
    return () => evts.forEach(e => window.removeEventListener(e, h));
  }, []);

  const QC = window.QRClockData;
  const canEdit = (window.Perms ? window.Perms.level("payroll") === "ทั้งหมด" : true) || !!(window.Session && window.Session.get() && window.Session.get().isAdmin);
  const isoOf = d => { const x = new Date(d); x.setHours(12, 0, 0, 0); return x.toISOString().slice(0, 10); };
  const today = new Date(); today.setHours(12, 0, 0, 0);
  const thOf = (QC && QC.thaiOf) || (iso => iso);
  const clocks = QC && QC.clocks ? QC.clocks() : (D.QRClockRecords || []);
  const reqs = QC && QC.reqs ? QC.reqs() : (D.TimeRequests || []);
  const emps = (D.Employees || []).filter(e => e.id !== "EMP-001");

  // ช่วงวันที่ตาม preset (ใหม่→เก่า)
  const dates = [];
  const addRange = (from, to) => { const d = new Date(to); while (d >= from) { dates.push(isoOf(d)); d.setDate(d.getDate() - 1); } };
  if (preset === "today") dates.push(isoOf(today));
  else if (preset === "yesterday") { const y = new Date(today); y.setDate(y.getDate() - 1); dates.push(isoOf(y)); }
  else if (preset === "week") { const day = today.getDay(); const diff = day === 0 ? -6 : 1 - day; const mon = new Date(today); mon.setDate(today.getDate() + diff); addRange(mon, today); }
  else if (preset === "7d") { const f = new Date(today); f.setDate(f.getDate() - 6); addRange(f, today); }
  else if (preset === "month") { addRange(new Date(today.getFullYear(), today.getMonth(), 1), today); }

  // ขยายเฉพาะวันแรก (วันนี้/ล่าสุด) เป็นค่าเริ่มต้น
  const exp = expanded || new Set(dates.slice(0, 1));
  const toggle = (iso) => { const n = new Set(exp); n.has(iso) ? n.delete(iso) : n.add(iso); setExpanded(n); };

  const PRESETS = [
    { k: "today", l: "วันนี้" }, { k: "yesterday", l: "เมื่อวาน" },
    { k: "week", l: "สัปดาห์นี้" }, { k: "7d", l: "7 วันล่าสุด" }, { k: "month", l: "เดือนนี้" }
  ];

  if (!QC || !QC.dayStatus) {
    return <Card title="ลงเวลารายวัน"><div style={{ padding: 20, color: "var(--ink-3)", fontSize: 13 }}>กำลังโหลดข้อมูลลงเวลา… เปิดเมนู "ลงเวลา QR" หนึ่งครั้งแล้วกลับมาใหม่</div></Card>;
  }

  return (
    <Card title="สรุปการลงเวลารายวัน" sub="ดึงจากการสแกน QR อัตโนมัติ · เลือกช่วงวัน · กดหัววันเพื่อพับ/ขยาย" flush
      right={<div className="seg">
        {PRESETS.map(o => <button key={o.k} className={`seg-btn ${preset === o.k ? "on" : ""}`} onClick={() => { setPreset(o.k); setExpanded(null); }}>{o.l}</button>)}
      </div>}>
      <div style={{ display: "flex", flexDirection: "column", gap: 10, padding: 12 }}>
        {dates.length === 0 && <div style={{ padding: 20, textAlign: "center", color: "var(--ink-3)" }}>ไม่มีวันในช่วงที่เลือก</div>}
        {dates.map(iso => {
          const rows = emps.map(e => ({ emp: e, st: QC.dayStatus(e.id, iso, clocks, reqs) }));
          const came = rows.filter(r => r.st.inT).length;
          const late = rows.filter(r => r.st.lateMin > 0).length;
          const leave = rows.filter(r => r.st.leave).length;
          const absent = rows.filter(r => r.st.status === "ขาดงาน").length;
          const open = exp.has(iso);
          return (
            <div key={iso} style={{ border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden", background: "var(--surface)" }}>
              <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 14px", background: "var(--surface-2)", cursor: "pointer" }} onClick={() => toggle(iso)}>
                <I.chevronDown size={15} style={{ transform: open ? "none" : "rotate(-90deg)", transition: "transform .15s", color: "var(--ink-3)" }}/>
                <span style={{ fontWeight: 700, fontSize: 13 }}>📅 {thOf(iso)}</span>
                <span style={{ flex: 1 }}/>
                <span className="badge success" style={{ fontSize: 10 }}>มา {came}</span>
                {late > 0 && <span className="badge warning" style={{ fontSize: 10 }}>สาย {late}</span>}
                {leave > 0 && <span className="badge info" style={{ fontSize: 10 }}>ลา {leave}</span>}
                {absent > 0 && <span className="badge danger" style={{ fontSize: 10 }}>ขาด {absent}</span>}
              </div>
              {open && (
                <div className="table-wrap">
                  <table className="t" style={{ fontSize: 12.5 }}>
                    <thead><tr><th style={{ paddingLeft: 14 }}>พนักงาน</th><th className="right">เข้างาน</th><th className="right">พักเที่ยง</th><th className="right">เลิกพัก</th><th className="right">ออกงาน</th><th>สถานะ</th>{canEdit && <th className="right">แก้ไข</th>}</tr></thead>
                    <tbody>
                      {rows.map(({ emp, st }) => (
                        <tr key={emp.id}>
                          <td style={{ paddingLeft: 14 }}>{emp.name}</td>
                          <td className="right amount">{st.inT || "—"}</td>
                          <td className="right amount muted">{st.brT || "—"}</td>
                          <td className="right amount muted">{st.rbT || "—"}</td>
                          <td className="right amount">{st.outT || "—"}</td>
                          <td><Badge tone={st.tone} dot>{st.status}</Badge></td>
                          {canEdit && <td className="right"><button className="icon-btn" title="แก้ไขเวลาวันนี้" onClick={() => setEditRow({ emp, iso, st })}><I.edit size={13}/></button></td>}
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}
            </div>
          );
        })}
      </div>
      {editRow && <DailyTimeEditModal row={editRow} onClose={() => setEditRow(null)} onSaved={() => { setEditRow(null); force(n => n + 1); }}/>}
    </Card>
  );
}

// แก้ไขเวลาลงเวลาของพนักงานหนึ่งคน "ทั้งวัน" (ผู้มีสิทธิ์) — กรณีตอกบัตรเครื่องกลาง/มือถือเสีย
function DailyTimeEditModal({ row, onClose, onSaved }) {
  const { Btn } = window.UI;
  const thOf = (window.QRClockData && window.QRClockData.thaiOf) || (x => x);
  const [f, setF] = useStateP2({ in: row.st.inT || "", br: row.st.brT || "", rb: row.st.rbT || "", out: row.st.outT || "" });
  const upd = (k, v) => setF(p => ({ ...p, [k]: v }));
  const save = () => {
    if (!window.QRTimeData || !window.QRTimeData.setDay) { window.toast && window.toast("ระบบลงเวลายังไม่พร้อม — เปิดเมนูลงเวลา QR หนึ่งครั้งแล้วลองใหม่"); return; }
    const who = (window.Session && window.Session.get() && window.Session.get().name) || "";
    window.QRTimeData.setDay(row.emp.id, row.iso, f, who);
    window.logActivity && window.logActivity("แก้ไขเวลาลงเวลา", `${row.emp.name} · ${thOf(row.iso)} · เข้า ${f.in || "—"} ออก ${f.out || "—"}`, "time");
    window.toast && window.toast(`บันทึกเวลาของ ${row.emp.name} แล้ว`);
    onSaved && onSaved();
  };
  return (
    <>
      <div className="scrim" style={{ zIndex: 230 }} onClick={onClose}></div>
      <div style={{ position: "fixed", left: "50%", top: "50%", transform: "translate(-50%,-50%)", zIndex: 231, background: "var(--surface)", border: "1px solid var(--line)", borderRadius: 14, padding: 20, width: 440, maxWidth: "94vw", boxShadow: "var(--shadow-lg)" }}>
        <div style={{ fontSize: 15, fontWeight: 700, marginBottom: 2 }}>แก้ไขเวลาลงเวลา</div>
        <div style={{ fontSize: 12.5, color: "var(--ink-3)", marginBottom: 14 }}>{row.emp.name} · 📅 {thOf(row.iso)} — เว้นว่างได้ถ้าไม่มีรายการนั้น</div>
        <div className="grid cols-2" style={{ gap: 10 }}>
          <div className="field"><label>เข้างาน</label><window.UI.TimeField value={f.in} onChange={v => upd("in", v)}/></div>
          <div className="field"><label>ออกงาน</label><window.UI.TimeField value={f.out} onChange={v => upd("out", v)}/></div>
          <div className="field"><label>พักเที่ยง</label><window.UI.TimeField value={f.br} onChange={v => upd("br", v)}/></div>
          <div className="field"><label>เลิกพัก</label><window.UI.TimeField value={f.rb} onChange={v => upd("rb", v)}/></div>
        </div>
        <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 10, lineHeight: 1.6 }}>การแก้ไขนี้จะแทนที่เวลาทั้งหมดของวันนั้น · บันทึกว่าแก้โดยผู้ดูแล · ซิงค์ทุกเครื่อง</div>
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 16 }}>
          <Btn kind="ghost" onClick={onClose}>ยกเลิก</Btn>
          <Btn kind="primary" icon={I.check} onClick={save}>บันทึกเวลา</Btn>
        </div>
      </div>
    </>
  );
}

// อนุมัติ+จ่ายเบิกล่วงหน้า — เลือกบัญชีที่หัก + สรุปยอด
function AdvancePayModal({ items, onClose, onConfirm }) {
  const { Btn, fmt0 } = window.UI;
  const balances = window.CompanyCashStore ? window.CompanyCashStore.balances() : [];
  const [accId, setAccId] = useStateP2(balances[0] ? balances[0].id : "");
  const total = items.reduce((s, a) => s + a.amount, 0);
  const acc = balances.find(a => a.id === accId);
  const after = acc ? acc.balance - total : 0;
  return (
    <>
      <div className="scrim" style={{ zIndex: 230 }} onClick={onClose}></div>
      <div style={{ position: "fixed", left: "50%", top: "50%", transform: "translate(-50%,-50%)", zIndex: 231, background: "var(--surface)", border: "1px solid var(--line)", borderRadius: 14, padding: 20, width: 460, maxWidth: "94vw", boxShadow: "var(--shadow-lg)" }}>
        <div style={{ fontSize: 15, fontWeight: 700, marginBottom: 4 }}>อนุมัติและจ่ายเบิกล่วงหน้า</div>
        <div style={{ fontSize: 12, color: "var(--ink-3)", marginBottom: 14 }}>{items.length} รายการ · รวม ฿{fmt0(total)} — ระบบจะหักจากบัญชีที่เลือก + สร้างใบสำคัญรับเงินให้พนักงานอัตโนมัติ</div>
        <div style={{ maxHeight: 160, overflowY: "auto", border: "1px solid var(--line)", borderRadius: 8, marginBottom: 12 }}>
          {items.map((a, i) => (
            <div key={i} style={{ display: "flex", justifyContent: "space-between", padding: "7px 12px", borderBottom: i < items.length - 1 ? "1px solid var(--line-soft)" : "none", fontSize: 12.5 }}>
              <span>{a.emp} <span style={{ color: "var(--ink-3)" }}>· {a.reason}</span></span><b className="amount">฿{fmt0(a.amount)}</b>
            </div>
          ))}
        </div>
        <div className="field" style={{ marginBottom: 10 }}><label>หักจากบัญชี</label>
          <select className="input" value={accId} onChange={e => setAccId(e.target.value)}>
            {balances.map(a => <option key={a.id} value={a.id}>{a.emoji} {a.name} — คงเหลือ ฿{fmt0(a.balance)}</option>)}
          </select>
        </div>
        {acc && <div style={{ display: "flex", justifyContent: "space-between", padding: "8px 12px", background: after < 0 ? "#fef2f2" : "var(--surface-2)", borderRadius: 8, fontSize: 12.5, color: after < 0 ? "var(--danger)" : "var(--ink-2)" }}>
          <span>คงเหลือหลังหัก</span><b className="amount">฿{fmt0(after)}</b>
        </div>}
        {after < 0 && <div style={{ fontSize: 11, color: "var(--danger)", marginTop: 6 }}>⚠️ ยอดในบัญชีไม่พอ — เลือกบัญชีอื่นหรือเติมเงินก่อน</div>}
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 16 }}>
          <Btn kind="ghost" onClick={onClose}>ยกเลิก</Btn>
          <Btn kind="primary" icon={I.check} onClick={() => onConfirm(items, accId)} disabled={!accId}>อนุมัติ + จ่าย ฿{fmt0(total)}</Btn>
        </div>
      </div>
    </>
  );
}

function AdvanceAddModal({ onClose, onSave }) {
  const D = window.SSSData;
  const { Btn } = window.UI;
  const [f, setF] = useStateP2({ empId: D.Employees[2]?.id, emp: D.Employees[2]?.name, reason: "", amount: 0, iso: prTodayISO() });
  const setEmp = (id) => { const e = D.Employees.find(emp => emp.id === id); setF(p => ({ ...p, empId: id, emp: e?.name })); };
  return (
    <div className="scrim" style={{display:"flex",alignItems:"center",justifyContent:"center",padding:24,zIndex:200}} onClick={onClose}>
      <div style={{background: "var(--surface)", borderRadius: 12, padding: 18, width: 440, maxWidth: "92vw"}} onClick={e => e.stopPropagation()}>
        <div style={{fontSize: 15, fontWeight: 600, marginBottom: 14}}>บันทึกการเบิกเงินล่วงหน้า</div>
        <div style={{display: "flex", flexDirection: "column", gap: 10}}>
          <div className="field-row cols-2">
            <div className="field"><label>พนักงาน</label>
              <select className="input" value={f.empId} onChange={e=>setEmp(e.target.value)}>
                {D.Employees.map(e => <option key={e.id} value={e.id}>{e.name}</option>)}
              </select>
            </div>
            <div className="field"><label>วันที่เบิก</label><input className="input" type="date" value={f.iso} onChange={e=>setF(p=>({...p, iso: e.target.value}))}/></div>
          </div>
          <div className="field"><label>จำนวนเงิน (บาท)</label><input className="input" type="number" value={f.amount} onChange={e=>setF(p=>({...p, amount: +e.target.value}))}/></div>
          <div className="field"><label>เหตุผล</label><textarea className="textarea" value={f.reason} onChange={e=>setF(p=>({...p, reason: e.target.value}))} placeholder="เช่น ค่ารักษาพยาบาล, ค่าเทอมลูก…"/></div>
        </div>
        <div style={{display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 16}}>
          <Btn kind="ghost" onClick={onClose}>ยกเลิก</Btn>
          <Btn kind="primary" icon={I.check} onClick={() => { if(!f.amount||!f.reason||!f.iso){window.toast&&window.toast("กรอกข้อมูลให้ครบ");return;} onSave({ empId: f.empId, emp: f.emp, reason: f.reason, amount: f.amount, date: prIsoToThai(f.iso), iso: f.iso }); }}>บันทึก</Btn>
        </div>
      </div>
    </div>
  );
}

function PaySlip({ row, period, payDate, calcDate, slogan, timeRecs, advances, month, round }) {
  const { fmtM, fmt0, bahtText } = window.UI;
  const D = window.SSSData;
  const C = D.Company;
  const emp = D.Employees.find(e => e.id === row.emp);
  const hourly = emp ? (emp.hourly || (emp.salary ? Math.round(emp.salary / 22 / 8) : 0)) : 0;
  // ใบแจ้งการทำงานรายวัน — ดึงจากลงเวลาเดือนนี้
  const isoOf = (t) => t.iso || (window.DocDates ? window.DocDates.toISO(t.date) : "") || "";
  // เลือกงวดต้นเดือน/ท้ายเดือน → ใบแจ้งรายวันโชว์เฉพาะช่วงวันของงวดนั้น (ต้น ≤15 · ท้าย ≥16)
  const inRound = (iso) => {
    if (!round || round === "full") return true;
    const d = parseInt(String(iso).slice(8, 10), 10) || 0;
    return round === "first" ? d <= 15 : d >= 16;
  };
  const dayLog = (timeRecs || []).filter(t => t.emp === row.emp && isoOf(t).startsWith(month || "") && inRound(isoOf(t)))
    .sort((a, b) => isoOf(a).localeCompare(isoOf(b)))
    .map(t => {
      const earn = Math.round((t.work || 0) * hourly + (t.ot || 0) * (emp?.otRate || 0));
      const advToday = (advances || []).filter(a => a.empId === row.emp && (a.date === t.date) && (a.status === "อนุมัติแล้ว" || a.status === "จ่ายแล้ว")).reduce((s, a) => s + a.amount, 0);
      return { ...t, earn, advToday };
    });
  const logEarnTotal = dayLog.reduce((s, d) => s + d.earn, 0);
  const logAdvTotal = dayLog.reduce((s, d) => s + d.advToday, 0);
  return (
    <div className="doc-paper" style={{padding: 30}}>
      <div style={{display: "flex", justifyContent: "space-between", marginBottom: 16, borderBottom: "1px solid #e7e5e4", paddingBottom: 12}}>
        <div>
          <div style={{display: "flex", alignItems: "center", gap: 10}}>
            <div style={{width: 36, height: 36, background: "#0c0a09", color: "white", display: "grid", placeItems: "center", fontWeight: 700, borderRadius: 5}}>SSS</div>
            <div>
              <div style={{fontWeight: 600, fontSize: 13}}>{C.name}</div>
              <div style={{fontSize: 10.5, color: "#78716c"}}>เลขผู้เสียภาษี {C.taxId}</div>
            </div>
          </div>
        </div>
        <div style={{textAlign: "right"}}>
          <h1 style={{fontSize: 18}}>ใบจ่ายเงินเดือน</h1>
          <div style={{fontSize: 11, color: "#57534e"}}>PAY SLIP · งวด {period || "พ.ค. 2569"}</div>
          {calcDate && <div style={{fontSize: 10, color: "#78716c", marginTop: 2}}>คำนวนเมื่อ {calcDate}</div>}
        </div>
      </div>

      <div className="field-row cols-2" style={{marginBottom: 14}}>
        <div><div style={{fontSize: 10, color: "#78716c"}}>พนักงาน</div><div style={{fontWeight: 600}}>{emp?.name}</div></div>
        <div><div style={{fontSize: 10, color: "#78716c"}}>รหัส / แผนก</div><div>{emp?.id} · {emp?.dept}</div></div>
        <div><div style={{fontSize: 10, color: "#78716c"}}>ตำแหน่ง</div><div>{emp?.role}</div></div>
        <div><div style={{fontSize: 10, color: "#78716c"}}>วันจ่าย</div><div>{payDate || "—"}</div></div>
        <div><div style={{fontSize: 10, color: "#78716c"}}>วันที่คำนวน</div><div>{calcDate || "—"}</div></div>
      </div>

      <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, marginBottom: 16}}>
        <div>
          <div style={{fontSize: 11, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.05em", color: "#44403c", marginBottom: 6}}>รายได้</div>
          <table style={{width: "100%", fontSize: 12}}>
            <tbody>
              <tr><td style={{padding: "4px 0"}}>เงินเดือน/ค่าจ้างรายชั่วโมง</td><td style={{textAlign: "right"}}>{fmtM(row.base > 0 ? row.base : row.hours * (emp?.hourly || 0))}</td></tr>
              <tr><td style={{padding: "4px 0"}}>OT ({row.otHours} ชม. × {emp?.otRate})</td><td style={{textAlign: "right"}}>{fmtM(row.otHours * (emp?.otRate || 0))}</td></tr>
              <tr style={{borderTop: "1px solid #e7e5e4", fontWeight: 600}}><td style={{padding: "6px 0"}}>รวมรายได้</td><td style={{textAlign: "right"}}>{fmtM(row.gross)}</td></tr>
            </tbody>
          </table>
        </div>
        <div>
          <div style={{fontSize: 11, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.05em", color: "#44403c", marginBottom: 6}}>รายการหัก</div>
          <table style={{width: "100%", fontSize: 12}}>
            <tbody>
              <tr><td style={{padding: "4px 0"}}>เงินสมทบประกันสังคม 5%</td><td style={{textAlign: "right"}}>−{fmtM(row.sso)}</td></tr>
              <tr><td style={{padding: "4px 0"}}>หัก ณ ที่จ่าย (ภ.ง.ด.1)</td><td style={{textAlign: "right"}}>{row.tax > 0 ? `−${fmtM(row.tax)}` : "—"}</td></tr>
              <tr><td style={{padding: "4px 0"}}>เบิกเงินล่วงหน้า</td><td style={{textAlign: "right"}}>{row.advance > 0 ? `−${fmtM(row.advance)}` : "—"}</td></tr>
              <tr><td style={{padding: "4px 0"}}>หักมาสาย/ขาดงาน</td><td style={{textAlign: "right"}}>{row.late > 0 ? `−${fmtM(row.late)}` : "—"}</td></tr>
              <tr style={{borderTop: "1px solid #e7e5e4", fontWeight: 600}}><td style={{padding: "6px 0"}}>รวมรายการหัก</td><td style={{textAlign: "right"}}>−{fmtM(row.sso + row.tax + row.advance + row.late)}</td></tr>
            </tbody>
          </table>
        </div>
      </div>

      <div style={{borderTop: "2px solid #0c0a09", padding: "12px 0", display: "flex", justifyContent: "space-between", alignItems: "center"}}>
        <div>
          <div style={{fontSize: 11, color: "#78716c"}}>ยอดสุทธิจ่าย (โอนเข้าบัญชี)</div>
          <div style={{fontSize: 11, color: "#57534e", fontStyle: "italic"}}>({bahtText(row.net)})</div>
        </div>
        <div style={{fontSize: 22, fontWeight: 600}}>฿{fmtM(row.net)}</div>
      </div>

      <div style={{marginTop: 12, padding: 10, background: "#f7f6f4", fontSize: 11, color: "#57534e", borderRadius: 4}}>
        <b>หมายเหตุ:</b> นายจ้างสมทบประกันสังคมเพิ่มอีก ฿{fmtM(row.sso)} (5%) เข้ากองทุน · เอกสารฉบับนี้เป็นข้อมูลส่วนตัวของพนักงาน
      </div>

      <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 40, marginTop: 40, fontSize: 11}}>
        <div style={{textAlign: "center"}}><div style={{borderTop: "1px solid #44403c", paddingTop: 4, marginTop: 30}}>ผู้จ่าย · {(window.Session && window.Session.get() && window.Session.get().name) || (C.currentUser && C.currentUser.name) || ""}</div></div>
        <div style={{textAlign: "center"}}><div style={{borderTop: "1px solid #44403c", paddingTop: 4, marginTop: 30}}>ผู้รับ · {emp?.name}</div></div>
      </div>

      {slogan && (
        <div style={{marginTop: 16, padding: "12px 16px", background: "#0c0a09", color: "white", borderRadius: 6, textAlign: "center", fontSize: 13, fontWeight: 600, letterSpacing: "0.01em"}}>
          "{slogan}"
        </div>
      )}

      {/* ──── แผ่นที่ 2: ใบแจ้งการทำงานรายวัน (สำหรับพนักงาน + ผู้จ่ายเงินตรวจ) ──── */}
      <div style={{pageBreakBefore: "always", breakBefore: "page", marginTop: 30, paddingTop: 18, borderTop: "2px dashed #d6d3d1"}}>
        <div style={{display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 10}}>
          <div>
            <h2 style={{fontSize: 16, margin: 0}}>ใบแจ้งการทำงานรายวัน</h2>
            <div style={{fontSize: 11, color: "#78716c"}}>DAILY WORK LOG · สำหรับแจ้งพนักงาน และให้ผู้จ่ายเงินตรวจสอบ</div>
          </div>
          <div style={{textAlign: "right", fontSize: 11}}><div><b>{emp?.name}</b> · {emp?.id}</div><div style={{color: "#78716c"}}>งวด {period} · ค่าแรง ฿{fmt0(hourly)}/ชม.</div></div>
        </div>
        {dayLog.length === 0 ? (
          <div style={{padding: 24, textAlign: "center", color: "#78716c", fontSize: 12, border: "1px dashed #d6d3d1", borderRadius: 6}}>ยังไม่มีข้อมูลลงเวลารายวันของเดือนนี้ — ไปที่แท็บ "ลงเวลา / OT" หรือดึงจาก QR</div>
        ) : (
          <table style={{width: "100%", borderCollapse: "collapse", fontSize: 11.5}}>
            <thead><tr style={{background: "#f5f5f4"}}>
              <th style={{textAlign: "left", padding: "6px 8px", borderBottom: "2px solid #0c0a09"}}>วันที่</th>
              <th style={{textAlign: "left", padding: "6px 8px", borderBottom: "2px solid #0c0a09"}}>สถานะ</th>
              <th style={{textAlign: "center", padding: "6px 8px", borderBottom: "2px solid #0c0a09"}}>เข้า</th>
              <th style={{textAlign: "center", padding: "6px 8px", borderBottom: "2px solid #0c0a09"}}>ออก</th>
              <th style={{textAlign: "right", padding: "6px 8px", borderBottom: "2px solid #0c0a09"}}>ชม.</th>
              <th style={{textAlign: "right", padding: "6px 8px", borderBottom: "2px solid #0c0a09"}}>OT</th>
              <th style={{textAlign: "right", padding: "6px 8px", borderBottom: "2px solid #0c0a09"}}>ค่าแรงวันนี้</th>
              <th style={{textAlign: "right", padding: "6px 8px", borderBottom: "2px solid #0c0a09"}}>เบิก</th>
            </tr></thead>
            <tbody>
              {dayLog.map((d, i) => (
                <tr key={i} style={{borderBottom: "1px solid #eceae7"}}>
                  <td style={{padding: "5px 8px"}}>{d.date}</td>
                  <td style={{padding: "5px 8px"}}>{d.status}</td>
                  <td style={{padding: "5px 8px", textAlign: "center", fontFamily: "monospace"}}>{d.in || "—"}</td>
                  <td style={{padding: "5px 8px", textAlign: "center", fontFamily: "monospace"}}>{d.out || "—"}</td>
                  <td style={{padding: "5px 8px", textAlign: "right"}}>{(d.work || 0).toFixed(1)}</td>
                  <td style={{padding: "5px 8px", textAlign: "right"}}>{d.ot > 0 ? d.ot.toFixed(1) : "—"}</td>
                  <td style={{padding: "5px 8px", textAlign: "right"}}>฿{fmt0(d.earn)}</td>
                  <td style={{padding: "5px 8px", textAlign: "right", color: d.advToday > 0 ? "#b45309" : "#a8a29e"}}>{d.advToday > 0 ? `−฿${fmt0(d.advToday)}` : "—"}</td>
                </tr>
              ))}
              <tr style={{fontWeight: 700, background: "#fafaf9"}}>
                <td style={{padding: "7px 8px"}} colSpan={6}>รวมค่าแรงตามวันทำงาน ({dayLog.length} วัน)</td>
                <td style={{padding: "7px 8px", textAlign: "right"}}>฿{fmt0(logEarnTotal)}</td>
                <td style={{padding: "7px 8px", textAlign: "right", color: "#b45309"}}>{logAdvTotal > 0 ? `−฿${fmt0(logAdvTotal)}` : "—"}</td>
              </tr>
            </tbody>
          </table>
        )}
        <div style={{marginTop: 10, padding: "8px 12px", background: "#f7f6f4", fontSize: 10.5, color: "#57534e", borderRadius: 4, lineHeight: 1.7}}>
          "ค่าแรงวันนี้" คิดจากชั่วโมงทำงาน×ค่าแรงรายชั่วโมง + OT · ยอดเบิกระหว่างงวดจะถูกหักออกตอนคิดเงินเดือนสุทธิ
        </div>
        <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 40, marginTop: 28, fontSize: 11}}>
          <div style={{textAlign: "center"}}><div style={{borderTop: "1px dashed #57534e", paddingTop: 4, marginTop: 26}}>ผู้จ่ายเงินตรวจสอบ<br/>วันที่ ............................</div></div>
          <div style={{textAlign: "center"}}><div style={{borderTop: "1px dashed #57534e", paddingTop: 4, marginTop: 26}}>พนักงานรับทราบ ({emp?.name})<br/>วันที่ ............................</div></div>
        </div>
      </div>
    </div>
  );
}

window.Payroll = Payroll;
window.PayrollPolicyModal = PolicyModal;
