/* Kalendár zmien — mesačná mrieža tímu, generovanie rozvrhu, kontrola pokrytia */

function Calendar({ version, bump }) {
  const [ym, setYm] = React.useState({ y: TD.YEAR, m: TD.MONTH });
  const [picker, setPicker] = React.useState(null); // {eid, date, x, y}
  const [toast, setToast] = React.useState(null);
  const [violations, setViolations] = React.useState([]);
  const scroller = React.useRef(null);

  const dim = new Date(ym.y, ym.m + 1, 0).getDate();
  const days = Array.from({ length: dim }, (_, i) => new Date(ym.y, ym.m, i + 1));
  const dateStrs = days.map(TD.fmt);
  const todayStr = TD.fmt(TD.TODAY);

  function shiftMonth(n) {
    setPicker(null);
    let m = ym.m + n, y = ym.y;
    if (m < 0) { m = 11; y--; } if (m > 11) { m = 0; y++; }
    setYm({ y, m });
  }

  function cellRec(eid, ds) { return TD.records[eid + "|" + ds]; }

  // prepočítaj porušenia §ZP pre viditeľný mesiac
  function revalidate() {
    setViolations(TD.validateSchedule(null, dateStrs));
  }
  React.useEffect(() => { revalidate(); }, [ym.y, ym.m]);

  function assign(eid, ds, val) {
    const key = eid + "|" + ds;
    if (val == null) {
      delete TD.records[key];
    } else if (TD.ABSENCE[val]) {
      const ex = TD.records[key];
      const r = { eid, date: ds, workplace: TD.empById(eid).wp, shift: ex ? ex.shift : null, status: val,
        workStart: null, breakStart: null, breakEnd: null, workEnd: null, in: null, out: null,
        breakMin: 0, hours: 0, nightHours: 0, overtimeHours: 0, source: "manual", approved: false, approvedBy: null, editLog: [] };
      TD.records[key] = r;
    } else {
      const ex = TD.records[key];
      if (ex && !TD.isAbsence(ex.status)) {
        ex.shift = val; ex.editLog = (ex.editLog || []).concat({ at: "", by: "manažér", what: "zmena na " + val });
      } else {
        TD.records[key] = { eid, date: ds, workplace: TD.empById(eid).wp, shift: val, status: "planned",
          workStart: null, breakStart: null, breakEnd: null, workEnd: null, in: null, out: null,
          breakMin: 0, hours: 0, nightHours: 0, overtimeHours: 0, source: "manual", approved: false, approvedBy: null, editLog: [] };
      }
    }
    setPicker(null); bump(); revalidate();
  }

  function generate() {
    const res = TD.generateForDates(dateStrs);
    bump(); revalidate();
    if (res.added) {
      let msg = "Vygenerovaných " + res.added + " smien — férové rozdelenie hodín a víkendov, dodržaný 12 h odpočinok a max. 40 h/týždeň. Dovolenky a PN zostali nedotknuté.";
      if (res.gaps) msg += " Pozor: " + res.gaps + " dní sa nedalo obsadiť bez porušenia zákona — vyžaduje zásah.";
      setToast(msg);
    } else {
      setToast("Rozvrh je už naplnený — nič nové na vygenerovanie.");
    }
    setTimeout(() => setToast(null), 7000);
  }

  // súčet hodín v mesiaci na zamestnanca
  function empMonthHours(eid) {
    return dateStrs.reduce((s, ds) => {
      const r = TD.records[eid + "|" + ds];
      if (!r || TD.isAbsence(r.status)) return s;
      if (r.hours > 0) return s + r.hours;
      const sh = TD.SHIFTS[r.shift];
      if (!sh) return s;
      const brk = TD.autoBreakFor(r.shift);
      return s + Math.max(0, TD.diffH(sh.start, sh.end) - (brk ? brk.breakMin / 60 : 0));
    }, 0);
  }

  // pokrytie na deň: obsadenie kľúčových pozícií (mimo neprítomnosti)
  function coverage(ds) {
    let recepcia = 0, chyzna = 0, admin = 0, total = 0;
    const dow = TD.dowOf(ds), hol = TD.isHoliday(ds);
    TD.EMPLOYEES.forEach(e => {
      const r = TD.records[e.id + "|" + ds];
      if (!r || TD.isAbsence(r.status) || !r.shift) return;
      total++;
      if (e.pos === "recepcia" || e.pos === "manazerH") recepcia++;
      if (e.pos === "chyzna") chyzna++;
      if (e.pos === "admin" || e.pos === "uctovnik") admin++;
    });
    // hotel beží každý deň (recepcia+chyžná), office len Po–Pia mimo sviatku (admin)
    const hotelOk = recepcia >= 1 && chyzna >= 1;
    const officeNeeded = dow < 5 && !hol;
    const officeOk = !officeNeeded || admin >= 1;
    return { recepcia, chyzna, admin, total, officeNeeded, ok: hotelOk && officeOk };
  }

  const monthLabel = TD.MONTHS[ym.m][0].toUpperCase() + TD.MONTHS[ym.m].slice(1) + " " + ym.y;
  const gaps = dateStrs.filter(ds => !coverage(ds).ok && TD.dowOf(ds) <= 6); // dni s neúplným pokrytím

  return (
    <div onClick={() => picker && setPicker(null)}>
      <div className="section-head">
        <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
          <div className="seg" onClick={e => e.stopPropagation()}>
            <button onClick={() => shiftMonth(-1)} style={{ padding: "7px 10px" }}><Icon.chevL width="16" height="16" /></button>
            <button className="on" style={{ minWidth: 168, cursor: "default" }}>{monthLabel}</button>
            <button onClick={() => shiftMonth(1)} style={{ padding: "7px 10px" }}><Icon.chevR width="16" height="16" /></button>
          </div>
          <button className="btn ghost sm" onClick={e => { e.stopPropagation(); setYm({ y: TD.YEAR, m: TD.MONTH }); }}>Aktuálny mesiac</button>
        </div>
        <button className="btn orange" onClick={e => { e.stopPropagation(); generate(); }}>
          <Icon.bolt width="17" height="17" /> Generovať rozvrh
        </button>
      </div>

      {/* pásik pokrytia / upozornenia */}
      <div className={"cov-bar " + (gaps.length ? "warn" : "ok")}>
        {gaps.length ? (
          <React.Fragment>
            <Icon.warn width="16" height="16" />
            <b>{gaps.length} dní</b> s neúplným pokrytím (chýba recepcia, chyžná alebo office).
            <span className="cov-days">
              {gaps.slice(0, 12).map(ds => <span key={ds} className="cov-pill" onClick={e => { e.stopPropagation(); scroller.current && scroller.current.scrollTo({ left: (new Date(ds).getDate() - 4) * 40, behavior: "smooth" }); }}>{new Date(ds).getDate()}.</span>)}
              {gaps.length > 12 && <span className="cov-pill more">+{gaps.length - 12}</span>}
            </span>
          </React.Fragment>
        ) : (
          <React.Fragment><Icon.check width="16" height="16" /> Pokrytie kompletné — každý prevádzkový deň má obsadené kľúčové pozície.</React.Fragment>
        )}
      </div>

      {/* zákonné porušenia (§ZP) — validátor */}
      {violations.length > 0 && (
        <div className="cov-bar warn" style={{ marginTop: 8 }}>
          <Icon.warn width="16" height="16" />
          <b>{violations.filter(v => v.severity === "hard").length} porušení zákona</b>
          {violations.filter(v => v.severity === "warn").length > 0 && <span>&nbsp;+ {violations.filter(v => v.severity === "warn").length} upozornení</span>}
          <span className="cov-days">
            {violations.slice(0, 6).map((v, i) => {
              const e = TD.empById(v.eid);
              return <span key={i} className="cov-pill" title={(e ? e.name + " — " : "") + v.msg}>{v.rule}</span>;
            })}
            {violations.length > 6 && <span className="cov-pill more">+{violations.length - 6}</span>}
          </span>
        </div>
      )}

      <div className="legend mcal-legend">
        {Object.values(TD.SHIFTS).map(s => <span key={s.id} className="lg"><span className="lgdot" style={{ background: s.color }}></span>{s.label}<span className="faint tnum"> {s.start}</span></span>)}
        <span className="lg-sep"></span>
        {Object.values(TD.ABSENCE).map(a => <span key={a.id} className="lg"><span className="lgsq" style={{ background: a.color + "26", borderColor: a.color, color: a.color }}>{a.code}</span>{a.label.split(" — ")[0].replace("Paragraf / lekár", "Paragraf")}</span>)}
      </div>

      <div className="card mgrid-card">
        <div className="mgrid-scroll" ref={scroller}>
          <table className="mgrid">
            <thead>
              <tr>
                <th className="mg-emp">Zamestnanec</th>
                {days.map((d, i) => {
                  const ds = dateStrs[i], dow = TD.dowOf(ds), hol = TD.isHoliday(ds);
                  return (
                    <th key={i} className={"mg-day" + (dow >= 5 ? " we" : "") + (hol ? " hol" : "") + (ds === todayStr ? " today" : "")} title={hol ? TD.HOLIDAYS[ds] : ""}>
                      <div className="mg-dow">{TD.DOW[dow]}</div>
                      <div className="mg-num tnum">{d.getDate()}</div>
                    </th>
                  );
                })}
                <th className="mg-sum">Σ h</th>
              </tr>
            </thead>
            <tbody>
              {TD.EMPLOYEES.map(e => (
                <tr key={e.id}>
                  <td className="mg-emp">
                    <div className="cell-name"><Avatar emp={e} size={30} /><div><b style={{ fontSize: 13 }}>{e.first} {e.last}</b><div style={{ marginTop: 1 }}><PositionPill pos={e.pos} /></div></div></div>
                  </td>
                  {days.map((d, i) => {
                    const ds = dateStrs[i], dow = TD.dowOf(ds), hol = TD.isHoliday(ds);
                    const r = cellRec(e.id, ds);
                    let inner = null, slotCls = "mg-slot";
                    if (r && TD.isAbsence(r.status)) {
                      const a = TD.ABSENCE[r.status];
                      inner = <span className="mg-abs" style={{ color: a.color, background: a.color + "22", borderColor: a.color + "66" }}>{a.code}</span>;
                      slotCls += " filled";
                    } else if (r && TD.SHIFTS[r.shift]) {
                      const sh = TD.SHIFTS[r.shift];
                      const done = r.hours > 0, prog = r.status === "working" || r.status === "working_late";
                      inner = <span className={"mg-sh" + (done ? " done" : "") + (prog ? " prog" : "")} style={{ background: sh.color + (done ? "30" : "1E"), borderColor: sh.color + "70", color: sh.color }} title={sh.label + " " + sh.start + "–" + sh.end}>{sh.code}</span>;
                      slotCls += " filled";
                    }
                    return (
                      <td key={i} className={"mg-cell" + (dow >= 5 ? " we" : "") + (hol ? " hol" : "") + (ds === todayStr ? " today" : "")}>
                        <button className={slotCls} onClick={ev => { ev.stopPropagation(); const rect = ev.currentTarget.getBoundingClientRect(); setPicker({ eid: e.id, date: ds, x: rect.left, y: rect.bottom }); }}>
                          {inner || <span className="mg-empty">+</span>}
                        </button>
                      </td>
                    );
                  })}
                  <td className="mg-sum tnum"><b>{Math.round(empMonthHours(e.id))}</b></td>
                </tr>
              ))}
            </tbody>
            <tfoot>
              <tr className="mg-cov">
                <td className="mg-emp">Pokrytie R/Ch{/* recepcia/chyžná (+office) */}</td>
                {days.map((d, i) => {
                  const ds = dateStrs[i], c = coverage(ds);
                  return <td key={i} className={"mg-cell cov" + (c.ok ? "" : (c.total ? " bad" : " zero"))} title={"Recepcia: " + c.recepcia + " · Chyžná: " + c.chyzna + (c.officeNeeded ? " · Office: " + c.admin : "")}>
                    {c.total ? <span className="cov-cell tnum">{c.recepcia}/{c.chyzna}{c.officeNeeded ? "/" + c.admin : ""}</span> : <span className="cov-cell off">·</span>}
                  </td>;
                })}
                <td className="mg-sum"></td>
              </tr>
            </tfoot>
          </table>
        </div>
      </div>

      <p className="muted" style={{ fontSize: 13, marginTop: 14, display: "flex", alignItems: "center", gap: 7 }}>
        <Icon.bolt width="15" height="15" /> <b style={{ fontWeight: 600 }}>Generovať rozvrh</b> obsadí budúce dni podľa zákonných pravidiel — 12 h odpočinok medzi zmenami, max. 40 h/týždeň, 2 dni voľna, férové hodiny a víkendy. Rešpektuje dovolenky a PN. Ak deň nejde obsadiť legálne, nahlási ho namiesto porušenia zákona. Ručné úpravy sa kontrolujú validátorom §ZP.
      </p>

      {toast && <div className="toast"><Icon.check width="17" height="17" />{toast}</div>}
      {picker && <ShiftPicker picker={picker} assign={assign} current={cellRec(picker.eid, picker.date)} />}
    </div>
  );
}

