/* ============================================================
   바른셈 — 연말정산 워크스페이스 (연 1회 트랙)
   Spec 04. 항목화 입력 + RB-DED 한도검증 → 결정세액 → 환급/추가징수 + 건보 정산.
   월 runPayroll/gantax와 독립.
   ============================================================ */
function YearEnd({ ctx }) {
  const B = window.BARUNSEM;
  const { clients } = ctx;
  const client = clients.find((c) => c.id === (ctx.params.clientId || clients[0].id)) || clients[0];
  const rs = ctx.rulesetFor(client.id);
  const rb = B.RULEBOOK.RB_DED;
  // E4 — 귀속연도를 명시한다. 5월 워크스페이스 안에서 "2월분 급여 반영"만 적혀 있으면 어느 해 정산인지 알 수 없다.
  const taxYear = Number(ctx.period.ym.slice(0, 4)) - 1;
  const [selId, setSelId] = useState(client.employees[0].id);
  const [edits, setEdits] = useState({});
  useEffect(() => { setSelId(client.employees[0].id); }, [client.id]);
  const e = client.employees.find((x) => x.id === selId) || client.employees[0];
  const ssE = ctx.ssOf ? ctx.ssOf(e.id) : { ye: null };
  /* B12 — 근로자가 모바일로 제출한 자료를 노무사 폼에 실제로 얹는다.
     전엔 "제출 도착" 배너만 뜨고 값은 시드 그대로여서, 근로자가 무엇을 넣든 정산 결과가 같았다. */
  const mergeSubmitted = (base, sub) => {
    if (!sub || !sub.submitted) return base;
    const it = sub.items || {};
    return { ...base,
      family: { ...base.family, ...(it.family || {}) },
      incomeItems: { ...base.incomeItems, ...(it.incomeItems || {}) },
      creditItems: { ...base.creditItems, ...(it.creditItems || {}) } };
  };
  const ye = edits[e.id] || mergeSubmitted(e.yearEnd, ssE.ye);

  const setYE = (patch) => setEdits((p) => ({ ...p, [e.id]: { ...ye, ...patch } }));
  const setInc = (k, v) => setYE({ incomeItems: { ...ye.incomeItems, [k]: num(v) } });
  const setCr = (k, v) => setYE({ creditItems: { ...ye.creditItems, [k]: num(v) } });
  const setFam = (k, v) => setYE({ family: { ...ye.family, [k]: v } });

  const r = B.yearEndSettlement(ye, rb);
  const dmap = Object.fromEntries(r.detail.map((d) => [d.k, d]));
  /* F2/B12 건보 정산 — 공단 고지액을 노무사가 입력할 수 있어야 하고, 차액이 급여로 흘러가야 한다.
     고지액 입력칸이 없으면 화면이 "우리 추정치"만 보여주고 실제 정산과 무관해진다. */
  const [hsInput, setHsInput] = useState({});
  const hsIn = hsInput[e.id] || {};
  const workedMonths = (() => {
    const y = taxYear;
    const from = e.joined && e.joined.slice(0, 4) === String(y) ? Number(e.joined.slice(5, 7)) : 1;
    const to = e.left && e.left.slice(0, 4) === String(y) ? Number(e.left.slice(5, 7)) : 12;
    return Math.max(1, to - from + 1);
  })();
  const hs = B.healthSettlement(ye.prevYearWageTotal, rs.hiRate, rs.ltcRate, ye.prepaidHi,
    { workedMonths, noticedAmount: hsIn.noticed != null && hsIn.noticed !== "" ? num(hsIn.noticed) : undefined, installments: hsIn.installments || 1 });
  const setHs = (patch) => setHsInput((p) => ({ ...p, [e.id]: { ...hsIn, ...patch } }));
  // 중도 퇴사자 — 연말정산이 아니라 '퇴직자 정산'이다. 경로가 없으면 이 사람은 화면에서 사라진다(B12).
  const midLeaver = !!(e.left && e.left.slice(0, 4) === String(taxYear));
  const ss = ssE;

  // 고객사 집계 (시드값 기준 — 편집 반영)
  const agg = client.employees.reduce((a, emp) => {
    const y = edits[emp.id] || mergeSubmitted(emp.yearEnd, ctx.ssOf ? ctx.ssOf(emp.id).ye : null);
    const rr = B.yearEndSettlement(y, rb);
    return { refund: a.refund + rr.refund, due: a.due + rr.due, n: a.n + 1 };
  }, { refund: 0, due: 0, n: 0 });

  return (
    <div className="page page-wide rise">
      <div className="page-head" style={{ marginBottom: 14 }}>
        <div className="page-title" style={{ fontSize: 19 }}>연말정산</div>
        <div className="page-desc">
          <b style={{ color: "var(--accent-ink)" }}>{taxYear}년 귀속</b> 연말정산 — 항목별 공제 입력 → 한도 자동검증(RB-DED) → 결정세액 → 환급·추가징수.
          {" "}{taxYear + 1}년 2월분 급여에 반영 · 신고기한 {taxYear + 1}-03-10 · <b>연 1회 작업</b>이라 월 급여계산과 독립입니다.
        </div>
      </div>

      {/* 고객사 집계 */}
      <div className="kpi-grid kpi-3" style={{ marginBottom: 18 }}>
        <div className="kpi" style={{ background: "var(--ok-soft)", borderColor: "var(--ok-line)" }}>
          <div className="kpi-label" style={{ color: "color-mix(in oklab, var(--ok) 80%, black)" }}><Ms name="south_west" style={{ color: "var(--ok)" }} />환급 합계</div>
          <div className="kpi-val num" style={{ color: "color-mix(in oklab, var(--ok) 82%, black)" }}>{KRW(agg.refund)}<small> 원</small></div>
          <div className="kpi-sub">근로자에게 환급</div>
        </div>
        <div className="kpi" style={{ background: "var(--danger-soft)", borderColor: "var(--danger-line)" }}>
          <div className="kpi-label" style={{ color: "var(--danger)" }}><Ms name="north_east" style={{ color: "var(--danger)" }} />추가징수 합계</div>
          <div className="kpi-val num" style={{ color: "var(--danger)" }}>{KRW(agg.due)}<small> 원</small></div>
          <div className="kpi-sub">근로자로부터 추가징수</div>
        </div>
        <div className="kpi">
          <div className="kpi-label"><Ms name="groups" />정산 대상</div>
          <div className="kpi-val num">{agg.n}<small> 명</small></div>
          <div className="kpi-sub">{client.name}</div>
        </div>
      </div>

      <div className="l-master" style={{ "--master": "264px" }}>
        {/* 근로자 리스트 */}
        <div className="card">
          <CardHead icon="groups" title="근로자" sub={`${client.employees.length}명`} />
          <div className="pick-list" style={{ maxHeight: 680, overflowY: "auto" }}>
            {client.employees.map((emp) => {
              const y = edits[emp.id] || mergeSubmitted(emp.yearEnd, ctx.ssOf ? ctx.ssOf(emp.id).ye : null);
              const rr = B.yearEndSettlement(y, rb);
              return (
                <button key={emp.id} onClick={() => setSelId(emp.id)} style={{
                  display: "flex", alignItems: "center", gap: 11, padding: "12px 16px", width: "100%", textAlign: "left", border: "none",
                  borderBottom: "1px solid var(--line)", background: emp.id === selId ? "var(--accent-soft)" : "transparent", cursor: "pointer",
                  borderLeft: emp.id === selId ? "3px solid var(--accent)" : "3px solid transparent",
                }}>
                  <div className="avatar" style={{ width: 32, height: 32, fontSize: 12, background: "var(--bg-sunken)", color: "var(--ink-2)" }}>{emp.name[0]}</div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontWeight: 650, fontSize: 13.5 }}>{emp.name}</div>
                    <div className="muted" style={{ fontSize: 11.5 }}>총급여 {KRW(y.totalPay)}</div>
                  </div>
                  {rr.refund > 0
                    ? <span className="tag tag-ok" style={{ height: 19, fontSize: 10 }}>환급 {KRW(rr.refund)}</span>
                    : <span className="tag tag-warn" style={{ height: 19, fontSize: 10 }}>징수 {KRW(rr.due)}</span>}
                  {ctx.ssOf && ctx.ssOf(emp.id).ye && ctx.ssOf(emp.id).ye.submitted && <span title="근로자 자료 제출 도착" style={{ width: 7, height: 7, borderRadius: 99, background: "var(--ok)", flex: "none" }} />}
                </button>
              );
            })}
          </div>
        </div>

        {/* 상세 */}
        <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
          {ss.ye && ss.ye.submitted && (
            <div className="card card-pad" style={{ display: "flex", gap: 11, alignItems: "center", background: "var(--ok-soft)", border: "1px solid var(--ok-line)" }}>
              <Ms name="move_to_inbox" style={{ color: "var(--ok)", fontSize: 20, flex: "none" }} />
              <div style={{ flex: 1, fontSize: 12.5, color: "color-mix(in oklab, var(--ok) 60%, black)", lineHeight: 1.5 }}>
                <b>{e.name}</b> 근로자가 모바일로 <b>연말정산 자료를 제출</b>했습니다 (도착 {ss.ye.at}). 부양가족 {(ss.ye.items.family && ss.ye.items.family.dependents) || 0}명 · 신용카드/의료비/교육비/기부/월세/보장성보험/연금저축 입력분이 <b>아래 폼에 이미 반영</b>되어 있습니다 — 한도·요건을 검토하고 확정하세요.
              </div>
              <span className="tag tag-ok" style={{ height: 22 }}><Ms name="check" style={{ fontSize: 13 }} />제출 도착</span>
            </div>
          )}
          {/* 정산 결과 흐름 */}
          <div className="card">
            <CardHead icon="account_balance_wallet" title={`${e.name} · 연말정산 결과`} sub="근로소득공제 → 과세표준 → 산출세액 → 세액공제 → 결정세액" />
            <div className="card-pad">
              <FlowRow label="연간 총급여 (비과세 제외)" value={ye.totalPay} />
              <FlowRow label="− 근로소득공제" value={-(ye.totalPay - r.earned)} minus />
              <FlowRow label="= 근로소득금액" value={r.earned} bold />
              <FlowRow label="− 인적·소득공제" value={-r.incomeDed} minus sub={`인적 ${KRW(r.personal)} 포함`} />
              <FlowRow label="= 과세표준" value={r.base} bold />
              <FlowRow label="× 누진세율 → 산출세액" value={r.computed} sub={bracketLabel(r.base)} />
              <FlowRow label="− 근로소득세액공제" value={-r.eitc} minus />
              <FlowRow label="− 특별세액공제 (항목)" value={-r.taxCredit} minus />
              <FlowRow label="= 결정세액" value={r.determined} bold accent />
              <FlowRow label="− 기납부세액 (월 원천징수)" value={-ye.prepaidTax} minus />
              <div style={{ marginTop: 10, padding: "16px 20px", borderRadius: 12, display: "flex", alignItems: "center", justifyContent: "space-between",
                background: r.settle < 0 ? "var(--ok)" : "var(--danger)", color: "#fff" }}>
                <div>
                  <div style={{ fontSize: 12.5, opacity: .9 }}>{r.settle < 0 ? "환급 — 근로자에게 돌려줌" : "추가징수 — 근로자로부터 징수"}</div>
                  <div style={{ fontSize: 11.5, opacity: .75, marginTop: 1 }}>2월분 급여 반영 · 지방소득세 {KRW(r.localTax)}원 동반</div>
                </div>
                <div className="num" style={{ fontSize: 26, fontWeight: 800, letterSpacing: "-0.03em" }}>{r.settle < 0 ? "−" : "+"}{KRW(Math.abs(r.settle))}원</div>
              </div>
            </div>
          </div>

          {/* 공제 항목 입력 */}
          <div className="card">
            <CardHead icon="fact_check" title="공제 항목 입력" sub="입력 즉시 한도·요건 자동 검증 (확정·요건판단은 노무사)" />
            <div className="card-pad" style={{ display: "flex", flexDirection: "column", gap: 16 }}>
              <div>
                <SubLabel icon="family_restroom" text="인적공제" />
                <div style={{ display: "flex", gap: 14, flexWrap: "wrap", alignItems: "center" }}>
                  <label style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 13, cursor: "pointer" }}>
                    <input type="checkbox" checked={!!ye.family.spouse} onChange={(ev) => setFam("spouse", ev.target.checked)} /> 배우자
                  </label>
                  <NumField label="부양가족" value={ye.family.dependents} onChange={(v) => setFam("dependents", num(v))} small unit="명" />
                  <NumField label="경로(65세↑)" value={ye.family.elderly} onChange={(v) => setFam("elderly", num(v))} small unit="명" />
                  <NumField label="장애인" value={ye.family.disabled} onChange={(v) => setFam("disabled", num(v))} small unit="명" />
                  <span className="tag tag-accent" style={{ alignSelf: "center" }}>인적공제 {KRW(r.personal)}원</span>
                </div>
              </div>
              <div>
                <SubLabel icon="savings" text="소득공제" />
                <div style={{ display: "flex", gap: 14, flexWrap: "wrap" }}>
                  <DedField label="신용카드 등 사용액" value={ye.incomeItems.creditCard} onChange={(v) => setInc("creditCard", v)} det={dmap.creditCard} kind="공제소득" />
                  <DedField label="주택자금" value={ye.incomeItems.housing} onChange={(v) => setInc("housing", v)} det={dmap.housing} kind="공제소득" />
                  <div style={{ alignSelf: "flex-end", fontSize: 12, color: "var(--ink-3)", paddingBottom: 6 }}>국민연금보험료 {KRW(ye.incomeItems.pension)} <span className="muted">(전액)</span></div>
                </div>
              </div>
              <div>
                <SubLabel icon="redeem" text="세액공제" />
                <div style={{ display: "flex", gap: 14, flexWrap: "wrap" }}>
                  <NumField label="자녀 수" value={ye.creditItems.children} onChange={(v) => setCr("children", num(v))} small unit="명" hint={dmap.children && dmap.children.allowed ? "공제 " + KRW(dmap.children.allowed) : null} />
                  <DedField label="연금저축·IRP" value={ye.creditItems.pensionSavings} onChange={(v) => setCr("pensionSavings", v)} det={dmap.pensionSavings} />
                  <DedField label="보장성보험" value={ye.creditItems.insurance} onChange={(v) => setCr("insurance", v)} det={dmap.insurance} />
                  <DedField label="의료비" value={ye.creditItems.medical} onChange={(v) => setCr("medical", v)} det={dmap.medical} />
                  <DedField label="교육비" value={ye.creditItems.education} onChange={(v) => setCr("education", v)} det={dmap.education} />
                  <DedField label="기부금" value={ye.creditItems.donation} onChange={(v) => setCr("donation", v)} det={dmap.donation} />
                  <DedField label="월세액" value={ye.creditItems.rent} onChange={(v) => setCr("rent", v)} det={dmap.rent} />
                </div>
              </div>
            </div>
          </div>

          {/* 건강보험 정산 */}
          <div className="card">
            <CardHead icon="health_and_safety" title="건강보험 연말정산" sub={`${taxYear}년 보수총액 ÷ 근무 ${hs.months}개월 기준 · ${taxYear + 1}년 4월분 급여 반영`}
              right={hs.noticed != null ? <span className="tag tag-ok"><Ms name="verified" style={{ fontSize: 13 }} />공단 고지액 적용</span>
                : <span className="tag tag-warn"><Ms name="calculate" style={{ fontSize: 13 }} />우리 추정치 — 고지액 입력 전</span>} />
            <div className="card-pad" style={{ display: "flex", gap: 14, flexWrap: "wrap", alignItems: "center" }}>
              <StatBox label="전년 보수총액" value={KRW(ye.prevYearWageTotal) + "원"} note={`정산 보수월액 ${KRW(hs.monthlyWage)}원`} />
              <Ms name="close" style={{ color: "var(--ink-4)", alignSelf: "center", fontSize: 16 }} />
              <StatBox label="건강보험요율" value={window.BARUNSEM.pctLabel(rs.hiRate)} />
              <Ms name="east" style={{ color: "var(--ink-4)", alignSelf: "center" }} />
              <StatBox label="정산보험료" value={KRW(hs.settled) + "원"} note={"장기요양 " + KRW(hs.ltc) + "원 동반"} />
              <Ms name="remove" style={{ color: "var(--ink-4)", alignSelf: "center" }} />
              <StatBox label="기납부" value={KRW(hs.prepaid) + "원"} />
              <Ms name="east" style={{ color: "var(--ink-4)", alignSelf: "center" }} />
              <StatBox label={hs.diff >= 0 ? "추가납부" : "환급"} value={KRW(Math.abs(hs.diff)) + "원"} accent={hs.diff < 0} ok={hs.diff < 0}
                note={hs.installments > 1 ? `${hs.installments}회 분납 · 월 ${KRW(Math.abs(hs.perMonth))}원` : "일시 반영"} />
            </div>
            <div className="card-pad" style={{ borderTop: "1px solid var(--line)", display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))", gap: 12 }}>
              <div className="field"><label>공단 고지액 (정산보험료)</label>
                <input className="input num" placeholder={`추정 ${KRW(hs.settled)}`} value={hsIn.noticed != null ? hsIn.noticed : ""}
                  onChange={(ev) => setHs({ noticed: ev.target.value.replace(/[^\d]/g, "") })} />
                <div className="muted" style={{ fontSize: 10.5, marginTop: 4 }}>공단 고지서 금액을 넣으면 이 값이 정산 기준이 됩니다.</div>
              </div>
              <div className="field"><label>분할 납부 회차</label>
                <select className="select" value={hsIn.installments || 1} onChange={(ev) => setHs({ installments: Number(ev.target.value) })}>
                  {[1, 2, 3, 5, 10].map((n) => <option key={n} value={n}>{n === 1 ? "일시 (1회)" : n + "회 분납"}</option>)}
                </select>
                <div className="muted" style={{ fontSize: 10.5, marginTop: 4 }}>급여 반영액 = 차액 ÷ 회차.</div>
              </div>
              <div className="field"><label>급여 반영</label>
                <button className="btn btn-primary" style={{ width: "100%" }}
                  onClick={() => { ctx.applyHealthSettlement(client.id, e.id, hs); }}>
                  <Ms name="playlist_add" />{taxYear + 1}년 4월 급여에 {hs.diff >= 0 ? "추가공제" : "환급"} {KRW(Math.abs(hs.perMonth))}원 반영
                </button>
                <div className="muted" style={{ fontSize: 10.5, marginTop: 4 }}>기타공제 항목으로 해당 월 변동분에 실립니다.</div>
              </div>
            </div>
          </div>

          {/* B12 중도 퇴사자 — 연말정산 경로가 따로 있어야 한다 */}
          {midLeaver && (
            <div className="card card-pad" style={{ display: "flex", gap: 12, alignItems: "center", background: "var(--warn-soft)", border: "1px solid var(--warn-line)" }}>
              <Ms name="logout" style={{ color: "var(--warn)", fontSize: 22, flex: "none" }} />
              <div style={{ flex: 1, fontSize: 12.5, lineHeight: 1.6, color: "color-mix(in oklab, var(--warn) 55%, black)" }}>
                <b>{e.name}</b> 근로자는 {e.left} 퇴사 — <b>퇴직자 정산</b> 대상입니다. 퇴직월 급여 지급 시 그때까지의 근로소득으로 정산하고 원천징수영수증을 교부해야 합니다.
                근무 {hs.months}개월 기준으로 건보 보수월액도 안분됩니다.
              </div>
              <button className="btn btn-default btn-sm" onClick={() => ctx.go("documents", { clientId: client.id, empId: e.id })}><Ms name="receipt" />원천징수영수증</button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function num(v) { const n = Number(String(v).replace(/[^\d.-]/g, "")); return isFinite(n) ? n : 0; }
function bracketLabel(base) {
  const b = window.BARUNSEM.TAX_BRACKETS.find((x) => base <= x[0]);
  return "세율 " + Math.round(b[1] * 100) + "% · 누진공제 " + KRW(b[2]) + "원";
}

function FlowRow({ label, value, minus, bold, accent, sub }) {
  return (
    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "7px 0", borderBottom: "1px solid var(--line)" }}>
      <div>
        <span style={{ fontSize: 13, fontWeight: bold ? 700 : 500, color: bold ? "var(--ink)" : "var(--ink-2)" }}>{label}</span>
        {sub && <span className="muted" style={{ fontSize: 11, marginLeft: 7 }}>{sub}</span>}
      </div>
      <span className="num" style={{ fontWeight: bold ? 750 : 600, fontSize: bold ? 15 : 13.5, color: accent ? "var(--accent-ink)" : minus ? "var(--danger)" : "var(--ink)" }}>
        {minus ? "−" : ""}{KRW(Math.abs(value))}
      </span>
    </div>
  );
}

