/* SkyOps — Alert center. One inbox for every threshold-triggered event across the product:
   detections, SCADA, coverage, work orders, fleet & crew, SLA, warranty. Each alert traces to its source
   and to the rule that fired it; ack / assign / snooze / resolve / create work order; escalation by age. */

const { useState: uSAL, useEffect: uEAL, useMemo: uMAL } = React;

const AL_CAT = { detection: ["Detection", "crosshair"], scada: ["SCADA", "zap"], coverage: ["Coverage", "map"], wo: ["Work order", "flag"], fleet: ["Fleet & crew", "drone"], sla: ["SLA", "clock"], warranty: ["Warranty", "shield"], weather: ["Weather", "globe"], field: ["Field report", "phone"] };
const AL_ST = { new: "New", ack: "Acknowledged", assigned: "Assigned", snoozed: "Snoozed", resolved: "Resolved" };
const AL_ESC = [["0 min", "Pilot on duty", "push"], ["30 min", "Site manager", "push + SMS"], ["2 h", "O&M lead", "phone call"], ["8 h", "Portfolio manager", "email digest"]];
const alSet = () => (window.setStore ? window.setStore.v : { hotCell: 18, soiling: 5, coverage: 95, maxWind: 10 });

function alBuild() {
  const S = window.SITES || [], I = window.INSPECTIONS || [], st = alSet();
  const site = (id) => S.find(s => s.id === id) || {};
  const out = [];
  const add = (a) => out.push({ status: "new", owner: null, ...a });
  // Detections over threshold in the open inspections
  (window.DETECTIONS || []).filter(d => d.severity === "critical" || (d.kind === "hot_cell" && d.dT >= st.hotCell)).slice(0, 6).forEach((d, k) => add({
    id: `ALT-D-${d.id.slice(4)}`, sev: d.severity === "critical" ? "critical" : "high", cat: "detection", siteId: "pt-ev-03", mic: "MIC-2026-04-033",
    title: `${d.label} · ΔT +${d.dT.toFixed(1)} °C`, detail: `${d.string} · ${d.module} · confidence ${d.confidence}%`, rule: d.kind === "hot_cell" ? `Hot-cell ΔT ≥ ${st.hotCell} °C` : "Severity = critical",
    at: `2026-04-16 ${String(9 + k).padStart(2, "0")}:${String(12 + k * 7).padStart(2, "0")}`, age: 20 + k * 55, link: ["workspace", "review"], wo: { title: `${d.label} — ${d.module}`, type: d.group === "STRING" ? "Electrical" : "Module replace", prio: "P1", loc: d.string, obs: d.id } }));
  // Seed portfolio alerts (SCADA / tracker / soiling)
  (window.ALERTS || []).forEach((a, k) => { const s = S.find(x => x.name === a.site) || {}; const cat = /String|Tracker/.test(a.kind) ? "scada" : /Coverage/.test(a.kind) ? "coverage" : /Hot/.test(a.kind) ? "detection" : "scada";
    add({ id: a.id, sev: a.sev, cat, siteId: s.id, mic: a.mic, title: a.kind, detail: cat === "scada" ? "Bentek SCADA · continuous channel" : `${a.mic}`, rule: cat === "coverage" ? `Coverage < ${st.coverage}%` : /Soiling/.test(a.kind) ? `Soiling loss > ${st.soiling}%` : "SCADA anomaly rule", at: `2026-04-17 ${String(8 + k).padStart(2, "0")}:05`, age: [12, 38, 60, 180, 240][k] || 300,
      link: cat === "coverage" ? ["workspace", "capture"] : ["site"], wo: { title: a.kind, type: /Tracker/.test(a.kind) ? "Tracker" : /Soiling/.test(a.kind) ? "Cleaning" : "Electrical", prio: a.sev === "critical" ? "P1" : "P2" } }); });
  // Overdue work orders
  (window.woStore?.list || []).filter(w => !["done", "verified"].includes(w.status) && w.due && w.due < "2026-04-17").forEach(w => add({
    id: `ALT-W-${w.id.slice(-4)}`, sev: w.prio === "P1" ? "high" : "medium", cat: "wo", siteId: w.siteId, title: `${w.id} overdue · ${w.title}`, detail: `Due ${w.due} · ${w.assignee}`, rule: "Work order past due date", at: `${w.due} 18:00`, age: 600, link: ["workorders"] }));
  // Fleet: drones in maintenance / service due, certifications expiring
  const R = window.resStore?.data;
  (R?.drones || []).filter(d => ["maintenance", "grounded"].includes(d.status) || d.nextMaint < window.skyAdd(14)).forEach(d => add({
    id: `ALT-F-${d.id}`, sev: d.status === "grounded" ? "high" : "medium", cat: "fleet", siteId: null, title: `${d.id} ${d.status === "maintenance" || d.status === "grounded" ? d.status : "service due " + d.nextMaint}`, detail: d.reason ? `${d.reason.cat} · ${d.reason.text}` : `${d.model} · ${d.base}`, rule: "Drone unavailable or service within 14 days", at: "2026-04-15 07:30", age: 900, link: ["fleet"] }));
  (R?.people || []).flatMap(p => p.certs.filter(c => c[1] < window.skyAdd(60)).map(c => [p, c])).forEach(([p, c]) => add({
    id: `ALT-C-${p.id}-${c[0].slice(0, 4)}`, sev: c[1] < window.skyAdd(21) ? "high" : "low", cat: "fleet", siteId: null, title: `${p.name} · ${c[0]} expires ${c[1]}`, detail: `${p.role} · ${p.org}`, rule: "Certification expiring within 60 days", at: "2026-04-14 06:00", age: 1200, link: ["fleet"] }));
  // Commercial SLA breaches (running)
  if (window.cmStore) { try { const jobs = window.__cmJobs ? window.__cmJobs() : []; jobs.filter(j => j.late).forEach(j => add({ id: `ALT-S-${j.i.id.slice(4)}`, sev: "high", cat: "sla", siteId: j.i.siteId, mic: j.i.id, title: `Report overdue by ${j.wd - 5} wd`, detail: `${j.i.id} · ${j.client}`, rule: "Report delivery ≤ 5 working days", at: "2026-04-17 09:00", age: 400, link: ["commercial"] })); } catch {} }
  // Warranty info requested
  (window.wcStore?.list || []).filter(c => c.status === "info").forEach(c => add({ id: `ALT-WC-${c.id.slice(-3)}`, sev: "medium", cat: "warranty", siteId: c.siteId, title: `${c.id} · manufacturer requests information`, detail: c.note, rule: "Claim status = info requested", at: "2026-04-12 11:20", age: 2000, link: ["warranty"] }));
  // Weather on scheduled flight days
  I.filter(i => i.status === "scheduled" && i.plannedFor).forEach(i => { const s = site(i.siteId); const ws = (s.wind || 0) / 3.6; if (ws > st.maxWind) add({ id: `ALT-WX-${i.id.slice(4)}`, sev: "medium", cat: "weather", siteId: i.siteId, mic: i.id, title: `Wind ${ws.toFixed(1)} m/s forecast · flight ${i.plannedFor}`, detail: `Limit ${st.maxWind} m/s · consider rescheduling`, rule: `Wind > ${st.maxWind} m/s on flight day`, at: "2026-04-17 06:00", age: 150, link: ["workspace", "plan"] }); });
  // Field reports from technicians (source FIELD_REPORT)
  ((window.faQ && window.faQ.v.obs) || []).filter(o => o.synced !== false).forEach(o => add({ id: `ALT-${o.id}`, sev: o.sev, cat: "field", siteId: o.siteId, title: `${o.label} · reported in the field`, detail: `${o.loc} · ${o.by}${o.note ? " · " + o.note : ""}`, rule: "Field report submitted", at: o.at, age: 5, link: ["site"],
    wo: { title: `${o.label} — ${o.loc}`, type: o.kind === "soiling" || o.kind === "bird_dropping" ? "Cleaning" : o.kind === "vegetation" ? "Vegetation" : o.kind === "tilt_fault" ? "Tracker" : "Electrical", prio: o.sev === "critical" ? "P1" : o.sev === "high" ? "P2" : "P3", loc: o.loc } }));
  // Link to Core situations (same root cause) and to work orders that address them
  const SIT = { "ALT-1042": "SIT-01", "ALT-1040": "SIT-04", "ALT-S-2026-04-028": "SIT-06" };
  const W = window.woStore?.list || [];
  out.forEach(a => {
    if (SIT[a.id]) a.sit = SIT[a.id];
    if (a.cat === "detection" && a.siteId === "pt-ev-03" && /Hot cell|bypass/i.test(a.title)) a.sit = "SIT-02";
    if (a.id === "ALT-D-04204" || (a.cat === "detection" && a.siteId === "pt-ev-03" && /Offline string/i.test(a.title))) a.sit = "SIT-01";
    if (a.id.startsWith("ALT-C-") && /Castaño/.test(a.title)) a.sit = "SIT-05";
    const SIT_WO = { "SIT-01": "WO-2026-0412", "SIT-04": "WO-2026-0421" };
    const viaSit = a.sit && SIT_WO[a.sit] && W.find(w => w.id === SIT_WO[a.sit]);
    const wo = viaSit || a.wo && W.find(w => w.siteId === a.siteId && ((a.wo.obs && w.obs === a.wo.obs) || w.title === a.wo.title || (a.wo.loc && w.loc && w.loc === a.wo.loc)));
    if (wo) { a.linkedWo = wo.id; a.woStatus = wo.status; if (["done", "verified"].includes(wo.status)) { a.status = "resolved"; a.autoResolved = true; } else a.status = "assigned"; a.owner = wo.assignee; }
  });
  return out;
}

