/* ============================================================
   바른셈 — 근태 캘린더 · 시프트 편성 (고객사 포털 제공 툴)
   점주·매니저가 직원 시프트를 캘린더로 편성 → e.timesheet 생성 →
   deriveVariation(커널)이 연장·야간·휴일·결근 자동 산출. 주52h·인건비·휴식위반 실시간.
   월간 그리드 / 주간 시프트보드 토글 · 반응형.
   ============================================================ */
const SC_DOW = ["월", "화", "수", "목", "금", "토", "일"];

/* ── 날짜 헬퍼 (로컬 기준, 결정적) ── */
function scYmDays(ym) {
  const p = ym.split("-").map(Number), Y = p[0], Mo = p[1];
  const dim = new Date(Y, Mo, 0).getDate();
  const out = [];
  for (let d = 1; d <= dim; d++) out.push(ym + "-" + String(d).padStart(2, "0"));
  return out;
}
function scDow(ds) { const dt = new Date(ds + "T00:00:00"); return (dt.getDay() + 6) % 7; } // 월=0
function scMondayOf(ds) { const dt = new Date(ds + "T00:00:00"); dt.setDate(dt.getDate() - scDow(ds)); return scIso(dt); }
function scIso(dt) { return dt.getFullYear() + "-" + String(dt.getMonth() + 1).padStart(2, "0") + "-" + String(dt.getDate()).padStart(2, "0"); }
function scAdd(ds, n) { const dt = new Date(ds + "T00:00:00"); dt.setDate(dt.getDate() + n); return scIso(dt); }
function scWeekDates(monday) { return Array.from({ length: 7 }, (_, i) => scAdd(monday, i)); }
function scMD(ds) { const p = ds.split("-"); return Number(p[1]) + "/" + Number(p[2]); }

/* 시프트 셀 → 일별 근태 레코드 (deriveVariation 입력) */
function scCellToDay(date, cell) {
  if (!cell) return null;
  if (cell.off) return { date, type: "off" };
  return { date, in: cell.in, out: cell.out, breakMin: cell.breakMin != null ? cell.breakMin : 60, type: cell.type || "work" };
}

