/* global React, ReactDOM */
// Variation A — "Mission Control"
// Hero cards for Off Today / Leading Daily / Weekend, then full roster grid.

const { useState, useMemo, useEffect } = React;

// Map our short TZ codes to IANA zone names. The browser's Intl API knows
// each zone's DST rules, so local time is correct year-round automatically.
const TZ_IANA = {
  GMT: "Etc/GMT",            WET: "Europe/Lisbon",
  CET: "Europe/Berlin",      EET: "Europe/Athens",
  MSK: "Europe/Moscow",      GST: "Asia/Dubai",
  PKT: "Asia/Karachi",       IST: "Asia/Kolkata",
  BST: "Asia/Dhaka",         ICT: "Asia/Bangkok",
  MYT: "Asia/Kuala_Lumpur",  SGT: "Asia/Singapore",
  CST_CN: "Asia/Shanghai",   JST: "Asia/Tokyo",
  AEST: "Australia/Sydney",  NZST: "Pacific/Auckland",
  BRT: "America/Sao_Paulo",  ART: "America/Argentina/Buenos_Aires",
  CLT: "America/Santiago",   COT: "America/Bogota",
  ET: "America/New_York",    MXT: "America/Mexico_City",
  PT: "America/Los_Angeles",
};

// Parse "HH:MM" → fractional hours; tolerant of "9", "9:30", "09:00".
function parseHM(s) {
  s = String(s || "").trim();
  let m = /^(\d{1,2}):(\d{2})$/.exec(s);
  if (m) return +m[1] + (+m[2]) / 60;
  m = /^(\d{1,2})$/.exec(s);          // bare hour like "9"
  if (m) return +m[1];
  return null;
}

// "09:00–18:00" / "9:00-17:00" / "9 - 18" → { start, end } in fractional hours.
function parseHoursRange(str) {
  if (!str) return null;
  const parts = String(str).split(/\s*[–-]\s*/); // en-dash or hyphen, optional spaces
  if (parts.length !== 2) return null;
  const s = parseHM(parts[0]);
  const e = parseHM(parts[1]);
  if (s == null || e == null) return null;
  return { start: s, end: e };
}

// Current local hour (fractional) in an IANA zone, DST-aware via Intl.
function localHourInZone(zone, now) {
  try {
    const fmt = new Intl.DateTimeFormat("en-US", {
      timeZone: zone, hour: "2-digit", minute: "2-digit", hour12: false,
    });
    const parts = fmt.formatToParts(now);
    const h = +parts.find(p => p.type === "hour").value;
    const m = +parts.find(p => p.type === "minute").value;
    return (h % 24) + m / 60;
  } catch {
    return null;
  }
}

// Is person currently within their working hours (in their TZ, DST-aware)?
function isOnShift(person, now = new Date()) {
  const zone = TZ_IANA[person.tz];
  if (!zone) return null;                 // unknown tz → can't compute
  const range = parseHoursRange(person.hours);
  if (!range) return null;                // bad hours → can't compute
  const localH = localHourInZone(zone, now);
  if (localH == null) return null;
  if (range.end > range.start) {
    return localH >= range.start && localH < range.end;
  }
  // wraps past midnight (e.g. 22:00–06:00)
  return localH >= range.start || localH < range.end;
}