function SubLabel({ icon, text }) {
  return <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 9, fontSize: 12, fontWeight: 700, color: "var(--ink-2)" }}><Ms name={icon} style={{ fontSize: 16, color: "var(--accent)" }} />{text}</div>;
}

function NumField({ label, value, onChange, small, unit, hint }) {
  return (
    <div>
      <div style={{ fontSize: 11, color: "var(--ink-3)", fontWeight: 600, marginBottom: 3 }}>{label}</div>
      <div style={{ display: "flex", alignItems: "center", gap: 4 }}>
        <input className="input" type="number" value={value} onChange={(e) => onChange(e.target.value)}
          style={{ width: small ? 64 : 130, height: 32, padding: "0 8px", fontSize: 13, textAlign: "right" }} />
        {unit && <span className="muted" style={{ fontSize: 12 }}>{unit}</span>}
      </div>
      {hint && <div style={{ fontSize: 10.5, color: "var(--accent-ink)", marginTop: 2 }}>{hint}</div>}
    </div>
  );
}

function DedField({ label, value, onChange, det, kind }) {
  const capped = det && det.capped;
  return (
    <div style={{ minWidth: 150 }}>
      <div style={{ fontSize: 11, color: "var(--ink-3)", fontWeight: 600, marginBottom: 3 }}>{label}</div>
      <input className="input" type="number" value={value} onChange={(e) => onChange(e.target.value)}
        style={{ width: 150, height: 32, padding: "0 8px", fontSize: 13, textAlign: "right", borderColor: capped ? "var(--warn-line)" : "var(--line-2)" }} />
      <div style={{ fontSize: 10.5, marginTop: 3, minHeight: 14 }}>
        {det && (det.allowed > 0 || det.reason)
          ? <span style={{ color: capped ? "color-mix(in oklab, var(--warn) 55%, black)" : "var(--ink-3)" }}>
              {capped && <Ms name="warning" style={{ fontSize: 12, verticalAlign: "-2px" }} />} {kind === "공제소득" ? "공제소득" : "세액공제"} {KRW(det.allowed)}원{det.reason ? " · " + det.reason : ""}
            </span>
          : <span className="muted">미입력</span>}
      </div>
    </div>
  );
}

Object.assign(window, { YearEnd });