function ShiftCalendar({ client, ym, onApply, toast }) {
  const B = window.BARUNSEM;
  const rb = B.attendanceRules(client);
  const [templates, setTemplates] = useState(() => (client.shiftTemplates || []).map((t) => ({ ...t })));
  const tplMap = Object.fromEntries(templates.map((t) => [t.id, t]));
  const [tplMgr, setTplMgr] = useState(false);
  const WORK_H = (B.RULESET && B.RULESET.workHours) || 209;
  const HOLI = (B.RULEBOOK.HOLIDAYS && B.RULEBOOK.HOLIDAYS[ym.slice(0, 4)]) || [];
  const emps = client.employees;
  const monthDays = useMemo(() => scYmDays(ym), [ym]);

  const seed = () => {
    const s = {};
    emps.forEach((e) => {
      s[e.id] = {};
      const ts = e.timesheet;
      if (ts && ts.ym === ym) ts.days.forEach((d) => {
        if (d.type === "off") s[e.id][d.date] = { off: true };
        else if (d.in && d.out) s[e.id][d.date] = { in: d.in, out: d.out, breakMin: d.breakMin != null ? d.breakMin : 60, type: d.type || "work" };
      });
    });
    return s;
  };
  const [schedule, setSchedule] = useState(seed);
  const [view, setView] = useState("week");
  const [weekAnchor, setWeekAnchor] = useState(() => scMondayOf(ym + "-01"));
  const [focusEmp, setFocusEmp] = useState(emps[0].id);
  const [edit, setEdit] = useState(null);          // { empId, date }
  const [swapMode, setSwapMode] = useState(false);
  const [swapPick, setSwapPick] = useState(null);  // { empId, date }

  const setCell = (empId, date, cell) => setSchedule((s) => {
    const emp = { ...(s[empId] || {}) };
    if (cell == null) delete emp[date]; else emp[date] = cell;
    return { ...s, [empId]: emp };
  });

  /* ── 파생 계산 ── */
  const empHourly = (e) => e.hourlyMode ? (e.hourly || 0) : Math.round((e.base || 0) / WORK_H);
  const buildDays = (empId) => Object.keys(schedule[empId] || {}).sort().map((d) => scCellToDay(d, schedule[empId][d])).filter(Boolean);
  const cellHours = (cell) => { if (!cell || cell.off) return 0; const s = B.splitDay(scCellToDay("2000-01-01", cell), rb); return Math.round((s.work + s.hol + s.holOver) * 10) / 10; };

  const derivedOf = (e) => B.deriveVariation({ ym, days: buildDays(e.id) }, e, rb);
  // D4 — 휴식 11h·연속근무 6일·주 52h가 네 파일에 흩어져 있던 자리. 룰셋이 단일 진실.
  const RS0 = B.RULESET;
  const REST_H = RS0.restBetweenH != null ? RS0.restBetweenH : 11;
  const MAX_CONSEC = RS0.maxConsecutiveDays != null ? RS0.maxConsecutiveDays : 6;
  const WEEK_TOTAL_CAP = RS0.weekTotalCap != null ? RS0.weekTotalCap : 52;
  // 휴식위반(연속 시프트 간 11h 미만) + 연속근무(>6일) 카운트
  const restViol = (empId) => {
    const dates = Object.keys(schedule[empId] || {}).filter((d) => !schedule[empId][d].off).sort();
    let rest = 0, run = 0, maxRun = 0;
    const allDates = Object.keys(schedule[empId] || {}).sort();
    for (let i = 1; i < dates.length; i++) {
      const a = schedule[empId][dates[i - 1]], b = schedule[empId][dates[i]];
      if (scAdd(dates[i - 1], 1) !== dates[i]) continue;        // 연속일만
      const hm = (s) => { const p = String(s).split(":").map(Number); return p[0] * 60 + (p[1] || 0); };
      let aOut = hm(a.out); if (aOut <= hm(a.in)) aOut += 1440;
      const gap = (1440 - aOut) + hm(b.in);                    // 전일 퇴근 → 익일 출근(분)
      if (gap < REST_H * 60) rest++;
    }
    // 연속근무일
    let prev = null;
    allDates.forEach((d) => {
      const c = schedule[empId][d];
      if (c && !c.off) { run = (prev && scAdd(prev, 1) === d) ? run + 1 : 1; maxRun = Math.max(maxRun, run); prev = d; }
      else { run = 0; prev = c && c.off ? null : prev; }
    });
    return { rest, consec: maxRun > MAX_CONSEC ? maxRun : 0 };
  };
  const empSummary = (e) => {
    const dv = derivedOf(e);
    const hourly = empHourly(e);
    // B9 — 인건비는 계산 커널을 그대로 돌려 얻는다. 화면이 자체 공식을 쓰면 급여대장과 다른 숫자가 나온다.
    const cost = B.runFor({ ...e, variation: { ...(e.variation || {}), overtime: dv.overtime, night: dv.night, holiday: dv.holiday, holidayOver: dv.holidayOver, absentDays: dv.absentDays, weeks: dv.weeks } }, client, ym).gross;
    const over52 = (dv.weeks || []).filter((w) => (w.wkWork != null ? w.wkWork : w.wkHours) > WEEK_TOTAL_CAP).length;
    const v = restViol(e.id);
    return { dv, hourly, cost, over52, rest: v.rest, consec: v.consec };
  };
  const allSummary = useMemo(() => emps.map((e) => ({ e, ...empSummary(e) })), [schedule]);
  const totals = allSummary.reduce((a, x) => ({ hours: a.hours + x.dv.workedHours, cost: a.cost + x.cost, over52: a.over52 + x.over52, rest: a.rest + x.rest, assigned: a.assigned + Object.keys(schedule[x.e.id] || {}).filter((d) => !schedule[x.e.id][d].off).length }), { hours: 0, cost: 0, over52: 0, rest: 0, assigned: 0 });

  /* ── 셀 칩 스타일 ── */
  const chipStyle = (cell) => {
    if (!cell) return null;
    if (cell.off) return { background: "var(--bg-sunken)", color: "var(--ink-4)", borderColor: "var(--line)" };
    if (cell.type === "holiday") return { background: "var(--danger-soft)", color: "var(--danger)", borderColor: "var(--danger-line)" };
    const hue = cell.tpl && tplMap[cell.tpl] ? tplMap[cell.tpl].hue : 250;
    return { background: `oklch(0.955 0.035 ${hue})`, color: `oklch(0.45 0.12 ${hue})`, borderColor: `oklch(0.88 0.06 ${hue})` };
  };
  const cellLabel = (cell) => {
    if (!cell) return null;
    if (cell.off) return "휴무";
    const t = cell.tpl && tplMap[cell.tpl];
    return t ? t.name : (cell.in + "–" + cell.out);
  };

  /* ── 셀 클릭 (편성 or 맞교환) ── */
  const onCellClick = (empId, date) => {
    if (!swapMode) { setEdit({ empId, date }); return; }
    if (!swapPick) { setSwapPick({ empId, date }); return; }
    // 두 번째 선택 → 스왑
    const a = swapPick, b = { empId, date };
    const ca = (schedule[a.empId] || {})[a.date] || null;
    const cb = (schedule[b.empId] || {})[b.date] || null;
    setCell(a.empId, a.date, cb); setCell(b.empId, b.date, ca);
    toast && toast("시프트를 맞교환했습니다", "ok");
    setSwapPick(null);
  };

  const copyLastWeek = () => {
    const prevMon = scAdd(weekAnchor, -7);
    const cur = scWeekDates(weekAnchor), prev = scWeekDates(prevMon);
    setSchedule((s) => {
      const ns = { ...s };
      emps.forEach((e) => {
        const emp = { ...(ns[e.id] || {}) };
        cur.forEach((d, i) => { const src = (s[e.id] || {})[prev[i]]; if (src) emp[d] = { ...src }; });
        ns[e.id] = emp;
      });
      return ns;
    });
    toast && toast("지난주 편성을 이번 주에 복사했습니다", "ok");
  };

  const applyToRows = () => {
    const map = {};
    emps.forEach((e) => { const dv = derivedOf(e); map[e.id] = { overtime: dv.overtime, night: dv.night, holiday: dv.holiday + dv.holidayOver, absentDays: dv.absentDays }; });
    onApply(map);
  };

  const weekDates = scWeekDates(weekAnchor);
  const isHoli = (d) => HOLI.includes(d) || scDow(d) >= 5;

  return (
    <div className="sc-wrap">
      {/* 요약 스트립 */}
      <div className="sc-summary">
        <SCStat icon="schedule" label="편성 근로시간" value={Math.round(totals.hours) + "h"} />
        <SCStat icon="payments" label="인건비 추정" value={KRW(totals.cost) + "원"} accent />
        <SCStat icon="warning" label="주52h 초과 주" value={totals.over52 + "건"} tone={totals.over52 ? "danger" : null} />
        <SCStat icon="bedtime" label={`휴식 ${REST_H}h 위반`} value={totals.rest + "건"} tone={totals.rest ? "warn" : null} />
        <div style={{ flex: 1 }} />
        <button className="btn btn-primary" onClick={applyToRows}><Ms name="auto_fix_high" />이 근태로 변동분 채우기</button>
      </div>

      {/* 툴바 */}
      <div className="sc-toolbar">
        <div className="seg" style={{ height: 34 }}>
          <button className={view === "week" ? "on" : ""} onClick={() => setView("week")}><Ms name="view_week" style={{ fontSize: 15, verticalAlign: "-3px" }} /> 주간 시프트보드</button>
          <button className={view === "month" ? "on" : ""} onClick={() => setView("month")}><Ms name="calendar_month" style={{ fontSize: 15, verticalAlign: "-3px" }} /> 월간 그리드</button>
        </div>
        <div style={{ flex: 1 }} />
        <button className="btn btn-default btn-sm" onClick={() => setTplMgr(true)} title="사업장 시프트 사전 정의"><Ms name="tune" />시프트 관리 <span className="num" style={{ opacity: .6 }}>{templates.length}</span></button>
        {view === "week" ? (<>
          <button className={"btn btn-default btn-sm" + (swapMode ? " on" : "")} style={swapMode ? { background: "var(--accent-soft)", borderColor: "var(--accent-line)", color: "var(--accent-ink)" } : null} onClick={() => { setSwapMode((v) => !v); setSwapPick(null); }} title="두 시프트를 골라 맞교환"><Ms name="swap_horiz" />{swapMode ? "맞교환 중…" : "교대 맞교환"}</button>
          <button className="btn btn-default btn-sm" onClick={copyLastWeek} title="지난주 편성을 그대로 복사"><Ms name="content_copy" />지난주 복사</button>
          <div className="sc-nav">
            <button className="iconbtn" aria-label="이전 주" title="이전 주" onClick={() => setWeekAnchor(scAdd(weekAnchor, -7))}><Ms name="chevron_left" /></button>
            <span className="num">{scMD(weekDates[0])} – {scMD(weekDates[6])}</span>
            <button className="iconbtn" aria-label="다음 주" title="다음 주" onClick={() => setWeekAnchor(scAdd(weekAnchor, 7))}><Ms name="chevron_right" /></button>
          </div>
        </>) : (
          <select className="select" style={{ height: 34, maxWidth: 220 }} value={focusEmp} onChange={(e) => setFocusEmp(e.target.value)}>
            {emps.map((e) => <option key={e.id} value={e.id}>{e.name} · {e.dept}</option>)}
          </select>
        )}
      </div>

      {swapMode && <div className="sc-hint"><Ms name="touch_app" style={{ fontSize: 15 }} />맞교환할 시프트 두 칸을 차례로 누르세요{swapPick ? ` — ${emps.find((e) => e.id === swapPick.empId).name} ${scMD(swapPick.date)} 선택됨` : ""}</div>}

      {view === "week"
        ? <WeekBoard emps={emps} weekDates={weekDates} schedule={schedule} chipStyle={chipStyle} cellLabel={cellLabel} cellHours={cellHours} onCellClick={onCellClick} summaryOf={(id) => allSummary.find((x) => x.e.id === id)} isHoli={isHoli} swapPick={swapPick} />
        : <MonthGrid emp={emps.find((e) => e.id === focusEmp)} monthDays={monthDays} ym={ym} schedule={schedule} chipStyle={chipStyle} cellLabel={cellLabel} cellHours={cellHours} onCellClick={onCellClick} summary={allSummary.find((x) => x.e.id === focusEmp)} isHoli={isHoli} />}

      <div className="sc-note">
        <Ms name="info" style={{ fontSize: 15, color: "var(--accent)" }} />
        점주·매니저가 편성한 시프트가 그대로 근태가 됩니다. 연장(1일 8h 초과)·야간(22–06시)·휴일은 자동 산출되며, 노무사 검수 후 확정됩니다 — 엑셀·표 입력이 필요 없습니다.
      </div>

      {edit && <ShiftEditor client={client} emp={emps.find((e) => e.id === edit.empId)} date={edit.date} cell={(schedule[edit.empId] || {})[edit.date] || null}
        templates={templates} onClose={() => setEdit(null)}
        onSet={(cell) => { setCell(edit.empId, edit.date, cell); setEdit(null); }}
        onApplyWeekdays={(cell) => {
          const mon = scMondayOf(edit.date);
          setSchedule((s) => { const emp = { ...(s[edit.empId] || {}) }; scWeekDates(mon).slice(0, 5).forEach((d) => { emp[d] = { ...cell }; }); return { ...s, [edit.empId]: emp }; });
          setEdit(null); toast && toast("이번 주 평일(월–금)에 적용했습니다", "ok");
        }} />}
      {tplMgr && <ShiftTemplateManager templates={templates} onClose={() => setTplMgr(false)} onChange={(list) => { setTemplates(list); toast && toast("시프트 템플릿을 저장했습니다", "ok"); }} />}
    </div>
  );
}