function ShiftPicker({ picker, assign, current }) {
  const style = { position: "fixed", left: Math.min(picker.x, window.innerWidth - 244), top: Math.min(picker.y + 6, window.innerHeight - 430), zIndex: 60 };
  const d = new Date(picker.date);
  return (
    <div className="shift-pop" style={style} onClick={e => e.stopPropagation()}>
      <div className="pop-title">{TD.DOW[TD.dowOf(picker.date)]} {d.getDate()}. {TD.MONTHS[d.getMonth()]}</div>
      <div className="pop-sect">Zmena</div>
      {Object.values(TD.SHIFTS).map(s => (
        <button key={s.id} className={"pop-opt" + (current && current.shift === s.id && !TD.isAbsence(current.status) ? " on" : "")} onClick={() => assign(picker.eid, picker.date, s.id)}>
          <span className="lgdot" style={{ background: s.color }}></span>
          <span style={{ fontWeight: 600 }}>{s.label}</span>
          <span className="faint tnum" style={{ marginLeft: "auto" }}>{s.start}–{s.end}</span>
        </button>
      ))}
      <div className="pop-sect">Neprítomnosť</div>
      {Object.values(TD.ABSENCE).map(a => (
        <button key={a.id} className={"pop-opt" + (current && current.status === a.id ? " on" : "")} onClick={() => assign(picker.eid, picker.date, a.id)}>
          <span className="lgsq" style={{ background: a.color + "26", borderColor: a.color, color: a.color }}>{a.code}</span>
          <span style={{ fontWeight: 600 }}>{a.label.split(" — ")[0]}</span>
        </button>
      ))}
      <button className="pop-opt clear" onClick={() => assign(picker.eid, picker.date, null)}>
        <Icon.close width="14" height="14" /> Voľno (vymazať)
      </button>
    </div>
  );
}

Object.assign(window, { Calendar });
