/* ============================================================
   바른셈 — 청구·매출 (수수료 청구 센터)
   Spec 05. 요금제 × 처리인원/건수 + 최저인원 보장 + 스팟 별도 → 청구서·매출 집계.
   생성·제안까지(자동 발송 금지). 계산·확정 경로 미변경.
   ============================================================ */
function Billing({ ctx }) {
  const B = window.BARUNSEM;
  const { clients, period } = ctx;
  const [openId, setOpenId] = useState(null);
  const [sent, setSent] = useState({});

  const [planEdit, setPlanEdit] = useState(null);   // F2 — 요금제 편집 대상 고객사
  const ASOF = "2026-06-08";
  const rows = clients.map((c) => {
    const hrCount = ctx.hrChangesOf(c.id).length;
    const spots = hrCount > 0 ? [{ type: "취득상실", qty: hrCount }] : [];
    const plan = ctx.planOf(c.id);
    const bill = B.billingForClient(plan, c.headcount, c.headcount, spots);
    return { c, plan, bill, spots, hrCount };
  });
  // F2 미수금 — 청구했는데 안 들어온 돈이 안 보이면 청구 화면은 절반이다.
  const ar = B.receivables(ctx.invoices, ASOF);
  const totAll = rows.reduce((a, r) => ({ supply: a.supply + r.bill.supply, vat: a.vat + r.bill.vat, total: a.total + r.bill.total, spot: a.spot + r.bill.spotTotal }), { supply: 0, vat: 0, total: 0, spot: 0 });

  const tot = totAll;
  const download = (name, headers, csvRows) => {
    const csv = B.toCSV(headers, csvRows);
    const blob = new Blob(["\ufeff" + csv], { type: "text/csv;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a"); a.href = url; a.download = name; document.body.appendChild(a); a.click(); a.remove();
    setTimeout(() => URL.revokeObjectURL(url), 800);
    ctx.toast("청구서 CSV를 내려받았습니다 · " + name, "ok");
  };
  const downloadAll = () => download(`매출집계_${period.ym}.csv`, ["고객사", "처리인원", "기본+인당", "스팟", "공급가", "부가세", "합계"],
    rows.map((r) => [r.c.name, r.bill.billHeads, r.bill.recurring, r.bill.spotTotal, r.bill.supply, r.bill.vat, r.bill.total]));

  const SPOT_LABEL = { 취득상실: "취득·상실 신고", 연말정산: "연말정산", 퇴직금: "퇴직금 정산" };

  return (
    <div className="page page-wide rise">
      <div className="page-head row-between" style={{ marginBottom: 16 }}>
        <div>
          <div className="page-title">청구·매출</div>
          <div className="page-desc">{period.label} · 요금제 × 처리인원 + 스팟 업무 별도. 청구서는 <b>생성·제안</b>까지 — 발송은 노무사가.</div>
        </div>
        <button className="btn btn-default" onClick={downloadAll}><Ms name="download" />매출집계 CSV</button>
      </div>

      {/* 매출 KPI */}
      <div className="kpi-grid" style={{ marginBottom: 22 }}>
        <div className="kpi" style={{ background: "var(--accent-soft)", borderColor: "var(--accent-line)" }}>
          <div className="kpi-label" style={{ color: "var(--accent-ink)" }}><Ms name="payments" style={{ color: "var(--accent)" }} />이번 달 매출 (합계)</div>
          <div className="kpi-val num" style={{ color: "var(--accent-ink)" }}>{KRW(tot.total)}<small> 원</small></div>
          <div className="kpi-sub num">공급가 {KRW(tot.supply)} + 부가세 {KRW(tot.vat)}</div>
        </div>
        <div className="kpi">
          <div className="kpi-label"><Ms name="receipt_long" />공급가액</div>
          <div className="kpi-val num">{KRW(tot.supply)}<small> 원</small></div>
          <div className="kpi-sub">부가세 별도</div>
        </div>
        <div className="kpi">
          <div className="kpi-label"><Ms name="bolt" style={{ color: "var(--warn)" }} />스팟 업무</div>
          <div className="kpi-val num">{KRW(tot.spot)}<small> 원</small></div>
          <div className="kpi-sub">취득·상실 등 수시 별도청구</div>
        </div>
        <div className="kpi">
          <div className="kpi-label"><Ms name="apartment" />청구 고객사</div>
          <div className="kpi-val num">{clients.length}<small> 곳</small></div>
          <div className="kpi-sub">최저인원 보장 포함</div>
        </div>
      </div>

      {/* 고객사별 청구서 */}
      <div className="card">
        <CardHead icon="request_quote" title="고객사별 청구서" sub={`${period.label} 처리분 · 요금제 적용`} />
        <table className="tbl tbl-cards">
          <thead>
            <tr><th>고객사</th><th className="r">처리인원</th><th className="r">기본+인당</th><th className="r">스팟</th><th className="r">공급가</th><th className="r">부가세</th><th className="r">합계</th><th style={{ width: 150, textAlign: "center" }}>청구서</th></tr>
          </thead>
          <tbody>
            {rows.map(({ c, plan, bill, spots, hrCount }) => {
              const minApplied = c.headcount < (plan.minHeads || 0);
              const isOpen = openId === c.id;
              return (
                <React.Fragment key={c.id}>
                  <tr>
                    <td className="tc-name"><div style={{ display: "flex", alignItems: "center", gap: 9 }}><ClientAvatar client={c} size={28} /><div><div style={{ fontWeight: 650 }}>{c.name}</div><div className="muted" style={{ fontSize: 11 }}>{c.biz} · {c.headcount}명</div></div></div></td>
                    <td className="r num" data-label="처리인원">{bill.billHeads}{minApplied && <span className="tag tag-warn" style={{ height: 17, fontSize: 9.5, marginLeft: 4 }} title={`실인원 ${c.headcount} → 최저 ${plan.minHeads}인 보장`}>최저</span>}</td>
                    <td className="r num" data-label="기본+인당">{KRW(bill.recurring)}</td>
                    <td className="r num" data-label="스팟">{bill.spotTotal ? KRW(bill.spotTotal) : <span className="muted">—</span>}</td>
                    <td className="r num" data-label="공급가">{KRW(bill.supply)}</td>
                    <td className="r num" data-label="부가세">{KRW(bill.vat)}</td>
                    <td className="r num" data-label="합계" style={{ fontWeight: 750 }}>{KRW(bill.total)}</td>
                    <td className="tc-action" style={{ textAlign: "center" }}>
                      <div style={{ display: "flex", gap: 6, justifyContent: "center" }}>
                        <button className="btn btn-default btn-sm" aria-label="청구 명세 펼치기" onClick={() => setOpenId(isOpen ? null : c.id)}><Ms name={isOpen ? "expand_less" : "expand_more"} /></button>
                        <button className="btn btn-default btn-sm" aria-label="요금제 편집" title="요금제 편집" onClick={() => setPlanEdit(c.id)}><Ms name="tune" /></button>
                        <button className="btn btn-default btn-sm" onClick={() => download(`청구서_${c.short}_${period.ym}.csv`, ["항목", "수량", "단가", "금액"], billRows({ ...c, _plan: plan }, bill, spots, SPOT_LABEL))}><Ms name="download" /></button>
                        <button className={"btn btn-sm " + (sent[c.id] ? "btn-default" : "btn-primary")} title={sent[c.id] ? "발송 준비 해제" : "발송 대기함에 올립니다 — 실제 발송은 노무사가 기존 채널로"}
                          onClick={() => setSent((s) => ({ ...s, [c.id]: !s[c.id] }))}>{sent[c.id] ? <><Ms name="undo" />준비 해제</> : <><Ms name="outbox" />발송 준비</>}</button>
                      </div>
                    </td>
                  </tr>
                  {isOpen && (
                    <tr className="tc-plain"><td colSpan="8" style={{ background: "var(--bg-sunken)", padding: "14px 22px" }}>
                      <div style={{ fontWeight: 700, fontSize: 12.5, marginBottom: 8 }}><Ms name="description" style={{ fontSize: 15, verticalAlign: "-3px", color: "var(--accent)" }} /> 청구서 명세 — {c.name} · 사업자 {c.bizNo}</div>
                      <table className="tbl" style={{ fontSize: 12.5, background: "var(--surface)" }}>
                        <tbody>
                          <tr><td>기본료</td><td className="r num">{KRW(plan.base)}원</td></tr>
                          <tr><td>인당 단가 × 처리인원</td><td className="r num">{KRW(plan.perHead)} × {bill.billHeads}명 = {KRW(plan.perHead * bill.billHeads)}원</td></tr>
                          {spots.map((sp, i) => <tr key={i}><td>{SPOT_LABEL[sp.type] || sp.type} (스팟) × {sp.qty}건</td><td className="r num">{KRW((plan.spotRates[sp.type] || 0) * sp.qty)}원</td></tr>)}
                          <tr style={{ background: "var(--surface-2)" }}><td style={{ fontWeight: 650 }}>공급가액</td><td className="r num" style={{ fontWeight: 650 }}>{KRW(bill.supply)}원</td></tr>
                          <tr><td>부가세 (10%)</td><td className="r num">{KRW(bill.vat)}원</td></tr>
                          <tr style={{ background: "var(--accent-soft)" }}><td style={{ fontWeight: 750, color: "var(--accent-ink)" }}>청구 합계</td><td className="r num" style={{ fontWeight: 800, color: "var(--accent-ink)" }}>{KRW(bill.total)}원</td></tr>
                        </tbody>
                      </table>
                    </td></tr>
                  )}
                </React.Fragment>
              );
            })}
          </tbody>
          <tfoot>
            <tr style={{ background: "var(--surface-2)", fontWeight: 750 }}>
              <td>전사 합계</td><td className="r num">{rows.reduce((s, r) => s + r.bill.billHeads, 0)}명</td><td></td>
              <td className="r num">{KRW(tot.spot)}</td><td className="r num">{KRW(tot.supply)}</td><td className="r num">{KRW(tot.vat)}</td><td className="r num" style={{ fontSize: 14 }}>{KRW(tot.total)}</td><td></td>
            </tr>
          </tfoot>
        </table>
      </div>

      {/* F2 미수금 — 청구했는데 안 들어온 돈. 이게 없으면 청구 화면이 "보여주기"에 그친다. */}
      <div className="card" style={{ marginTop: 18 }}>
        <CardHead icon="account_balance" title="미수금" sub={`미입금 ${ar.open.length}건 · 연체 ${ar.overdue.length}건 (기준일 ${ASOF})`}
          right={ar.overdueTotal > 0
            ? <span className="tag tag-danger"><Ms name="warning" style={{ fontSize: 13 }} />연체 {KRW(ar.overdueTotal)}원</span>
            : <span className="tag tag-ok"><Ms name="check" style={{ fontSize: 13 }} />연체 없음</span>} />
        {ar.rows.length === 0
          ? <div className="muted" style={{ padding: "16px 22px", fontSize: 12.5 }}>발행된 청구서가 없습니다.</div>
          : (
            <table className="tbl tbl-cards">
              <thead><tr><th>고객사</th><th>귀속</th><th>발행</th><th>납기</th><th className="r">청구액</th><th>상태</th><th style={{ width: 90 }}></th></tr></thead>
              <tbody>
                {ar.rows.map((iv) => {
                  const cl = clients.find((c) => c.id === iv.clientId);
                  return (
                    <tr key={iv.id}>
                      <td className="tc-name" style={{ fontWeight: 650 }}>{cl ? cl.short : iv.clientId}</td>
                      <td className="num" data-label="귀속">{iv.ym}</td>
                      <td className="num muted" data-label="발행">{iv.issuedAt}</td>
                      <td className="num" data-label="납기">{iv.dueDate}</td>
                      <td className="r num" data-label="청구액" style={{ fontWeight: 650 }}>{KRW(iv.total)}</td>
                      <td data-label="상태">
                        <span className={"tag " + (iv.state === "paid" ? "tag-ok" : iv.state === "overdue" ? "tag-danger" : "tag-warn")}>{iv.label}</span>
                      </td>
                      <td className="tc-action" style={{ textAlign: "center" }}>
                        {iv.state === "paid"
                          ? <span className="muted" style={{ fontSize: 11.5 }}>{iv.paidAt}</span>
                          : <button className="btn btn-default btn-sm" onClick={() => { ctx.markPaid(iv.id); ctx.toast("입금 처리했습니다", "ok"); }}><Ms name="done" />입금 확인</button>}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          )}
      </div>

      <div className="card card-pad" style={{ marginTop: 16, display: "flex", gap: 11, alignItems: "flex-start", background: "var(--bg-sunken)" }}>
        <Ms name="info" style={{ fontSize: 19, color: "var(--ink-4)", flex: "none", marginTop: 1 }} />
        <div style={{ fontSize: 12, color: "var(--ink-3)", lineHeight: 1.6 }}>
          <b>최저인원 보장</b>: 소규모 고객사도 요금제의 최저인원으로 과금(실무 관행) — 요금제는 <b>고객사별로 다르며 표에서 편집</b>할 수 있습니다. <b>스팟 업무</b>(취득·상실·연말정산·퇴직금 정산)는 월정액에 포함되지 않아 건당 별도 청구됩니다 — 수시 업무를 무료로 떠안지 않도록. 청구서는 생성·제안이며 자동 발송하지 않습니다.
        </div>
      </div>
      {planEdit && (() => {
        const row = rows.find((r) => r.c.id === planEdit);
        if (!row) return null;
        const p = row.plan;
        const num = (v) => Math.max(0, Number(String(v).replace(/[^\d]/g, "")) || 0);
        return (
          <Modal title={`요금제 — ${row.c.name}`} onClose={() => setPlanEdit(null)}
            footer={<button className="btn btn-primary" onClick={() => setPlanEdit(null)}>완료</button>}>
            <p className="muted" style={{ fontSize: 12.5, marginBottom: 12 }}>변경은 즉시 이번 달 청구액에 반영됩니다. 요금제는 고객사별 계약이며 변경 이력은 감사로그에 남습니다.</p>
            <div className="form-2">
              <div className="field"><label>기본료 (월)</label><input className="input num" value={p.base} onChange={(e) => ctx.savePlan(row.c.id, { base: num(e.target.value) })} /></div>
              <div className="field"><label>인당 단가</label><input className="input num" value={p.perHead} onChange={(e) => ctx.savePlan(row.c.id, { perHead: num(e.target.value) })} /></div>
              <div className="field"><label>최저 과금 인원</label><input className="input num" value={p.minHeads} onChange={(e) => ctx.savePlan(row.c.id, { minHeads: num(e.target.value) })} /></div>
              <div className="field"><label>부가세</label>
                <select className="select" value={p.vat ? "y" : "n"} onChange={(e) => ctx.savePlan(row.c.id, { vat: e.target.value === "y" })}>
                  <option value="y">별도 (10%)</option><option value="n">포함·면세</option>
                </select>
              </div>
            </div>
            <div style={{ fontSize: 11.5, fontWeight: 700, color: "var(--ink-2)", margin: "14px 0 7px" }}>스팟 단가</div>
            <div className="form-2">
              {Object.keys(p.spotRates || {}).map((k) => (
                <div className="field" key={k}><label>{k}</label>
                  <input className="input num" value={p.spotRates[k]} onChange={(e) => ctx.savePlan(row.c.id, { spotRates: { ...p.spotRates, [k]: num(e.target.value) } })} /></div>
              ))}
            </div>
            <hr className="divider" style={{ margin: "16px 0" }} />
            {(() => {
              const ti = B.taxInvoiceDraft(row.c, row.bill, period.ym);
              return (
                <>
                  <div style={{ fontSize: 11.5, fontWeight: 700, color: "var(--ink-2)", marginBottom: 7 }}>세금계산서 초안 (발행은 홈택스·연동사)</div>
                  <div className="dl" style={{ fontSize: 12.5 }}>
                    <dt>공급받는자</dt><dd>{ti.buyerName} · {ti.buyerBizNo}</dd>
                    <dt>품목</dt><dd>{ti.itemName}</dd>
                    <dt>공급가 / 세액</dt><dd className="num">{KRW(ti.supply)} / {KRW(ti.vat)}</dd>
                    <dt>합계</dt><dd className="num" style={{ fontWeight: 700 }}>{KRW(ti.total)}원</dd>
                    <dt>발행 예정일</dt><dd className="num">{ti.issueDate}</dd>
                  </div>
                </>
              );
            })()}
          </Modal>
        );
      })()}
    </div>
  );
}

function billRows(c, bill, spots, SPOT_LABEL) {
  const plan = c._plan || c.plan;
  const rows = [
    ["기본료", 1, plan.base, plan.base],
    ["인당 단가", bill.billHeads, plan.perHead, plan.perHead * bill.billHeads],
  ];
  spots.forEach((sp) => rows.push([(SPOT_LABEL[sp.type] || sp.type) + " (스팟)", sp.qty, plan.spotRates[sp.type] || 0, (plan.spotRates[sp.type] || 0) * sp.qty]));
  rows.push(["공급가액", "", "", bill.supply]);
  rows.push(["부가세", "", "", bill.vat]);
  rows.push(["청구 합계", "", "", bill.total]);
  return rows;
}

Object.assign(window, { Billing });