const alStore = {
  v: (() => { try { return JSON.parse(localStorage.getItem("skyops_alerts_v1") || "{}"); } catch { return {}; } })(),
  subs: new Set(),
  set(id, p) { this.v = { ...this.v, [id]: { ...(this.v[id] || {}), ...p, log: [...((this.v[id] || {}).log || []), [p.status || "note", p.note || "", "You"]] } }; try { localStorage.setItem("skyops_alerts_v1", JSON.stringify(this.v)); } catch {} this.subs.forEach(s => s(this.v)); },
};
function useAlerts() {
  const [v, setV] = uSAL(alStore.v);
  uEAL(() => { alStore.subs.add(setV); return () => alStore.subs.delete(setV); }, []);
  return uMAL(() => alBuild().map(a => ({ ...a, ...(v[a.id] || {}) })), [v]);
}
const alAge = (m) => m < 60 ? `${m} min` : m < 1440 ? `${Math.round(m / 60)} h` : `${Math.round(m / 1440)} d`;
const alEsc = (a) => a.status !== "new" || !["critical", "high"].includes(a.sev) ? null : a.age >= 480 ? 3 : a.age >= 120 ? 2 : a.age >= 30 ? 1 : 0;

function AlertsPage({ go, setActiveSite, setActiveMic, setWsStage }) {
  const alerts = useAlerts();
  const [tab, setTab] = uSAL("inbox");
  const [stF, setStF] = uSAL("open");
  const [sevF, setSevF] = uSAL("all");
  const [catF, setCatF] = uSAL("all");
  const [sel, setSel] = uSAL(null);
  const [note, setNote] = uSAL("");
  const SR = { critical: 0, high: 1, medium: 2, low: 3 };
  const list = alerts.filter(a => (stF === "all" || (stF === "open" ? !["resolved", "snoozed"].includes(a.status) : a.status === stF)) && (sevF === "all" || a.sev === sevF) && (catF === "all" || a.cat === catF))
    .sort((a, b) => SR[a.sev] - SR[b.sev] || a.age - b.age);
  const cur = alerts.find(a => a.id === sel) || list[0];
  const open = alerts.filter(a => !["resolved", "snoozed"].includes(a.status));
  const people = window.resAssignees ? window.resAssignees().filter(x => x !== "Unassigned") : [];
  const openSrc = (a) => { if (a.siteId) setActiveSite(a.siteId); if (a.mic) setActiveMic(a.mic); if (a.link[1]) setWsStage(a.link[1]); go(a.link[0]); };
  const site = (id) => (window.SITES || []).find(s => s.id === id);

  return (
    <div className="page al">
      <div className="page-head">
        <div className="title"><div className="kicker">Operate · common operational picture</div><h1>Alerts</h1>
          <div className="sub">Every threshold-triggered event in one inbox. Each alert links to its source and to the rule that fired it.</div></div>
      </div>

      <div className="wo-kpis">
        <div className={`wo-kpi ${open.some(a => a.sev === "critical") ? "is-crit" : ""}`}><span className="caps">Open critical</span><b className="mono">{open.filter(a => a.sev === "critical").length}</b><em>{open.filter(a => a.sev === "high").length} high</em></div>
        <div className="wo-kpi"><span className="caps">Unacknowledged</span><b className="mono">{alerts.filter(a => a.status === "new").length}</b><em>{alerts.filter(a => alEsc(a) >= 1).length} escalated</em></div>
        <div className="wo-kpi"><span className="caps">Assigned</span><b className="mono">{alerts.filter(a => a.status === "assigned").length}</b><em>{alerts.filter(a => a.wo).length} can become work orders</em></div>
        <div className="wo-kpi is-ok"><span className="caps">Resolved</span><b className="mono">{alerts.filter(a => a.status === "resolved").length}</b><em>{alerts.filter(a => a.status === "snoozed").length} snoozed</em></div>
      </div>

      <div className="tabs" style={{ marginBottom: 12 }}>{[["inbox", `Inbox · ${open.length}`], ["rules", "Rules & escalation"]].map(([k, l]) => <button key={k} className={tab === k ? "on" : ""} onClick={() => setTab(k)}>{l}</button>)}</div>

      {tab === "inbox" && <>
        {window.CoreStrip && <window.CoreStrip dom={["maintenance", "fleet", "planning"]} title="Situations Argus correlated from these alerts" limit={2}/>}
        <div className="wo-tb">
          <div className="ps-seg">{[["open", "Open"], ["new", "New"], ["assigned", "Assigned"], ["snoozed", "Snoozed"], ["resolved", "Resolved"], ["all", "All"]].map(([k, l]) => <button key={k} className={stF === k ? "on" : ""} onClick={() => setStF(k)}>{l}</button>)}</div>
          <div className="ps-seg">{["all", "critical", "high", "medium", "low"].map(k => <button key={k} className={sevF === k ? "on" : ""} onClick={() => setSevF(k)}>{k === "all" ? "All severities" : k}</button>)}</div>
          <select className="sel wo-sel" value={catF} onChange={e => setCatF(e.target.value)}><option value="all">All sources</option>{Object.entries(AL_CAT).map(([k, [l]]) => <option key={k} value={k}>{l}</option>)}</select>
        </div>
        <div className="al-split">
          <div className="card al-list">
            {list.map(a => { const e = alEsc(a); return (
              <button key={a.id} className={`al-it ${cur && cur.id === a.id ? "on" : ""} ${a.status}`} onClick={() => setSel(a.id)}>
                <span className={`al-sev al-sev-${a.sev}`}/>
                <span className="al-it-ic"><Icon name={AL_CAT[a.cat][1]} size={13}/></span>
                <span className="al-it-m"><b>{a.title}</b><em>{site(a.siteId)?.name || "Fleet"} · {AL_CAT[a.cat][0]} · {alAge(a.age)} ago{a.sit ? " · " + a.sit : ""}{a.linkedWo ? " · " + a.linkedWo : ""}</em></span>
                {e ? <span className="al-esc">L{e + 1} escalated</span> : <span className={`al-st al-st-${a.status}`}>{AL_ST[a.status]}</span>}
              </button>); })}
            {list.length === 0 && <div className="sec" style={{ padding: 24, fontSize: 12, textAlign: "center" }}>No alerts match these filters.</div>}
          </div>
          {cur && <div className="card al-det">
            <div className="al-det-hd">
              <div className="wo-dr-id"><span className={`al-sev al-sev-${cur.sev}`}/><span className="mono">{cur.id}</span><span className={`al-st al-st-${cur.status}`}>{AL_ST[cur.status]}</span></div>
              <h3>{cur.title}</h3><div className="sec" style={{ fontSize: 12 }}>{cur.detail}</div>
            </div>
            <div className="al-det-b">
              <div className="al-kv">
                <div className="ps-kv"><span>Source</span><b>{AL_CAT[cur.cat][0]}</b></div>
                <div className="ps-kv"><span>Site</span><b>{site(cur.siteId)?.name || "—"}</b></div>
                {cur.mic && <div className="ps-kv"><span>Inspection</span><b className="mono">{cur.mic}</b></div>}
                <div className="ps-kv"><span>Rule fired</span><b>{cur.rule}</b></div>
                <div className="ps-kv"><span>Raised</span><b className="mono">{cur.at} · {alAge(cur.age)} ago</b></div>
                {cur.owner && <div className="ps-kv"><span>Owner</span><b>{cur.owner}</b></div>}
                {cur.linkedWo && <div className="ps-kv"><span>Work order</span><b><button className="cm-link mono" onClick={() => go("workorders")}>{cur.linkedWo}</button> · {cur.woStatus.replace("_", " ")}{cur.autoResolved ? " · alert closed automatically" : ""}</b></div>}
                {cur.sit && (() => { const s = window.coreModel().sit.find(x => x.id === cur.sit); return s ? <div className="al-sit"><span className="core-mark sm"><i/>Argus</span><div><b>Part of situation · {s.title}</b><span>{s.cause}</span></div></div> : null; })()}
              </div>
              <div className="caps">Escalation</div>
              <div className="al-escl">{AL_ESC.map(([t, who, ch], i) => { const e = alEsc(cur); return <div key={i} className={`${e != null && i <= e ? "hit" : ""} ${cur.status !== "new" && i === 0 ? "hit" : ""}`}><i/><span className="mono">{t}</span><b>{who}</b><em>{ch}</em></div>; })}</div>
              <div className="al-acts">
                {cur.status === "new" && <button className="btn btn-secondary btn-xs" onClick={() => alStore.set(cur.id, { status: "ack" })}><Icon name="check" size={11}/>Acknowledge</button>}
                <select className="sel wo-sel" value="" onChange={e => e.target.value && alStore.set(cur.id, { status: "assigned", owner: e.target.value })}><option value="">Assign to…</option>{people.map(p => <option key={p}>{p}</option>)}</select>
                {cur.wo && !cur.linkedWo && <button className="btn btn-secondary btn-xs" onClick={() => { window.dispatchEvent(new CustomEvent("skyops:new-wo", { detail: { ...cur.wo, siteId: cur.siteId, mic: cur.mic } })); alStore.set(cur.id, { status: "assigned", owner: "Work order" }); }}><Icon name="flag" size={11}/>Create work order</button>}
                <button className="btn btn-ghost btn-xs" onClick={() => alStore.set(cur.id, { status: "snoozed" })}>Snooze 24 h</button>
                <button className="btn btn-ghost btn-xs" onClick={() => openSrc(cur)}>Open source<Icon name="arrow_right" size={11}/></button>
              </div>
              <div className="dd-note"><input className="inp" value={note} onChange={e => setNote(e.target.value)} placeholder="Resolution note (required to resolve)"/>
                <button className="btn btn-primary btn-xs" disabled={!note.trim() || cur.status === "resolved"} onClick={() => { alStore.set(cur.id, { status: "resolved", note: note.trim() }); setNote(""); }}>Resolve</button></div>
              {(cur.log || []).length > 0 && <div className="wo-dr-sec"><div className="caps">Activity</div>
                {cur.log.map(([s, n, by], i) => <div key={i} className="dd-log"><i/><span className="mono dd-log-d">{AL_ST[s] || s}</span><span className="dd-log-t">{n}</span><span className="sec dd-log-b">{by}</span></div>)}</div>}
            </div>
          </div>}
        </div>
      </>}

      {tab === "rules" && <div className="cm-2">
        <div className="card st-card">
          <div className="st-card-h">Alert rules<span>Thresholds come from Settings · inspection thresholds</span></div>
          {[["Hot-cell ΔT", `≥ ${alSet().hotCell} °C`, "detection", "critical"], ["Detection severity", "= critical", "detection", "critical"], ["String offline", "> 4 h on SCADA", "scada", "critical"], ["Soiling loss", `> ${alSet().soiling}%`, "scada", "medium"],
            ["Coverage", `< ${alSet().coverage}% of AOI`, "coverage", "medium"], ["Wind on flight day", `> ${alSet().maxWind} m/s`, "weather", "medium"], ["Work order", "past due date", "wo", "high"], ["Drone", "maintenance or service ≤ 14 d", "fleet", "medium"],
            ["Certification", "expires ≤ 60 d", "fleet", "high"], ["Report delivery", "> 5 working days", "sla", "high"], ["Warranty claim", "info requested", "warranty", "medium"]].map(([l, c, k, s]) => (
            <div key={l} className="st-row"><div className="st-row-l"><b>{l} {c}</b><span>{AL_CAT[k][0]}</span></div><div className="st-row-c" style={{ gap: 10, alignItems: "center" }}><span className={`al-st al-sev-t-${s}`}>{s}</span><label className="st-tog"><input type="checkbox" defaultChecked/><i/></label></div></div>))}
        </div>
        <div className="card st-card">
          <div className="st-card-h">Escalation chain<span>Unacknowledged critical & high alerts</span></div>
          {AL_ESC.map(([t, who, ch]) => <div key={t} className="st-row"><div className="st-row-l"><b>After {t}</b><span>{ch}</span></div><div className="st-row-c"><div className="inp">{who}</div></div></div>)}
        </div>
      </div>}
    </div>
  );
}

function alOpenCount() { try { return alBuild().map(a => ({ ...a, ...(alStore.v[a.id] || {}) })).filter(a => a.status === "new" && (a.sev === "critical" || a.sev === "high")).length; } catch { return 0; } }
Object.assign(window, { AlertsPage, alStore, alOpenCount, alBuild });