/* 주간 시프트보드 — 직원 × 7일 (가로 스크롤·sticky 직원열) */
function WeekBoard({ emps, weekDates, schedule, chipStyle, cellLabel, cellHours, onCellClick, summaryOf, isHoli, swapPick }) {
  return (
    <div className="sc-board">
      <table>
        <thead>
          <tr>
            <th className="sc-emcol">직원 · 주간</th>
            {weekDates.map((d, i) => <th key={d} className={isHoli(d) ? "sc-holi" : ""}>{SC_DOW[i]} <span className="num">{scMD(d)}</span></th>)}
          </tr>
        </thead>
        <tbody>
          {emps.map((e) => {
            const sm = summaryOf(e.id);
            const wk = (sm.dv.weeks || []).find((w) => weekDates.includes(w.wk)) || null;
            const wkHours = wk ? wk.wkHours : weekDates.reduce((s, d) => s + cellHours((schedule[e.id] || {})[d]), 0);
            const over = wkHours > 52;
            return (
              <tr key={e.id}>
                <td className="sc-emcol">
                  <div style={{ fontWeight: 650, fontSize: 12.5 }}>{e.name}</div>
                  <div style={{ display: "flex", alignItems: "center", gap: 5, marginTop: 2 }}>
                    <span className="muted" style={{ fontSize: 10.5 }}>{e.dept}</span>
                    <span className={"sc-wk" + (over ? " over" : "")}>{Math.round(wkHours * 10) / 10}h</span>
                    {over && <Ms name="warning" style={{ fontSize: 12, color: "var(--danger)" }} title="주52h 초과" />}
                  </div>
                </td>
                {weekDates.map((d) => {
                  const cell = (schedule[e.id] || {})[d];
                  const picked = swapPick && swapPick.empId === e.id && swapPick.date === d;
                  return (
                    <td key={d} className={isHoli(d) ? "sc-holi-cell" : ""}>
                      <button className={"sc-cell" + (picked ? " picked" : "")} onClick={() => onCellClick(e.id, d)}>
                        {cell ? <span className="sc-chip" style={chipStyle(cell)}>{cellLabel(cell)}{!cell.off && <em>{cellHours(cell)}h</em>}</span>
                          : <span className="sc-plus"><Ms name="add" style={{ fontSize: 15 }} /></span>}
                      </button>
                    </td>
                  );
                })}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

/* 월간 그리드 — 직원 1명 포커스 */
function MonthGrid({ emp, monthDays, ym, schedule, chipStyle, cellLabel, cellHours, onCellClick, summary, isHoli }) {
  const lead = scDow(monthDays[0]);  // 첫날 앞 빈칸(월=0)
  const cells = [...Array(lead).fill(null), ...monthDays];
  return (
    <div>
      <div className="sc-mhead">
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <div className="avatar" style={{ width: 30, height: 30, fontSize: 12, background: "var(--bg-sunken)", color: "var(--ink-2)" }}>{emp.name[0]}</div>
          <div><div style={{ fontWeight: 650, fontSize: 13.5 }}>{emp.name}</div><div className="muted" style={{ fontSize: 11.5 }}>{emp.dept} · {emp.title}</div></div>
        </div>
        <div style={{ flex: 1 }} />
        <div className="sc-mstats">
          <span>편성 {summary.dv.workDays}일</span>
          <span>근로 {summary.dv.workedHours}h</span>
          <span className={summary.dv.overtime ? "hot" : ""}>연장 {summary.dv.overtime}h</span>
          <span className={summary.dv.night ? "hot" : ""}>야간 {summary.dv.night}h</span>
          {summary.over52 > 0 && <span className="bad"><Ms name="warning" style={{ fontSize: 12, verticalAlign: "-2px" }} />주52 {summary.over52}</span>}
          {summary.rest > 0 && <span className="bad">휴식위반 {summary.rest}</span>}
          <span className="cost">인건비 {KRW(summary.cost)}원</span>
        </div>
      </div>
      <div className="sc-monthgrid sc-mg-head">{SC_DOW.map((w, i) => <div key={w} className={i >= 5 ? "sc-holi" : ""}>{w}</div>)}</div>
      <div className="sc-monthgrid">
        {cells.map((d, i) => d == null
          ? <div key={"b" + i} className="sc-mcell empty" />
          : (() => {
            const cell = (schedule[emp.id] || {})[d];
            return (
              <button key={d} className={"sc-mcell" + (isHoli(d) ? " holi" : "")} onClick={() => onCellClick(emp.id, d)}>
                <span className="sc-mdate">{Number(d.split("-")[2])}</span>
                {cell ? <span className="sc-chip" style={chipStyle(cell)}>{cellLabel(cell)}{!cell.off && <em>{cellHours(cell)}h</em>}</span>
                  : <span className="sc-plus sm"><Ms name="add" style={{ fontSize: 14 }} /></span>}
              </button>
            );
          })())}
      </div>
    </div>
  );
}

/* 시프트 편집 모달 */
function ShiftEditor({ client, emp, date, cell, templates, onClose, onSet, onApplyWeekdays }) {
  const [tab, setTab] = useState(cell && !cell.off && !cell.tpl ? "custom" : "tpl");
  const [cin, setCin] = useState(cell && cell.in || "09:00");
  const [cout, setCout] = useState(cell && cell.out || "18:00");
  const [brk, setBrk] = useState(cell && cell.breakMin != null ? cell.breakMin : 60);
  const [holiday, setHoliday] = useState(cell && cell.type === "holiday");
  const dow = SC_DOW[scDow(date)];
  const assignTpl = (t) => onSet({ tpl: t.id, in: t.in, out: t.out, breakMin: t.breakMin, type: holiday ? "holiday" : "work" });
  const assignCustom = () => onSet({ in: cin, out: cout, breakMin: Number(brk) || 0, type: holiday ? "holiday" : "work" });

  return (
    <Modal title={`${emp.name} · ${scMD(date)}(${dow}) 시프트`} onClose={onClose} width={460}
      footer={<>
        <button className="btn btn-default" onClick={() => onSet(null)}><Ms name="backspace" />미배정</button>
        <div style={{ flex: 1 }} />
        <button className="btn btn-default" onClick={() => onSet({ off: true })}><Ms name="weekend" />휴무</button>
      </>}>
      <div className="seg" style={{ marginBottom: 14 }}>
        <button className={tab === "tpl" ? "on" : ""} onClick={() => setTab("tpl")}>시프트 템플릿</button>
        <button className={tab === "custom" ? "on" : ""} onClick={() => setTab("custom")}>직접 입력</button>
      </div>

      <label style={{ display: "flex", alignItems: "center", gap: 7, fontSize: 12.5, marginBottom: 12, cursor: "pointer" }}>
        <input type="checkbox" checked={holiday} onChange={(e) => setHoliday(e.target.checked)} /> 휴일근로로 처리 (8h 이내 +50% / 초과 +100%)
      </label>

      {tab === "tpl" ? (
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 9 }}>
          {templates.map((t) => (
            <button key={t.id} onClick={() => assignTpl(t)} style={{ display: "flex", flexDirection: "column", alignItems: "flex-start", gap: 2, padding: "12px 14px", borderRadius: 11, cursor: "pointer",
              border: "1px solid " + `oklch(0.88 0.06 ${t.hue})`, background: `oklch(0.97 0.03 ${t.hue})`, color: `oklch(0.42 0.12 ${t.hue})`, fontFamily: "inherit" }}>
              <span style={{ fontWeight: 750, fontSize: 14 }}>{t.name}</span>
              <span className="num" style={{ fontSize: 12 }}>{t.in}–{t.out}</span>
              <span style={{ fontSize: 10.5, opacity: .8 }}>휴게 {t.breakMin}분</span>
            </button>
          ))}
        </div>
      ) : (
        <div className="form-2">
          <div className="field"><label>출근</label><input className="input num" value={cin} onChange={(e) => setCin(e.target.value)} placeholder="09:00" /></div>
          <div className="field"><label>퇴근</label><input className="input num" value={cout} onChange={(e) => setCout(e.target.value)} placeholder="18:00" /></div>
          <div className="field"><label>휴게(분)</label><input className="input num" value={brk} onChange={(e) => setBrk(e.target.value.replace(/[^\d]/g, ""))} placeholder="60" /></div>
          <div className="field" style={{ alignSelf: "flex-end" }}><button className="btn btn-primary" style={{ width: "100%" }} onClick={assignCustom}><Ms name="check" />이 시프트 배정</button></div>
        </div>
      )}

      <div style={{ marginTop: 14, paddingTop: 12, borderTop: "1px solid var(--line)" }}>
        <button className="btn btn-ghost btn-sm" onClick={() => {
          const t = templates[0];
          onApplyWeekdays(tab === "custom" ? { in: cin, out: cout, breakMin: Number(brk) || 0, type: holiday ? "holiday" : "work" } : { tpl: t.id, in: t.in, out: t.out, breakMin: t.breakMin, type: "work" });
        }}><Ms name="repeat" />{tab === "custom" ? "이 시프트" : templates[0].name}를 이번 주 평일(월–금)에 일괄 적용</button>
      </div>
    </Modal>
  );
}

/* 시프트 템플릿 관리 — 사업장별 사전 정의(추가·수정·삭제) */
function ShiftTemplateManager({ templates, onClose, onChange }) {
  const [list, setList] = useState(templates.map((t) => ({ ...t })));
  const HUES = [255, 190, 35, 300, 150, 12, 210, 330];
  const upd = (i, k, v) => setList((l) => l.map((t, j) => j === i ? { ...t, [k]: v } : t));
  const add = () => setList((l) => [...l, { id: "t" + Math.random().toString(36).slice(2, 6), name: "새 시프트", in: "09:00", out: "18:00", breakMin: 60, hue: 210 }]);
  const del = (i) => setList((l) => l.filter((_, j) => j !== i));
  const tin = { width: 62, height: 30, padding: "0 8px", fontSize: 12.5, textAlign: "center" };
  return (
    <Modal title="시프트 템플릿 관리" width={600} onClose={onClose}
      footer={<><button className="btn btn-default" onClick={onClose}>취소</button><button className="btn btn-primary" onClick={() => { onChange(list.filter((t) => t.name.trim())); onClose(); }}><Ms name="check" />저장</button></>}>
      <p className="muted" style={{ fontSize: 12.5, marginBottom: 14, lineHeight: 1.55 }}>이 사업장에서 쓰는 시프트를 <b>사전에 정의</b>합니다. 캘린더에서 클릭 한 번으로 배정돼요 — 외식은 오픈/미들/마감, 제조는 주간/야간 2교대처럼 업종에 맞게 구성하세요.</p>
      <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
        {list.map((t, i) => (
          <div key={t.id} style={{ display: "flex", alignItems: "center", gap: 8, padding: "9px 11px", border: "1px solid var(--line)", borderRadius: 11, background: `oklch(0.985 0.018 ${t.hue})`, flexWrap: "wrap" }}>
            <span style={{ width: 8, height: 28, borderRadius: 4, background: `oklch(0.62 0.14 ${t.hue})`, flex: "none" }} />
            <input className="input" value={t.name} onChange={(e) => upd(i, "name", e.target.value)} placeholder="이름" style={{ width: 84, height: 30, fontSize: 13, fontWeight: 650 }} />
            <input className="input num" value={t.in} onChange={(e) => upd(i, "in", e.target.value)} style={tin} />
            <span className="muted">–</span>
            <input className="input num" value={t.out} onChange={(e) => upd(i, "out", e.target.value)} style={tin} />
            <span className="muted" style={{ fontSize: 12 }}>휴게</span>
            <input className="input num" value={t.breakMin} onChange={(e) => upd(i, "breakMin", Number(e.target.value.replace(/[^\d]/g, "")) || 0)} style={{ width: 48, height: 30, padding: "0 6px", fontSize: 12.5, textAlign: "center" }} />
            <span className="muted" style={{ fontSize: 12 }}>분</span>
            <div style={{ display: "flex", gap: 4, marginLeft: 4 }}>
              {HUES.map((h) => (
                <button key={h} onClick={() => upd(i, "hue", h)} title="색" style={{ width: 18, height: 18, borderRadius: "50%", cursor: "pointer", background: `oklch(0.62 0.15 ${h})`, border: t.hue === h ? "2px solid var(--ink)" : "2px solid transparent", padding: 0 }} />
              ))}
            </div>
            <div style={{ flex: 1 }} />
            <button className="iconbtn" aria-label="시프트 템플릿 삭제" style={{ width: 30, height: 30 }} onClick={() => del(i)} title="삭제"><Ms name="close" style={{ fontSize: 16 }} /></button>
          </div>
        ))}
        {list.length === 0 && <div className="muted" style={{ fontSize: 12.5, padding: "10px 0", textAlign: "center" }}>시프트가 없습니다. 아래에서 추가하세요.</div>}
      </div>
      <button className="btn btn-default btn-sm" style={{ marginTop: 12 }} onClick={add}><Ms name="add" />시프트 추가</button>
    </Modal>
  );
}

function SCStat({ icon, label, value, accent, tone }) {
  const c = tone === "danger" ? { bg: "var(--danger-soft)", line: "var(--danger-line)", ink: "var(--danger)" }
    : tone === "warn" ? { bg: "var(--warn-soft)", line: "var(--warn-line)", ink: "color-mix(in oklab, var(--warn) 60%, black)" }
    : accent ? { bg: "var(--accent-soft)", line: "var(--accent-line)", ink: "var(--accent-ink)" }
    : { bg: "var(--surface-2)", line: "var(--line)", ink: "var(--ink)" };
  return (
    <div className="sc-stat" style={{ background: c.bg, borderColor: c.line }}>
      <Ms name={icon} style={{ fontSize: 17, color: c.ink }} />
      <div><div className="sc-stat-l">{label}</div><div className="sc-stat-v num" style={{ color: c.ink }}>{value}</div></div>
    </div>
  );
}

window.ShiftCalendar = ShiftCalendar;
