/* global React, I, UI, SSSData, SSSAccounting */
const { useState: useStateAP, useMemo: useMemoAP } = React;

// ============================================================
//  Auto-posting Workflow
//  ดึงเอกสารที่ยังไม่ถูก post → preview JV → approve → posted
// ============================================================

function AutoPosting() {
  const { Card, Btn, Badge, fmt0 } = window.UI;
  const A = window.SSSAccounting;
  const D = window.SSSData;
  const [section, setSection] = useStateAP("queue"); // queue | rules | history

  const pending = useMemoAP(() => buildPendingQueue(), []);
  const postedCount = A.JournalEntries.length;
  const errorCount = 0;
  const rulesEnabled = A.PostingRules.filter(r => r.enabled).length;
  const rulesAuto = A.PostingRules.filter(r => r.enabled && r.autoPost).length;

  return (
    <div style={{display: "flex", flexDirection: "column", gap: 14}}>
      {/* Status strip */}
      <div className="grid" style={{gridTemplateColumns: "repeat(4, 1fr)", gap: 10}}>
        <APStatTile label="รอบันทึก" value={pending.length} accent="oklch(64% 0.13 70)" icon={I.clock}
          sub={`${pending.filter(p => p.rule?.autoPost).length} เปิด auto-post · ${pending.filter(p => !p.rule?.autoPost).length} รอตรวจ`}/>
        <APStatTile label="บันทึกแล้ววันนี้" value={postedCount} accent="oklch(60% 0.10 150)" icon={I.check}
          sub="ทั้งหมดในเดือนนี้"/>
        <APStatTile label="ข้อผิดพลาด" value={errorCount} accent={errorCount > 0 ? "oklch(58% 0.18 25)" : "var(--ink-4)"} icon={I.shield}
          sub={errorCount > 0 ? "ต้องแก้ไขก่อน post" : "ไม่มีปัญหา"}/>
        <APStatTile label="กฎที่เปิดใช้" value={`${rulesEnabled}/${A.PostingRules.length}`} accent="var(--ink-1)" icon={I.cog}
          sub={`${rulesAuto} ตั้งค่า auto-post`}/>
      </div>

      {/* Section nav */}
      <div style={{display: "flex", gap: 4, borderBottom: "1px solid var(--line)"}}>
        {[
          { k: "queue", l: "คิวรอบันทึก", c: pending.length },
          { k: "rules", l: "ตั้งค่ากฎการบันทึก", c: A.PostingRules.length },
          { k: "payroll", l: "ลงบัญชีเงินเดือน", c: 6 },
          { k: "history", l: "ประวัติการ post", c: postedCount }
        ].map(t => (
          <button key={t.k} onClick={() => setSection(t.k)} style={{
            padding: "10px 14px",
            background: "transparent",
            border: "none",
            borderBottom: `2px solid ${section === t.k ? "var(--ink-1)" : "transparent"}`,
            cursor: "pointer",
            fontSize: 13,
            fontWeight: section === t.k ? 600 : 400,
            color: section === t.k ? "var(--ink-1)" : "var(--ink-3)",
            fontFamily: "var(--font)",
            marginBottom: -1
          }}>{t.l} <span style={{marginLeft: 6, color: "var(--ink-3)", fontSize: 11.5}}>{t.c}</span></button>
        ))}
      </div>

      {section === "queue" && <PendingQueue pending={pending}/>}
      {section === "rules" && <window.PostingRulesView/>}
      {section === "payroll" && <window.PayrollPosting/>}
      {section === "history" && <window.PostHistory/>}
    </div>
  );
}

