/* 가온 학적부 — 순수 계산 로직. 브라우저와 Node 테스트가 같은 함수를 공유한다. */
(function (global) {
  "use strict";

  const attSummary = (row) => {
    const days = (row || []).filter((v) => v !== null && v !== undefined);
    if (!days.length) return "휴학";
    const att = days.filter((v) => v === 2).length;
    return `${Math.round((att / days.length) * 100)}%`;
  };

  // 일별 합계 — marks 는 '행 배열'의 목록이다. v11 사고(행 자체를 세어 0/3) 방지가 이 함수의 존재 이유.
  const dayTotal = (marks, d) =>
    marks.filter((row) => row && row[d] !== null && row[d] !== undefined).length;
  const dayPresent = (marks, d) =>
    marks.filter((row) => row && row[d] === 2).length;

  const counts = (marks) => {
    const flat = (marks || []).filter(Boolean).flat();
    const att = flat.filter((v) => v === 2).length;
    const late = flat.filter((v) => v === 1).length;
    const abs = flat.filter((v) => v === 0).length;
    return {
      att, late, abs, total: flat.length,
      rate: flat.length ? Math.round((att / flat.length) * 100) : 0,
    };
  };

  // 명단 통계 — 0명 나눗셈 가드 포함
  const rosterStats = (students) => {
    const list = students || [];
    const active = list.filter((s) => s.status === "재학");
    const avgAtt = active.length
      ? Math.round(active.reduce((a, s) => a + (s.att || 0), 0) / active.length)
      : 0;
    const hw = active.reduce(
      (a, s) => {
        const [done, total] = String(s.hw || "0/0").split("/").map(Number);
        return { done: a.done + (done || 0), total: a.total + (total || 0) };
      },
      { done: 0, total: 0 }
    );
    return {
      total: list.length,
      active: active.length,
      off: list.length - active.length,
      avgAtt,
      hwDone: hw.done,
      hwTotal: hw.total,
      hwRate: hw.total ? Math.round((hw.done / hw.total) * 100) : 0,
    };
  };

  const api = { attSummary, dayTotal, dayPresent, counts, rosterStats };
  global.GAON = api;
  if (typeof module !== "undefined") module.exports = api;
})(typeof window !== "undefined" ? window : globalThis);
