/* SkyOps — Calendar. One consolidated operational calendar (portfolio or single site):
   inspections · recommended cycles · work-order due dates · fleet & crew availability · flight weather.
   Detects conflicts (weather, drone unavailable, pilot cert lapsing) and lets you schedule on a day. */

const { useState: uSCA, useMemo: uMCA } = React;

const CAL_LAYERS = {
  insp: ["Inspections", "crosshair", "var(--accent-primary)"],
  rec: ["Recommended", "sparkles", "#a78bfa"],
  wo: ["Work orders", "flag", "var(--accent-mission)"],
  res: ["Fleet & crew", "drone", "#22d3ee"],
  wx: ["Flight weather", "cloud", "var(--sev-critical)"],
};
const calAdd = (d, n) => { const t = new Date(d + "T00:00:00Z"); t.setUTCDate(t.getUTCDate() + n); return t.toISOString().slice(0, 10); };
const calYm = (d) => d.slice(0, 7);
const calAddM = (ym, k) => { const [y, m] = ym.split("-").map(Number); const d = new Date(Date.UTC(y, m - 1 + k, 1)); return d.toISOString().slice(0, 7); };
const calHash = (s) => { let h = 7; for (const c of s) h = (h * 31 + c.charCodeAt(0)) >>> 0; return h; };

function calEvents(siteIds) {
  const T = window.SKY_TODAY || "2026-04-17";
  const S = (window.SITES || []).filter(s => siteIds.includes(s.id));
  const sName = (id) => (window.SITES || []).find(s => s.id === id)?.name || id;
  const R = window.resStore?.data || { drones: [], people: [] };
  const ev = [];
  const insps = (window.INSPECTIONS || []).filter(i => siteIds.includes(i.siteId));
  // Weather (forecast horizon 14 days)
  const wx = {};
  S.forEach(s => { for (let k = 0; k <= 14; k++) { const d = calAdd(T, k); const h = calHash(s.id + d) % 29;
    if (h < 3) { const r = h === 0 ? "Wind 31 km/h · gusts 44" : h === 1 ? "Rain 12 mm" : "Wind 28 km/h"; wx[s.id + d] = { sev: "block", r }; ev.push({ d, layer: "wx", sev: "block", siteId: s.id, title: `No-fly · ${r}`, sub: sName(s.id) }); }
    else if (h < 5) { wx[s.id + d] = { sev: "warn", r: "Overcast 85% · irradiance < 600 W/m²" }; ev.push({ d, layer: "wx", sev: "warn", siteId: s.id, title: "Low irradiance · thermal not valid", sub: sName(s.id) }); } } });
  // Inspections
  insps.forEach(i => { const d = i.startedAt || i.plannedFor; if (!d) return;
    const st = ["closed", "reported", "archived"].includes(i.status) ? "done" : ["flying", "processing", "review", "capture"].includes(i.status) ? "live" : "planned";
    const drone = R.drones.find(x => i.drone && (i.drone.includes(x.id) || i.drone.includes(x.model)));
    const pilot = R.people.find(p => p.name === i.lead);
    const issues = [];
    if (st === "planned") {
      const w = wx[i.siteId + d]; if (w && w.sev === "block") issues.push(`Weather: ${w.r}`); if (w && w.sev === "warn") issues.push(`Irradiance: ${w.r}`);
      if (drone && ["maintenance", "grounded", "retired"].includes(drone.status) && (!drone.reason?.back || drone.reason.back >= d)) issues.push(`${drone.id} ${drone.status}${drone.reason?.back ? " until " + drone.reason.back : ""}`);
      const cert = pilot && (pilot.certs || []).find(c => /EASA/.test(c[0]) && c[1] <= d); if (cert) issues.push(`${pilot.name}: ${cert[0]} expires ${cert[1]}`);
      if (d < T) issues.push("Planned date has passed");
    }
    ev.push({ d, layer: "insp", st, siteId: i.siteId, title: i.id, sub: `${sName(i.siteId)} · ${i.cycle || i.purpose || ""}`.trim(), mic: i.id, lead: i.lead, drone: i.drone, status: i.status, issues });
  });
  // Recommended next cycle per site (90-day cadence) if nothing planned after
  S.forEach(s => { const mine = insps.filter(i => i.siteId === s.id); const last = mine.filter(i => i.startedAt).sort((a, b) => b.startedAt.localeCompare(a.startedAt))[0];
    const planned = mine.some(i => (i.plannedFor || "") >= T && !i.startedAt);
    if (last && !planned) { let d = calAdd(last.startedAt, 90); if (d < T) d = calAdd(T, 7); let k = 0; while (wx[s.id + d] && wx[s.id + d].sev === "block" && k++ < 10) d = calAdd(d, 1);
      ev.push({ d, layer: "rec", siteId: s.id, title: `Next cycle · ${s.name}`, sub: `90-day cadence since ${last.id}`, why: `Last flown ${last.startedAt}. ${d === calAdd(last.startedAt, 90) ? "Quarterly cadence." : "Overdue — earliest flyable day."}` }); } });
  // Work orders due
  (window.woStore?.list || []).filter(w => siteIds.includes(w.siteId) && w.due && !["verified"].includes(w.status)).forEach(w => {
    ev.push({ d: w.due, layer: "wo", siteId: w.siteId, title: w.id, sub: w.title, wo: w.id, prio: w.prio, status: w.status, assignee: w.assignee, overdue: w.due < T && w.status !== "done" });
  });
  // Fleet & crew
  R.drones.forEach(dr => {
    if (dr.nextMaint) ev.push({ d: dr.nextMaint, layer: "res", title: `${dr.id} service due`, sub: dr.model, res: dr.id });
    if (dr.reason?.back && dr.status !== "available") ev.push({ d: dr.reason.back, layer: "res", title: `${dr.id} back · ${dr.reason.cat}`, sub: dr.reason.text, res: dr.id });
  });
  R.people.forEach(p => (p.certs || []).forEach(c => { if (c[1] >= calAdd(T, -30) && c[1] <= calAdd(T, 180)) ev.push({ d: c[1], layer: "res", title: `${p.name} · ${c[0]} expires`, sub: "Certificate renewal", res: p.id, warn: true }); }));
  return ev;
}