function APStatTile({ label, value, sub, accent, icon }) {
  return (
    <div style={{
      padding: 14, background: "var(--surface)",
      border: "1px solid var(--line)", borderRadius: "var(--radius)",
      borderLeft: `3px solid ${accent}`
    }}>
      <div style={{display: "flex", alignItems: "center", gap: 6, fontSize: 11.5, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.04em", fontWeight: 500}}>
        {icon && React.createElement(icon, { size: 12 })}
        {label}
      </div>
      <div style={{fontSize: 24, fontWeight: 600, marginTop: 6, letterSpacing: "-0.01em"}}>{value}</div>
      {sub && <div style={{fontSize: 11.5, color: "var(--ink-3)", marginTop: 2}}>{sub}</div>}
    </div>
  );
}

// ============================================================
//  Build pending queue from existing docs
// ============================================================
function buildPendingQueue() {
  const A = window.SSSAccounting;
  const D = window.SSSData;
  const postedRefs = new Set();
  A.JournalEntries.forEach(e => e.ref.split("/").forEach(r => postedRefs.add(r.trim())));

  const ruleMap = Object.fromEntries(A.PostingRules.map(r => [r.docType, r]));
  const items = [];

  // Invoices not yet posted
  (D.Invoices || []).forEach(inv => {
    if (postedRefs.has(inv.no)) return;
    const base = inv.amount / 1.07;
    const vat = inv.amount - base;
    items.push({
      docId: inv.no,
      docType: "invoice",
      date: inv.date,
      party: inv.customer,
      amount: inv.amount,
      rule: ruleMap["invoice"],
      values: {
        total: inv.amount,
        base_product: base,
        base_service: 0,
        vat: vat
      },
      autoSuggested: ruleMap["invoice"]?.autoPost
    });
  });

  // Receipts not posted
  (D.Receipts || []).forEach(rc => {
    if (postedRefs.has(rc.no)) return;
    items.push({
      docId: rc.no,
      docType: "receipt",
      date: rc.date,
      party: rc.customer,
      amount: rc.amount,
      rule: ruleMap["receipt"],
      values: { total: rc.amount },
      meta: { method: rc.method },
      autoSuggested: ruleMap["receipt"]?.autoPost
    });
  });

  // Payment vouchers (mocked)
  const mockPV = [
    { id: "PV-2569-0073", date: "22/05/2569", party: "ก๊าซอุตสาหกรรม BIG", category: "วัสดุสิ้นเปลือง", base: 8500, vat: 595, total: 9095, method: "เงินสด", wht: 0 },
    { id: "PV-2569-0072", date: "21/05/2569", party: "หจก. เครื่องมือกล วี.ที.", category: "ค่าซ่อมแซม", base: 12000, vat: 840, total: 12480, method: "โอน · KBank", wht: 360, whtType: "service" }
  ];
  mockPV.forEach(p => {
    if (postedRefs.has(p.id)) return;
    items.push({
      docId: p.id,
      docType: "payment-voucher",
      date: p.date,
      party: p.party,
      amount: p.total,
      rule: ruleMap["payment-voucher"],
      values: { total: p.total, base: p.base, vat: p.vat, net: p.total - p.wht, wht: p.wht },
      meta: { category: p.category, method: p.method, whtType: p.whtType },
      autoSuggested: false
    });
  });

  // Purchase orders awaiting receipt
  const mockPO = [
    { id: "PO-2569-0090", date: "21/05/2569", party: "บริษัท โพสโก้ ไทย จำกัด", base: 380000, vat: 26600, total: 406600 }
  ];
  mockPO.forEach(p => {
    items.push({
      docId: p.id,
      docType: "purchase-order",
      date: p.date,
      party: p.party,
      amount: p.total,
      rule: ruleMap["purchase-order"],
      values: { total: p.total, base: p.base, vat: p.vat },
      autoSuggested: false
    });
  });

  // Payroll closing
  items.push({
    docId: "PR-2569-05",
    docType: "payroll",
    date: "31/05/2569",
    party: "เงินเดือนรอบ พ.ค. 2569 · 9 คน",
    amount: 332750,
    rule: ruleMap["payroll"],
    values: {
      salary_direct: 185000, salary_indirect: 145000, sso_er: 8800,
      salary_net: 312950, wht_pnd1: 2925, sso_total: 22925
    },
    autoSuggested: false
  });

  return items.sort((a, b) => a.date.localeCompare(b.date));
}

// ============================================================
//  Pending queue + preview
// ============================================================
function PendingQueue({ pending: initialPending }) {
  const { Card, Btn, Badge, fmt0 } = window.UI;
  const [pending, setPending] = useStateAP(initialPending);
  const [selected, setSelected] = useStateAP(new Set());
  const [expanded, setExpanded] = useStateAP(new Set([initialPending[0]?.docId].filter(Boolean)));

  // Actually create journal entries and drop posted docs from the queue
  const postIds = (ids) => {
    const A = window.SSSAccounting;
    let posted = 0;
    ids.forEach(id => {
      const item = pending.find(p => p.docId === id);
      if (!item || !item.rule) return;
      const jv = computePostingLines(item);
      const jtype = item.rule.journal;
      const same = A.JournalEntries.filter(e => e.type === jtype);
      const maxN = Math.max(0, ...same.map(e => parseInt((e.id.split("-")[1]) || 0, 10)));
      const newId = `${jtype}69-${String(maxN + 1 + posted).padStart(4, "0")}`;
      A.JournalEntries.unshift({
        id: newId,
        type: jtype,
        date: item.date,
        ref: item.docId,
        desc: `${item.rule.desc} — ${item.party}`,
        lines: jv.lines.map(l => ({ acc: l.acc, dr: l.dr, cr: l.cr, note: l.note }))
      });
      posted++;
    });
    setPending(prev => prev.filter(p => !ids.includes(p.docId)));
    setSelected(new Set());
    window.logActivity && window.logActivity("บันทึกบัญชี", `บันทึก ${posted} รายการเข้าสมุดรายวัน`, "create");
    window.toast && window.toast(`บันทึก ${posted} รายการเข้าสมุดรายวันเรียบร้อย`);
  };

  const skipId = (id) => {
    setPending(prev => prev.filter(p => p.docId !== id));
    setSelected(s => { const n = new Set(s); n.delete(id); return n; });
    window.toast && window.toast(`ข้ามรายการ ${id} แล้ว`);
  };

  const toggleSel = (id) => {
    setSelected(s => {
      const n = new Set(s);
      n.has(id) ? n.delete(id) : n.add(id);
      return n;
    });
  };
  const selectAll = () => {
    if (selected.size === pending.length) setSelected(new Set());
    else setSelected(new Set(pending.map(p => p.docId)));
  };
  const toggleExp = (id) => {
    setExpanded(s => {
      const n = new Set(s);
      n.has(id) ? n.delete(id) : n.add(id);
      return n;
    });
  };

  const postSelected = () => {
    postIds([...selected]);
  };

  return (
    <div style={{display: "flex", flexDirection: "column", gap: 12}}>
      {/* Bulk actions */}
      <div style={{display: "flex", alignItems: "center", gap: 10, padding: "10px 14px",
        background: "var(--surface)", border: "1px solid var(--line)", borderRadius: "var(--radius-sm)"}}>
        <label style={{display: "flex", alignItems: "center", gap: 6, cursor: "pointer", fontSize: 12.5}}>
          <input type="checkbox" checked={selected.size === pending.length && pending.length > 0}
            onChange={selectAll} style={{cursor: "pointer"}}/>
          <span>เลือกทั้งหมด</span>
        </label>
        <span style={{fontSize: 12, color: "var(--ink-3)"}}>·</span>
        <span style={{fontSize: 12.5, color: "var(--ink-2)"}}>
          เลือก <b>{selected.size}</b>/{pending.length} รายการ
        </span>
        <div style={{flex: 1}}/>
        <Btn size="sm" kind="ghost" icon={I.check}
          onClick={() => {
            const auto = new Set(pending.filter(p => p.autoSuggested).map(p => p.docId));
            setSelected(auto);
          }}>เลือกที่ตั้ง auto</Btn>
        <Btn size="sm" kind="primary" icon={I.send} disabled={selected.size === 0} onClick={postSelected}>
          บันทึก {selected.size > 0 ? `${selected.size} รายการ` : ""}เข้าสมุดรายวัน
        </Btn>
      </div>

      {pending.length === 0 && (
        <Card>
          <div style={{textAlign: "center", padding: "40px 20px", color: "var(--ink-3)"}}>
            <I.check size={28} stroke="var(--success)"/>
            <div style={{marginTop: 8, fontSize: 14}}>ไม่มีเอกสารรอบันทึก</div>
            <div style={{fontSize: 12, marginTop: 4}}>ทุกเอกสารถูก post เข้าสมุดรายวันเรียบร้อย</div>
          </div>
        </Card>
      )}

      {pending.map(item => (
        <PendingCard key={item.docId} item={item}
          selected={selected.has(item.docId)}
          expanded={expanded.has(item.docId)}
          onToggleSelect={() => toggleSel(item.docId)}
          onToggleExpand={() => toggleExp(item.docId)}
          onPost={() => postIds([item.docId])}
          onSkip={() => skipId(item.docId)}/>
      ))}
    </div>
  );
}

function PendingCard({ item, selected, expanded, onToggleSelect, onToggleExpand, onPost, onSkip }) {
  const { Btn, Badge, fmt0 } = window.UI;
  const A = window.SSSAccounting;
  const rule = item.rule;
  if (!rule) return null;

  const T = window.JOURNAL_TYPES[rule.journal];
  const jvLines = computePostingLines(item);
  const balanced = jvLines.totalDr === jvLines.totalCr;

  return (
    <div style={{
      background: "var(--surface)",
      border: `1px solid ${selected ? "var(--ink-1)" : "var(--line)"}`,
      borderRadius: "var(--radius)",
      overflow: "hidden"
    }}>
      {/* Row header */}
      <div style={{display: "flex", alignItems: "center", gap: 12, padding: "12px 14px",
        background: selected ? "var(--surface-2)" : "transparent",
        borderBottom: expanded ? "1px solid var(--line)" : "none"}}>
        <input type="checkbox" checked={selected} onChange={onToggleSelect} style={{cursor: "pointer"}}/>
        <div style={{display: "flex", alignItems: "center", gap: 8, minWidth: 280}}>
          <span style={{
            fontSize: 10.5, padding: "2px 7px", borderRadius: 4,
            background: T.color, color: "var(--accent-ink)", fontWeight: 500
          }}>{T.short}</span>
          <div>
            <span className="mono" style={{fontSize: 12.5, fontWeight: 600}}>{item.docId}</span>
            <div style={{fontSize: 11, color: "var(--ink-3)", marginTop: 1}}>{rule.label}</div>
          </div>
        </div>
        <div style={{minWidth: 80, fontSize: 12, color: "var(--ink-3)"}}>{item.date}</div>
        <div style={{flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontSize: 13}}>
          {item.party}
        </div>
        <div className="amount" style={{fontSize: 14, fontWeight: 600, minWidth: 120, textAlign: "right"}}>
          ฿{fmt0(item.amount)}
        </div>
        {item.autoSuggested && (
          <span style={{
            fontSize: 10.5, padding: "2px 7px", borderRadius: 4,
            background: "var(--success-bg)", color: "var(--success)", border: "1px solid var(--success)",
            display: "inline-flex", alignItems: "center", gap: 4
          }}><I.sparkle size={10}/>AUTO</span>
        )}
        <button onClick={onToggleExpand} style={{
          background: "transparent", border: "none", cursor: "pointer", padding: 6,
          color: "var(--ink-3)"
        }}>
          {expanded
            ? <I.chevronUp size={14}/>
            : <I.chevronDown size={14}/>}
        </button>
      </div>

      {/* Expanded preview */}
      {expanded && (
        <div style={{padding: "12px 14px 14px", background: "var(--surface-2)"}}>
          <div style={{fontSize: 11, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.04em", fontWeight: 500, marginBottom: 8}}>
            ตัวอย่าง JV ที่จะถูกสร้าง ({rule.desc})
          </div>

          <div style={{background: "var(--surface)", border: "1px solid var(--line)", borderRadius: "var(--radius-sm)"}}>
            <table style={{width: "100%", fontSize: 12.5, borderCollapse: "collapse"}}>
              <thead>
                <tr style={{background: "var(--surface-2)"}}>
                  <th style={apTh}>รหัส</th>
                  <th style={apTh}>ชื่อบัญชี</th>
                  <th style={{...apTh, textAlign: "right", width: 110}}>เดบิต</th>
                  <th style={{...apTh, textAlign: "right", width: 110}}>เครดิต</th>
                </tr>
              </thead>
              <tbody>
                {jvLines.lines.map((l, i) => {
                  const acc = A.accByCode[l.acc];
                  return (
                    <tr key={i} style={{borderTop: "1px solid var(--line-soft)"}}>
                      <td style={{...apTd, paddingLeft: l.cr > 0 ? 30 : 12, fontFamily: "var(--font-mono)", fontSize: 11.5, color: "var(--ink-3)"}}>{l.acc}</td>
                      <td style={{...apTd, paddingLeft: l.cr > 0 ? 24 : 0}}>
                        <div>{acc?.name || l.note}</div>
                        {l.note && <div style={{fontSize: 11, color: "var(--ink-4)", marginTop: 1}}>{l.note}</div>}
                      </td>
                      <td style={{...apTd, textAlign: "right", fontVariantNumeric: "tabular-nums"}}>{l.dr > 0 ? l.dr.toLocaleString("th-TH", {minimumFractionDigits: 2, maximumFractionDigits: 2}) : ""}</td>
                      <td style={{...apTd, textAlign: "right", fontVariantNumeric: "tabular-nums"}}>{l.cr > 0 ? l.cr.toLocaleString("th-TH", {minimumFractionDigits: 2, maximumFractionDigits: 2}) : ""}</td>
                    </tr>
                  );
                })}
              </tbody>
              <tfoot>
                <tr style={{borderTop: "2px solid var(--ink-1)", background: balanced ? "var(--success-bg)" : "var(--warning-bg)", fontWeight: 600}}>
                  <td colSpan="2" style={{...apTd, color: balanced ? "var(--success)" : "var(--warning)"}}>
                    {balanced ? <><I.check size={11}/> สมดุล Dr = Cr</> : "⚠ ไม่สมดุล"}
                  </td>
                  <td style={{...apTd, textAlign: "right", fontVariantNumeric: "tabular-nums"}}>
                    {jvLines.totalDr.toLocaleString("th-TH", {minimumFractionDigits: 2, maximumFractionDigits: 2})}
                  </td>
                  <td style={{...apTd, textAlign: "right", fontVariantNumeric: "tabular-nums"}}>
                    {jvLines.totalCr.toLocaleString("th-TH", {minimumFractionDigits: 2, maximumFractionDigits: 2})}
                  </td>
                </tr>
              </tfoot>
            </table>
          </div>

          <div style={{display: "flex", gap: 8, marginTop: 12, alignItems: "center"}}>
            <div style={{flex: 1, fontSize: 11.5, color: "var(--ink-3)"}}>
              ใช้กฎ: <b>{rule.label}</b> → {T.label}
            </div>
            <Btn size="sm" kind="ghost" icon={I.edit} onClick={() => window.openNewJournal && window.openNewJournal()}>แก้ไขก่อนบันทึก</Btn>
            <Btn size="sm" kind="ghost" onClick={onSkip}>ข้าม</Btn>
            <Btn size="sm" kind="primary" icon={I.check} onClick={onPost}>บันทึกทันที</Btn>
          </div>
        </div>
      )}
    </div>
  );
}

const apTh = { padding: "8px 12px", textAlign: "left", fontWeight: 500, color: "var(--ink-3)", fontSize: 11, textTransform: "uppercase", letterSpacing: "0.04em" };
const apTd = { padding: "8px 12px" };

// Compute the JV lines for a doc by applying its rule
function computePostingLines(item) {
  const A = window.SSSAccounting;
  const out = [];
  item.rule.lines.forEach(tmpl => {
    let amt = item.values[tmpl.source] || 0;
    if (tmpl.optional && amt === 0) return;
    let acc = tmpl.acc;
    let note = tmpl.note;
    // resolve dynamic accounts
    if (acc === "DYNAMIC_CASH") {
      acc = A.CashMap[item.meta?.method] || A.CashMap[Object.keys(A.CashMap).find(k => item.meta?.method?.startsWith(k))] || "1110";
    } else if (acc === "DYNAMIC_EXPENSE") {
      // map by category
      const catMap = {
        "ค่าซ่อมแซม": "5230", "ค่าเช่า": "5220", "ค่าไฟฟ้า": "5221",
        "วัสดุสิ้นเปลือง": "5250", "ค่าน้ำมัน": "5240", "ค่าใช้จ่ายเบ็ดเตล็ด": "5260"
      };
      const cat = item.meta?.category;
      acc = (cat && (catMap[cat] || Object.keys(catMap).find(k => cat.includes(k)) ? catMap[Object.keys(catMap).find(k => cat.includes(k))] : null)) || "5260";
    } else if (acc === "DYNAMIC_WHT") {
      acc = A.WhtMap[item.meta?.whtType] || "2132";
    }
    out.push({ acc, dr: tmpl.side === "Dr" ? amt : 0, cr: tmpl.side === "Cr" ? amt : 0, note });
  });
  const totalDr = out.reduce((s, l) => s + l.dr, 0);
  const totalCr = out.reduce((s, l) => s + l.cr, 0);
  return { lines: out, totalDr, totalCr };
}

window.AutoPosting = AutoPosting;
window.buildPendingQueue = buildPendingQueue;
