/* global React */
// Monthly Schedule — whole-team calendar showing working / time-off per day.
// Driven by the connector (mock or Workable proxy via /timeoff?from=…&to=…).

const { useState: useStateM, useEffect: useEffectM, useMemo: useMemoM } = React;

function fmtMonthYearM(y, m) {
  return new Date(y, m, 1).toLocaleString("en-US", { month: "long", year: "numeric" });
}
function fmtDateKeyM(date) {
  const y = date.getFullYear();
  const mm = String(date.getMonth() + 1).padStart(2, "0");
  const dd = String(date.getDate()).padStart(2, "0");
  return `${y}-${mm}-${dd}`;
}
function daysInMonth(y, m) {
  return new Date(y, m + 1, 0).getDate();
}

function MonthlySchedule({ people }) {
  const today = new Date(2026, 4, 27); // anchor: May 27, 2026
  const [year, setYear] = useStateM(today.getFullYear());
  const [month, setMonth] = useStateM(today.getMonth());
  const [timeOff, setTimeOff] = useStateM([]);
  const [loading, setLoading] = useStateM(true);
  const [error, setError] = useStateM(null);
  const [teamFilter, setTeamFilter] = useStateM("All");

  // Fetch time-off for the visible month
  useEffectM(() => {
    let cancelled = false;
    setLoading(true);
    setError(null);
    const from = fmtDateKeyM(new Date(year, month, 1));
    const to   = fmtDateKeyM(new Date(year, month, daysInMonth(year, month)));
    const settings = window.CSConnector.loadSettings();
    window.CSConnector.fetchTimeOff(settings, { from, to })
      .then(res => {
        if (cancelled) return;
        setTimeOff(res.items);
        setLoading(false);
      })
      .catch(err => {
        if (cancelled) return;
        setError(err.message || String(err));
        setTimeOff([]);
        setLoading(false);
      });
    return () => { cancelled = true; };
  }, [year, month]);

  const numDays = daysInMonth(year, month);
  const days = useMemoM(() => {
    return Array.from({ length: numDays }, (_, i) => {
      const date = new Date(year, month, i + 1);
      return {
        n: i + 1,
        date,
        iso: fmtDateKeyM(date),
        dow: date.getDay(), // 0 = Sun, 6 = Sat
        isWeekend: date.getDay() === 0 || date.getDay() === 6,
        isToday: fmtDateKeyM(date) === fmtDateKeyM(today),
      };
    });
  }, [year, month, numDays]);

  // A stable key for joining roster ↔ time-off: prefer Workable ID, else name.
  const keyOf = (x) =>
    x && x.workableId ? "id:" + String(x.workableId)
                      : "nm:" + String(x.name || "").toLowerCase();

  // Index time-off by key → list of {from,to,reason}
  const offByKey = useMemoM(() => {
    const m = new Map();
    timeOff.forEach(t => {
      const k = keyOf(t);
      if (!m.has(k)) m.set(k, []);
      m.get(k).push(t);
    });
    return m;
  }, [timeOff]);

  function dayStatus(person, day) {
    // Try ID match first, then fall back to name match.
    const entries =
      (person.workableId && offByKey.get("id:" + String(person.workableId))) ||
      offByKey.get("nm:" + person.name.toLowerCase()) ||
      [];
    const hit = entries.find(e => day.iso >= e.from && day.iso <= e.to);
    if (hit) return { state: "off", reason: hit.reason };
    if (day.isWeekend) return { state: "weekend" };
    return { state: "working" };
  }

  // Group people by team
  const filtered = useMemoM(() => {
    if (teamFilter === "All") return people;
    return people.filter(p => p.team === teamFilter);
  }, [people, teamFilter]);

  const groups = useMemoM(() => {
    const buckets = {
      "L1 · EMEA":  filtered.filter(p => p.team === "L1" && p.region === "EMEA"),
      "L1 · APAC":  filtered.filter(p => p.team === "L1" && p.region === "APAC"),
      "L1 · LATAM": filtered.filter(p => p.team === "L1" && p.region === "LATAM"),
      "L2":         filtered.filter(p => p.team === "L2"),
      "Invoicing":  filtered.filter(p => p.team === "Invoicing"),
    };
    return Object.entries(buckets).filter(([, list]) => list.length > 0);
  }, [filtered]);

  // Counts — keyed the same way as the join (id-or-name).
  const offThisMonth = useMemoM(() => {
    const counts = new Map();
    timeOff.forEach(t => {
      const k = keyOf(t);
      counts.set(k, (counts.get(k) || 0) + countDays(t.from, t.to, year, month));
    });
    return counts;
  }, [timeOff, year, month]);
  const offDaysFor = (p) =>
    (p.workableId && offThisMonth.get("id:" + String(p.workableId))) ||
    offThisMonth.get("nm:" + p.name.toLowerCase()) ||
    0;

  const goPrev = () => {
    if (month === 0) { setMonth(11); setYear(year - 1); }
    else setMonth(month - 1);
  };
  const goNext = () => {
    if (month === 11) { setMonth(0); setYear(year + 1); }
    else setMonth(month + 1);
  };
  const goToday = () => { setYear(today.getFullYear()); setMonth(today.getMonth()); };

  const source = timeOff[0]?.source || "—";
  const liveMode = window.CSConnector.loadSettings().mode === "workable";

  return (
    <div className="ms-root">
      <header className="ms-header">
        <div>
          <div className="ms-eyebrow">Monthly schedule</div>
          <h1 className="ms-title">{fmtMonthYearM(year, month)}</h1>
        </div>

        <div className="ms-month-nav">
          <button className="ms-nav-btn" onClick={goPrev} aria-label="Previous month">‹</button>
          <button className="ms-nav-btn ms-nav-today" onClick={goToday}>This month</button>
          <button className="ms-nav-btn" onClick={goNext} aria-label="Next month">›</button>
        </div>

        <div className="ms-team-filter">
          {["All", "L1", "L2", "Invoicing"].map(t => (
            <button key={t}
              className={teamFilter === t ? "is-active" : ""}
              onClick={() => setTeamFilter(t)}>{t}</button>
          ))}
        </div>

        <div className="ms-status">
          {loading
            ? <span className="ms-status-pill ms-status-loading">Syncing…</span>
            : error
              ? <span className="ms-status-pill ms-status-err" title={error}>⚠ {error}</span>
              : (
                <span className={`ms-status-pill ${liveMode ? "ms-status-live" : "ms-status-mock"}`}>
                  <span className="ms-status-dot" />
                  {liveMode ? "Workable · live" : "Mock data"}
                </span>
              )}
        </div>
      </header>

      <div className="ms-legend">
        <span className="ms-leg-item"><span className="ms-leg-sw ms-cell-working" /> Working</span>
        <span className="ms-leg-item"><span className="ms-leg-sw ms-cell-off" /> Time off</span>
        <span className="ms-leg-item"><span className="ms-leg-sw ms-cell-weekend" /> Weekend</span>
        <span className="ms-leg-item ms-leg-meta">
          {timeOff.length} active time-off {timeOff.length === 1 ? "request" : "requests"} this month
        </span>
      </div>

      <div className="ms-grid-wrap">
        <div className="ms-grid" style={{ "--days": numDays }}>
          {/* Header row */}
          <div className="ms-grid-corner">
            <div className="ms-corner-label">Agent</div>
            <div className="ms-corner-sub">{filtered.length} of {people.length}</div>
          </div>
          <div className="ms-day-header">
            {days.map(d => (
              <div key={d.iso}
                className={`ms-day-h ${d.isWeekend ? "is-weekend" : ""} ${d.isToday ? "is-today" : ""}`}>
                <div className="ms-day-h-dow">{["S","M","T","W","T","F","S"][d.dow]}</div>
                <div className="ms-day-h-num">{d.n}</div>
              </div>
            ))}
          </div>

          {/* Team groups */}
          {groups.map(([groupName, list]) => (
            <React.Fragment key={groupName}>
              <div className="ms-group-head">
                <span>{groupName}</span>
                <span className="ms-group-count">{list.length}</span>
              </div>
              <div className="ms-group-spacer" />

              {list.map(p => {
                const offDays = offDaysFor(p);
                return (
                  <React.Fragment key={p.name}>
                    <div className="ms-person">
                      <span className="mc-avatar mc-avatar-working ms-person-avatar">{p.name[0]}</span>
                      <div className="ms-person-info">
                        <div className="ms-person-name">{p.name}</div>
                        <div className="ms-person-meta">{p.tz}{offDays > 0 ? ` · ${offDays}d off` : ""}</div>
                      </div>
                    </div>
                    <div className="ms-row">
                      {days.map(d => {
                        const s = dayStatus(p, d);
                        return (
                          <div
                            key={d.iso}
                            className={`ms-cell ms-cell-${s.state} ${d.isToday ? "is-today" : ""}`}
                            title={`${p.name} · ${d.iso}${s.reason ? ` · ${s.reason}` : ""}`}
                          >
                            {s.state === "off" && s.reason && (
                              <span className="ms-cell-tag">{shortReason(s.reason)}</span>
                            )}
                          </div>
                        );
                      })}
                    </div>
                  </React.Fragment>
                );
              })}
            </React.Fragment>
          ))}
        </div>
      </div>
    </div>
  );
}

function shortReason(r) {
  if (!r) return "";
  if (/sick/i.test(r))     return "S";
  if (/holiday/i.test(r))  return "H";
  if (/parental/i.test(r)) return "P";
  if (/wr/i.test(r))       return "WR";
  return "•";
}

function countDays(from, to, year, month) {
  const start = new Date(from + "T00:00:00");
  const end   = new Date(to   + "T00:00:00");
  const monthStart = new Date(year, month, 1);
  const monthEnd   = new Date(year, month, daysInMonth(year, month));
  const lo = start > monthStart ? start : monthStart;
  const hi = end   < monthEnd   ? end   : monthEnd;
  if (hi < lo) return 0;
  return Math.round((hi - lo) / (1000 * 60 * 60 * 24)) + 1;
}

window.MonthlySchedule = MonthlySchedule;