function CalendarView({ siteId, go, setActiveSite, setActiveMic, setWsStage }) {
  const T = window.SKY_TODAY || "2026-04-17";
  const allSites = window.SITES || [];
  const [site, setSite] = uSCA(siteId || "all");
  const [ym, setYm] = uSCA(calYm(T));
  const [view, setView] = uSCA("month");
  const [layers, setLayers] = uSCA({ insp: true, rec: true, wo: true, res: true, wx: true });
  const [day, setDay] = uSCA(T);
  const [selE, setSelE] = uSCA(null);
  window.useWOs && window.useWOs();
  const ids = siteId ? [siteId] : site === "all" ? allSites.map(s => s.id) : [site];
  const all = uMCA(() => calEvents(ids), [ids.join(), window.woStore?.list]);
  const ev = all.filter(e => layers[e.layer]);
  const by = {}; ev.forEach(e => (by[e.d] = by[e.d] || []).push(e));
  const ord = { insp: 0, wo: 1, rec: 2, res: 3, wx: 4 };
  Object.values(by).forEach(l => l.sort((a, b) => ord[a.layer] - ord[b.layer]));

  const [y, m] = ym.split("-").map(Number);
  const first = new Date(Date.UTC(y, m - 1, 1)), lead = (first.getUTCDay() + 6) % 7, nDays = new Date(Date.UTC(y, m, 0)).getUTCDate();
  const cells = []; for (let i = 0; i < lead; i++) cells.push(calAdd(`${ym}-01`, i - lead)); for (let d = 1; d <= nDays; d++) cells.push(`${ym}-${String(d).padStart(2, "0")}`); while (cells.length % 7) cells.push(calAdd(cells[cells.length - 1], 1));
  const in30 = all.filter(e => e.d >= T && e.d <= calAdd(T, 30));
  const conflicts = all.filter(e => e.layer === "insp" && e.issues && e.issues.length);
  const kpi = [["Inspections · 30 d", in30.filter(e => e.layer === "insp").length], ["Work orders due · 30 d", in30.filter(e => e.layer === "wo").length], ["Overdue work orders", all.filter(e => e.overdue).length, "crit"], ["Scheduling conflicts", conflicts.length, conflicts.length ? "crit" : ""], ["Cycles to schedule", all.filter(e => e.layer === "rec").length, "rec"]];
  const monthLbl = new Date(Date.UTC(y, m - 1, 1)).toLocaleDateString("en", { month: "long", year: "numeric", timeZone: "UTC" });
  const sName = (id) => allSites.find(s => s.id === id)?.name;
  const openInsp = (mic, sid) => { setActiveSite && sid && setActiveSite(sid); setActiveMic(mic); setWsStage && setWsStage("plan"); go("workspace"); };
  const schedule = (d, sid) => window.dispatchEvent(new CustomEvent("skyops:new-insp", { detail: { siteId: sid || (site !== "all" ? site : undefined), date: d } }));
  const chip = (e, i) => (
    <button key={i} className={`cal-ev cal-${e.layer} ${e.st ? "is-" + e.st : ""} ${e.sev ? "is-" + e.sev : ""} ${e.issues?.length || e.overdue ? "has-issue" : ""} ${selE === e ? "on" : ""}`} onClick={(x) => { x.stopPropagation(); setDay(e.d); setSelE(e); }} title={`${e.title} · ${e.sub || ""}`}>
      {(e.issues?.length || e.overdue) ? <Icon name="alert" size={9}/> : <i/>}<span>{e.layer === "wx" ? (e.sev === "block" ? "No-fly" : "Low irr.") : e.title}</span>{ids.length > 1 && e.siteId && e.layer !== "res" && <em>{(sName(e.siteId) || "").split(" ")[0]}</em>}
    </button>);
  const dayEv = by[day] || [];
  const wxDay = all.filter(e => e.layer === "wx" && e.d === day);

  return (
    <div className="cal">
      <div className="cal-kpis">{kpi.map(([l, v, c]) => <div key={l} className={c || ""}><span>{l}</span><b className="mono">{v}</b></div>)}</div>
      <div className="cal-tb">
        <button className="btn btn-ghost btn-xs" onClick={() => setYm(calAddM(ym, -1))}><Icon name="chevron_down" size={11} style={{ transform: "rotate(90deg)" }}/></button>
        <h3>{monthLbl}</h3>
        <button className="btn btn-ghost btn-xs" onClick={() => setYm(calAddM(ym, 1))}><Icon name="chevron_down" size={11} style={{ transform: "rotate(-90deg)" }}/></button>
        <button className="btn btn-ghost btn-xs" onClick={() => { setYm(calYm(T)); setDay(T); setSelE(null); }}>Today</button>
        {!siteId && <select className="sel cal-site" value={site} onChange={e => setSite(e.target.value)}><option value="all">All sites · {allSites.length}</option>{allSites.map(s => <option key={s.id} value={s.id}>{s.name}</option>)}</select>}
        <span className="grow"/>
        <div className="cal-layers">{Object.entries(CAL_LAYERS).map(([k, [l, ic, col]]) => <button key={k} className={layers[k] ? "on" : ""} style={{ "--c": col }} onClick={() => setLayers(x => ({ ...x, [k]: !x[k] }))}><i/>{l}<span className="mono">{all.filter(e => e.layer === k && calYm(e.d) === ym).length}</span></button>)}</div>
        <div className="ps-seg">{[["month", "Month"], ["agenda", "Agenda"]].map(([v, l]) => <button key={v} className={view === v ? "on" : ""} onClick={() => setView(v)}>{l}</button>)}</div>
        <button className="btn btn-primary btn-xs" onClick={() => schedule(day >= T ? day : undefined)}><Icon name="plus" size={11}/>Schedule inspection</button>
      </div>

      <div className="cal-body">
        {view === "month" ? <div className="cal-month">
          <div className="cal-wd">{["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].map(d => <span key={d}>{d}</span>)}</div>
          <div className="cal-grid">{cells.map(d => { const l = by[d] || []; const out = calYm(d) !== ym; const blk = l.some(e => e.layer === "wx" && e.sev === "block");
            return <div key={d} className={`cal-cell ${out ? "out" : ""} ${d === T ? "today" : ""} ${d === day ? "sel" : ""} ${d < T ? "past" : ""} ${blk ? "wx-block" : ""}`} onClick={() => { setDay(d); setSelE(null); }}>
              <div className="cal-d"><span className="mono">{+d.slice(8)}</span>{d === T && <em>Today</em>}</div>
              <div className="cal-evs">{l.slice(0, 3).map(chip)}{l.length > 3 && <span className="cal-more">+{l.length - 3} more</span>}</div>
            </div>; })}</div>
        </div> : <div className="cal-agenda">
          {Object.keys(by).filter(d => calYm(d) === ym).sort().map(d => <div key={d} className={`cal-ag-day ${d === T ? "today" : ""}`}>
            <div className="cal-ag-d"><b className="mono">{d.slice(8)}</b><span>{new Date(d + "T00:00:00Z").toLocaleDateString("en", { weekday: "short", timeZone: "UTC" })}</span></div>
            <div className="cal-ag-l">{by[d].map((e, i) => <button key={i} className={`cal-ag-r cal-${e.layer} ${selE === e ? "on" : ""}`} onClick={() => { setDay(d); setSelE(e); }}><i/><b className={e.layer === "insp" || e.layer === "wo" ? "mono" : ""}>{e.title}</b><span>{e.sub}</span>{(e.issues?.length || e.overdue) ? <span className="cal-iss"><Icon name="alert" size={10}/>{e.overdue ? "Overdue" : e.issues.length + " conflict" + (e.issues.length > 1 ? "s" : "")}</span> : null}</button>)}</div>
          </div>)}
          {!Object.keys(by).some(d => calYm(d) === ym) && <div className="sec" style={{ padding: 24, fontSize: 12 }}>Nothing this month with the selected layers.</div>}
        </div>}

        <aside className="cal-side">
          {selE ? <CalDetail e={selE} sName={sName} onBack={() => setSelE(null)} openInsp={openInsp} go={go} schedule={schedule} T={T}/> : <>
            <div className="cal-side-h"><b>{new Date(day + "T00:00:00Z").toLocaleDateString("en", { weekday: "long", day: "numeric", month: "short", timeZone: "UTC" })}</b>{day === T && <span className="cal-tag">Today</span>}</div>
            {wxDay.length > 0 && <div className="cal-side-wx">{wxDay.map((w, i) => <div key={i} className={`is-${w.sev}`}><Icon name="cloud" size={11}/><span><b>{w.sub}</b> · {w.title}</span></div>)}</div>}
            {dayEv.filter(e => e.layer !== "wx").map((e, i) => <button key={i} className={`cal-ag-r cal-${e.layer}`} onClick={() => setSelE(e)}><i/><b className={e.layer === "insp" || e.layer === "wo" ? "mono" : ""}>{e.title}</b><span>{e.sub}</span>{(e.issues?.length || e.overdue) ? <span className="cal-iss"><Icon name="alert" size={10}/></span> : null}</button>)}
            {dayEv.filter(e => e.layer !== "wx").length === 0 && <div className="sec" style={{ fontSize: 11.5 }}>Nothing scheduled.</div>}
            {day >= T && <button className="btn btn-secondary btn-sm" style={{ marginTop: 6 }} onClick={() => schedule(day)}><Icon name="plus" size={11}/>Schedule inspection on this day</button>}
            {conflicts.length > 0 && <div className="cal-conf">
              <div className="caps">Conflicts to resolve · {conflicts.length}</div>
              {conflicts.map((e, i) => <button key={i} className="cal-conf-r" onClick={() => { setYm(calYm(e.d)); setDay(e.d); setSelE(e); }}><b className="mono">{e.title}</b><span className="mono sec">{e.d}</span><em>{e.issues[0]}</em></button>)}
            </div>}
          </>}
        </aside>
      </div>
    </div>
  );
}

function CalDetail({ e, sName, onBack, openInsp, go, schedule, T }) {
  const L = CAL_LAYERS[e.layer];
  const kv = (a, b) => b ? <div className="ps-kv"><span>{a}</span><b>{b}</b></div> : null;
  return <div className="cal-det">
    <button className="cm-link" onClick={onBack}>← Day</button>
    <div className="cal-det-k" style={{ "--c": L[2] }}><Icon name={L[1]} size={11}/>{L[0]}</div>
    <h4 className={e.layer === "insp" || e.layer === "wo" ? "mono" : ""}>{e.title}</h4>
    <div className="sec" style={{ fontSize: 11.5 }}>{e.sub}</div>
    <div className="cal-det-kv">
      {kv("Date", e.d)}{kv("Site", e.siteId && sName(e.siteId))}{kv("Status", e.status && e.status.replace("_", " "))}{kv("Lead pilot", e.lead)}{kv("Drone", e.drone)}{kv("Priority", e.prio)}{kv("Assignee", e.assignee)}
    </div>
    {e.why && <div className="cal-why"><Icon name="sparkles" size={11}/><span>{e.why}</span></div>}
    {e.issues?.length > 0 && <div className="cal-issues">{e.issues.map((x, i) => <div key={i}><Icon name="alert" size={11}/>{x}</div>)}</div>}
    {e.overdue && <div className="cal-issues"><div><Icon name="alert" size={11}/>Due {e.d} · not done</div></div>}
    <div className="cal-det-act">
      {e.mic && <button className="btn btn-primary btn-sm" onClick={() => openInsp(e.mic, e.siteId)}>Open inspection<Icon name="arrow_right" size={11}/></button>}
      {e.mic && e.issues?.length > 0 && <button className="btn btn-secondary btn-sm" onClick={() => openInsp(e.mic, e.siteId)}>Reschedule / reassign</button>}
      {e.wo && <button className="btn btn-primary btn-sm" onClick={() => go("workorders")}>Open work order<Icon name="arrow_right" size={11}/></button>}
      {e.layer === "rec" && <button className="btn btn-primary btn-sm" onClick={() => schedule(e.d, e.siteId)}><Icon name="plus" size={11}/>Schedule this cycle</button>}
      {e.layer === "res" && <button className="btn btn-secondary btn-sm" onClick={() => go("fleet")}>Open Fleet & crew<Icon name="arrow_right" size={11}/></button>}
    </div>
  </div>;
}

function PortfolioCalendarPage({ go, setActiveSite, setActiveMic, setWsStage }) {
  return <div className="page">
    <div className="page-head"><div className="title"><div className="kicker">Operations</div><h1>Calendar</h1>
      <div className="sub">Inspections, work orders, fleet & crew availability and flight weather in one place. Conflicts are flagged before the day.</div></div></div>
    <CalendarView go={go} setActiveSite={setActiveSite} setActiveMic={setActiveMic} setWsStage={setWsStage}/>
  </div>;
}
function SiteCalendar({ site, go, setActiveMic }) { return <CalendarView siteId={site.id} go={go} setActiveMic={setActiveMic}/>; }

Object.assign(window, { PortfolioCalendarPage, SiteCalendar, CalendarView });