function MissionControl({ liveOff, liveMode = false, people: peopleProp, leadHistory: leadHistoryProp, weekendSel: weekendSelProp }) {
  const { meta } = window.CS_DATA;
  const basePeople = peopleProp || window.CS_DATA.people;
  const [teamFilter, setTeamFilter] = useState("All");
  const [regionFilter, setRegionFilter] = useState("All");
  const [statusFilter, setStatusFilter] = useState("All");
  const [localHistory, setLocalHistory] = useState(() => window.CSLeadHistory.load());
  const leadHistory = leadHistoryProp !== undefined ? leadHistoryProp : localHistory;

  // Re-load history when localStorage changes (so Admin re-picks reflect here without refresh)
  useEffect(() => {
    if (leadHistoryProp !== undefined) return; // parent-driven, no polling needed
    const onStorage = () => setLocalHistory(window.CSLeadHistory.load());
    window.addEventListener("storage", onStorage);
    const id = setInterval(onStorage, 2000);
    return () => { window.removeEventListener("storage", onStorage); clearInterval(id); };
  }, [leadHistoryProp]);

  // Tick once a minute so shift-status (computed from current time) updates.
  const [, setTick] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setTick(t => t + 1), 60_000);
    return () => clearInterval(id);
  }, []);

  // When live data is present, treat it as authoritative for who's off today.
  const people = useMemo(() => {
    if (!liveMode || !liveOff) return basePeople;
    // Index live entries by Workable ID (primary) and by name (fallback).
    // Multiple entries per person possible — collect all and pick the one
    // covering today; carry its date range through for the Away card.
    // Local "today" (timezone-correct)
    const d = new Date();
    const todayLocal = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
    function pickActive(matches) {
      const covering = matches.filter(o => o.from <= todayLocal && todayLocal <= o.to);
      return covering[0] || matches[0];
    }
    const byId = new Map();
    const byName = new Map();
    liveOff.forEach(o => {
      if (o.workableId) {
        const arr = byId.get(String(o.workableId)) || [];
        arr.push(o); byId.set(String(o.workableId), arr);
      }
      if (o.name) {
        const arr = byName.get(o.name.toLowerCase()) || [];
        arr.push(o); byName.set(o.name.toLowerCase(), arr);
      }
    });
    return basePeople.map(p => {
      const matches =
        (p.workableId && byId.get(String(p.workableId))) ||
        byName.get(p.name.toLowerCase());
      if (matches && matches.length) {
        const hit = pickActive(matches);
        return { ...p, status: "off", reason: hit.reason || "Time Off", offFrom: hit.from, offTo: hit.to };
      }
      // Workable is the sole authority for time-off. Anyone without a current
      // Workable entry is working (manual status editing has been removed).
      return { ...p, status: "working", reason: undefined };
    });
  }, [liveOff, liveMode, basePeople]);

  const offToday = people.filter(p => p.status === "off");

  // Leads driven by history (seeded from CS_DATA.leadsHistory inside the store)
  const todayLeads = useMemo(() => window.CSLeadGen.SCOPES.map(scope => ({
    scope,
    name: leadHistory[`${meta.today.iso}__${scope}`] || null,
  })), [leadHistory, meta.today.iso]);
  const tomorrowLeads = useMemo(() => window.CSLeadGen.SCOPES.map(scope => ({
    scope,
    name: leadHistory[`${meta.tomorrow.iso}__${scope}`] || null,
  })), [leadHistory, meta.tomorrow.iso]);

  // Weekend coverage — derived from the live shared selections (same data the
  // Weekend Schedule page edits), not the hardcoded CS_DATA.weekend seed.
  const weekend = useMemo(() => {
    const sel = weekendSelProp || (window.CSStore && window.CSStore.loadWeekend && window.CSStore.loadWeekend()) || {};
    const satIso = meta.sat.iso;
    const sunIso = meta.sun.iso;
    const REGIONS = ["APAC", "EMEA", "LATAM", "L2"];
    return REGIONS.map(region => ({
      region,
      sat: sel[`${satIso}__${region}`] || null,
      sun: sel[`${sunIso}__${region}`] || null,
    }));
  }, [meta.sat.iso, meta.sun.iso, weekendSelProp]);

  const leadNames = new Set(
    todayLeads.filter(l => l.name).map(l => l.name)
  );

  const onWeekendNames = new Set(weekend.flatMap(w => [w.sat, w.sun]).filter(Boolean));

  const filtered = useMemo(() => people.filter(p => {
    if (teamFilter !== "All" && p.team !== teamFilter) return false;
    if (regionFilter !== "All" && p.region !== regionFilter) return false;
    if (statusFilter === "Working" && p.status !== "working") return false;
    if (statusFilter === "Off" && p.status !== "off") return false;
    return true;
  }), [people, teamFilter, regionFilter, statusFilter]);

  const groups = useMemo(() => {
    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]);

  return (
    <div className="mc-root">
      {/* ── Header ─────────────────────────────────── */}
      <header className="mc-header">
        <div className="mc-header-left">
          <div className="mc-eyebrow">
            <span className="mc-live-dot" /> LIVE · {meta.today.date}, 2026
          </div>
          <h1 className="mc-title">{meta.title}</h1>
        </div>
        <div className="mc-header-right">
          <div className="mc-stat">
            <div className="mc-stat-num">{people.filter(p => p.status === "working").length}</div>
            <div className="mc-stat-label">Available</div>
          </div>
          <div className="mc-stat mc-stat-off">
            <div className="mc-stat-num">{offToday.length}</div>
            <div className="mc-stat-label">Away</div>
          </div>
          <div className="mc-stat mc-stat-total">
            <div className="mc-stat-num">{people.length}</div>
            <div className="mc-stat-label">Team total</div>
          </div>
          <div className="mc-slack">
            {meta.slack.map(s => <span key={s} className="mc-slack-chip">{s}</span>)}
          </div>
        </div>
      </header>

      {/* ── Hero row: 3 cards ─────────────────────── */}
      <div className="mc-hero-row">
        {/* Away today */}
        <section className="mc-card mc-card-off">
          <div className="mc-card-head">
            <h2>Away today</h2>
            <span className="mc-card-count">{offToday.length}</span>
          </div>
          <ul className={`mc-away-list ${offToday.length > 5 ? "is-two-col" : ""}`}>
            {offToday.map(p => (
              <li key={p.uid || p.name}>
                <span className="mc-avatar mc-avatar-off">{p.name[0]}</span>
                <div className="mc-away-info">
                  <div className="mc-away-name">{p.name}</div>
                  <div className="mc-away-meta">
                    {p.offFrom && p.offTo
                      ? formatAwayRange(p.offFrom, p.offTo)
                      : `${p.team}${p.region ? ` · ${p.region}` : ""} · ${p.tz}`}
                  </div>
                </div>
                <span className="mc-pill mc-pill-off">{p.reason || "Off"}</span>
              </li>
            ))}
          </ul>
        </section>

        {/* Leading daily */}
        <section className="mc-card mc-card-lead">
          <div className="mc-card-head">
            <h2>Leading daily standup</h2>
          </div>
          <div className="mc-lead-grid">
            <div className="mc-lead-col">
              <div className="mc-lead-day mc-lead-day-today">
                <span className="mc-lead-pip" />Today · {meta.today.date}
              </div>
              {todayLeads.map(l => (
                <LeadRow key={l.scope} l={l} muted={false} />
              ))}
            </div>
            <div className="mc-lead-divider" />
            <div className="mc-lead-col">
              <div className="mc-lead-day">Tomorrow · {meta.tomorrow.date}</div>
              {tomorrowLeads.map(l => (
                <LeadRow key={l.scope} l={l} muted={true} />
              ))}
            </div>
          </div>
        </section>

        {/* Weekend */}
        <section className="mc-card mc-card-weekend">
          <div className="mc-card-head">
            <h2>Weekend coverage</h2>
            <span className="mc-card-sub">May 30 – 31</span>
          </div>
          <table className="mc-weekend-table">
            <thead>
              <tr>
                <th></th>
                <th>{meta.sat.date.replace("Sat, ", "Sat · ")}</th>
                <th>{meta.sun.date.replace("Sun, ", "Sun · ")}</th>
              </tr>
            </thead>
            <tbody>
              {weekend.map(w => (
                <tr key={w.region}>
                  <td className="mc-weekend-region">{w.region}</td>
                  <td>
                    {w.sat ? (
                      <><span className="mc-avatar mc-avatar-weekend">{w.sat[0]}</span>{w.sat}</>
                    ) : <span className="mc-weekend-empty">—</span>}
                  </td>
                  <td>
                    {w.sun ? (
                      <><span className="mc-avatar mc-avatar-weekend">{w.sun[0]}</span>{w.sun}</>
                    ) : <span className="mc-weekend-empty">—</span>}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </section>
      </div>

      {/* ── Filters ──────────────────────────────── */}
      <div className="mc-filters">
        <div className="mc-filters-label">Team</div>
        <FilterGroup label="Team" options={["All", "L1", "L2", "Invoicing"]} value={teamFilter} onChange={setTeamFilter} />
        <FilterGroup label="Region" options={["All", "EMEA", "APAC", "LATAM"]} value={regionFilter} onChange={setRegionFilter} />
        <FilterGroup label="Status" options={["All", "Working", "Off"]} value={statusFilter} onChange={setStatusFilter} />
        <div className="mc-filters-count">
          Showing <strong>{filtered.length}</strong> of {people.length}
        </div>
      </div>

      {/* ── Roster ───────────────────────────────── */}
      <div className="mc-roster">
        {groups.map(([groupName, list]) => (
          <section key={groupName} className="mc-roster-group">
            <header className="mc-roster-head">
              <h3>{groupName}</h3>
              <span className="mc-roster-count">{list.length}</span>
            </header>
            <div className="mc-roster-grid">
              {list.map(p => {
                const isLead = leadNames.has(p.name);
                const onWk = onWeekendNames.has(p.name);
                const computedOn = isOnShift(p);
                // Shift is computed purely from timezone + working hours.
                // No fallback to the old static field (which went stale).
                // If it can't be computed (unknown tz / bad hours), treat as off.
                const onShift = p.status === "working" && computedOn === true;
                const stateClass = p.status === "off" ? "mc-person-off"
                                : onShift ? "mc-person-on-shift"
                                : "mc-person-off-shift";
                return (
                  <div key={p.uid || p.name} className={`mc-person ${stateClass}`}>
                    <span className="mc-status-bar" />
                    <span className={`mc-avatar mc-avatar-${p.status}`}>{p.name[0]}</span>
                    <div className="mc-person-body">
                      <div className="mc-person-name" title={p.name}>{p.name}</div>
                      <div className="mc-person-meta">{p.tz}</div>
                    </div>
                    <div className="mc-person-tags">
                      {p.status === "off"
                        ? <span className="mc-tag mc-tag-off" title={p.reason || "Off"}>{shortReason(p.reason)}</span>
                        : onShift
                          ? <span className="mc-tag mc-tag-on">On shift</span>
                          : <span className="mc-tag mc-tag-shift-off">Off shift</span>}
                      {isLead && <span className="mc-tag mc-tag-lead">Lead</span>}
                      {onWk && <span className="mc-tag mc-tag-weekend">Wknd</span>}
                    </div>
                  </div>
                );
              })}
            </div>
          </section>
        ))}
      </div>
    </div>
  );
}

function FilterGroup({ label, options, value, onChange }) {
  return (
    <div className="mc-filter">
      <span className="mc-filter-label">{label}</span>
      <div className="mc-filter-pills">
        {options.map(opt => (
          <button
            key={opt}
            className={`mc-filter-pill ${value === opt ? "is-active" : ""}`}
            onClick={() => onChange(opt)}>
            {opt}
          </button>
        ))}
      </div>
    </div>
  );
}

function LeadRow({ l, muted }) {
  return (
    <div className="mc-lead-row">
      <div className="mc-lead-scope">{l.scope}</div>
      {l.name ? (
        <div className={`mc-lead-name ${muted ? "mc-lead-name-muted" : ""}`}>
          <span className={`mc-avatar ${muted ? "mc-avatar-lead-muted" : "mc-avatar-lead"}`}>
            {l.name[0]}
          </span>
          {l.name}
        </div>
      ) : (
        <div className="mc-lead-name mc-lead-unassigned">Not assigned</div>
      )}
    </div>
  );
}

window.MissionControl = MissionControl;

// Abbreviate long time-off reasons so the compact roster tag never overflows.
function shortReason(r) {
  if (!r) return "Off";
  const s = String(r).trim();
  if (/support\s*weekend\s*replacement/i.test(s)) return "SWR";
  if (/weekend\s*replacement/i.test(s)) return "WR";
  if (/^wr$/i.test(s)) return "WR";
  if (/sick/i.test(s)) return "Sick";
  if (/holiday/i.test(s)) return "Holiday";
  if (/parental/i.test(s)) return "Parental";
  if (/time[\s-]*off/i.test(s)) return "Time-Off";
  // Fallback: cap length so it can't break the layout
  return s.length > 12 ? s.slice(0, 11) + "…" : s;
}

function formatAwayRange(from, to) {
  function fmt(iso) {
    const [y, m, d] = iso.split("-").map(Number);
    const dt = new Date(y, m - 1, d);
    return dt.toLocaleString("en-US", { day: "2-digit", month: "short" });
  }
  if (from === to) return fmt(from);
  return `${fmt(from)} → ${fmt(to)}`;
}
