/* SkyOps — Warranty claims. Turns eligible MODULE detections into manufacturer claim packs
   with serial-level evidence (IR + RGB at ≥600 W/m², temporal history, IEC TS 62446-3 metadata). */

const { useState: uSWC, useEffect: uEWC, useMemo: uMWC } = React;

const WC_ELIGIBLE = { hot_cell: "Hot cell", module_cracking: "Module cracking", delamination: "Delamination", activated_bypass: "Activated bypass diode", pid: "PID", missing_module: "Missing module" };
const WC_MFR = {
  "Longi Hi-MO5 LR5-72HPH-550M": { mfr: "LONGi Green Energy", product: 12, perf: 25, price: 118, prefix: "LRP23", contact: "warranty.eu@longi.com" },
  "Jinko Tiger Neo JKM570N-72HL4": { mfr: "JinkoSolar", product: 12, perf: 30, price: 124, prefix: "JKN22", contact: "service.eu@jinkosolar.com" },
  "Trina Vertex TSM-DE21 660W": { mfr: "Trina Solar", product: 12, perf: 25, price: 131, prefix: "TSD21", contact: "claims@trinasolar.com" },
};
const WC_SITE_MODEL = { "pt-ev-03": "Longi Hi-MO5 LR5-72HPH-550M", "es-mu-02": "Jinko Tiger Neo JKM570N-72HL4", "es-zr-07": "Trina Vertex TSM-DE21 660W" };
const WC_STATUS = { draft: "Draft", submitted: "Submitted", review: "Under review", info: "Info requested", approved: "Approved", rejected: "Rejected", credited: "Credited" };
const WC_FLOW = ["draft", "submitted", "review", "approved", "credited"];
const WC_LABOR = 46; // € per module swap

const wcSerial = (mod, prefix) => { const n = +mod.replace(/\D/g, ""); return `${prefix}${String(10 + (n % 12)).padStart(2, "0")}-${String(1000 + (n * 37) % 8999)}-${String(n).padStart(4, "0")}`; };
const wcModel = (site) => site.model || WC_SITE_MODEL[site.id] || "Longi Hi-MO5 LR5-72HPH-550M";
const wcCod = (site) => site.cod || (window.siteProfile ? window.siteProfile(site).cod : "2021-06-30");

function wcEligible(siteId) {
  const site = (window.SITES || []).find(s => s.id === siteId); if (!site) return [];
  const model = wcModel(site), M = WC_MFR[model] || WC_MFR["Longi Hi-MO5 LR5-72HPH-550M"];
  const codY = +wcCod(site).slice(0, 4), inWarranty = 2026 - codY < M.product;
  const dets = (window.DETECTIONS || []).filter(d => d.group === "MODULE");
  // seed detections belong to Évora; other sites get a deterministic subset
  const pool = siteId === "pt-ev-03" ? dets : dets.filter((_, i) => (i + siteId.length) % 3 === 0);
  return pool.map(d => {
    const covered = !!WC_ELIGIBLE[d.kind] && inWarranty;
    const cycles = d.temporal === "PERSISTENT" ? 3 : d.temporal === "DEGRADED" ? 2 : 1;
    return { ...d, siteId, serial: wcSerial(d.module, M.prefix), model, mfr: M.mfr, covered,
      reason: !WC_ELIGIBLE[d.kind] ? "Not a manufacturing defect (O&M scope)" : !inWarranty ? `Outside ${M.product}-yr product warranty` : null,
      cycles, firstSeen: cycles === 3 ? "2025-10-09" : cycles === 2 ? "2026-01-14" : "2026-04-15", irr: 900 + (+d.module.replace(/\D/g, "") % 90), value: M.price + WC_LABOR };
  });
}

const WC_SEED = [
  { id: "WC-2026-007", siteId: "es-mu-02", mfr: "JinkoSolar", model: "Jinko Tiger Neo JKM570N-72HL4", ref: "JKS-EU-88213", status: "approved", created: "2026-02-04", submitted: "2026-02-06", items: 22, value: 3740, credited: 0, note: "Hot-cell cluster INV-03 · 22 modules · replacement approved" },
  { id: "WC-2026-005", siteId: "pt-ev-03", mfr: "LONGi Green Energy", model: "Longi Hi-MO5 LR5-72HPH-550M", ref: "LG-WTY-20418", status: "credited", created: "2026-01-20", submitted: "2026-01-22", items: 14, value: 2296, credited: 2296, note: "Delamination batch LRP2311 · credited to O&M account" },
  { id: "WC-2026-009", siteId: "es-zr-07", mfr: "Trina Solar", model: "Trina Vertex TSM-DE21 660W", ref: "TS-C-4471", status: "info", created: "2026-03-02", submitted: "2026-03-05", items: 9, value: 1593, credited: 0, note: "Manufacturer requests IV curves for 9 modules" },
  { id: "WC-2026-010", siteId: "pt-ev-03", mfr: "LONGi Green Energy", model: "Longi Hi-MO5 LR5-72HPH-550M", ref: "—", status: "rejected", created: "2026-03-10", submitted: "2026-03-11", items: 6, value: 984, credited: 0, note: "Rejected: cracking attributed to installation handling" },
];
const wcStore = {
  list: (() => { try { const s = localStorage.getItem("skyops_wc_v1"); if (s) return JSON.parse(s); } catch {} return WC_SEED; })(),
  subs: new Set(),
  set(fn) { this.list = fn(this.list); try { localStorage.setItem("skyops_wc_v1", JSON.stringify(this.list)); } catch {} this.subs.forEach(s => s(this.list)); },
};
function useWC() { const [l, setL] = uSWC(wcStore.list); uEWC(() => { wcStore.subs.add(setL); return () => wcStore.subs.delete(setL); }, []); return l; }
const eur = (n) => "€" + Math.round(n).toLocaleString("en-US");

function WarrantyPage({ go, setActiveSite }) {
  const claims = useWC();
  const [building, setBuilding] = uSWC(null);
  const [sel, setSel] = uSWC(null);
  const sites = (window.SITES || []).filter(s => WC_SITE_MODEL[s.id] || s.model);
  const opp = uMWC(() => sites.map(s => {
    const el = wcEligible(s.id).filter(x => x.covered && !claims.some(c => c.siteId === s.id && (c.serials || []).includes(x.serial)));
    return { site: s, n: el.length, value: el.reduce((a, x) => a + x.value, 0) };
  }).filter(o => o.n > 0), [claims]);
  const open = claims.filter(c => ["submitted", "review", "info", "approved"].includes(c.status));
  const recovered = claims.reduce((a, c) => a + (c.credited || 0), 0);
  const decided = claims.filter(c => ["approved", "credited", "rejected"].includes(c.status));
  const rate = decided.length ? decided.filter(c => c.status !== "rejected").length / decided.length * 100 : 0;
  const cur = sel && claims.find(c => c.id === sel);

  return (
    <div className="page wc">
      <div className="page-head">
        <div className="title"><div className="kicker">Business · asset value recovery</div><h1>Warranty & insurance claims</h1>
          <div className="sub">Manufacturing defects go to the module manufacturer; external damage (hail, storm) goes to the insurer. Each claim carries inspection evidence and the module's history across cycles.</div></div>
        <div className="actions"><button className="btn btn-primary" onClick={() => setBuilding(opp[0] ? opp[0].site.id : "pt-ev-03")}><Icon name="plus" size={12}/>New claim</button></div>
      </div>

      <div className="wo-kpis">
        <div className="wo-kpi is-ok"><span className="caps">Unclaimed value</span><b className="mono">{eur(opp.reduce((a, o) => a + o.value, 0))}</b><em>{opp.reduce((a, o) => a + o.n, 0)} eligible modules not yet claimed</em></div>
        <div className="wo-kpi"><span className="caps">Open claims</span><b className="mono">{open.length}</b><em>{eur(open.reduce((a, c) => a + c.value, 0))} pending</em></div>
        <div className="wo-kpi"><span className="caps">Recovered YTD</span><b className="mono">{eur(recovered)}</b><em>credited by manufacturers</em></div>
        <div className="wo-kpi"><span className="caps">Approval rate</span><b className="mono">{rate.toFixed(1)}%</b><em>{decided.length} decided claims</em></div>
      </div>

      {window.CoreStrip && <window.CoreStrip dom="warranty" title="Argus · defect patterns worth claiming"/>}
      {opp.length > 0 && <div className="wc-opp">
        <div className="wc-opp-h"><Icon name="sparkles" size={13}/><b>Claimable now</b><span className="sec">from the latest inspections · defects within product warranty</span></div>
        <div className="wc-opp-list">{opp.map(o => (
          <button key={o.site.id} className="wc-opp-it" onClick={() => setBuilding(o.site.id)}>
            <div><b>{o.site.name}</b><span className="sec">{WC_MFR[wcModel(o.site)]?.mfr || "—"} · {wcModel(o.site).split(" ").slice(0, 2).join(" ")}</span></div>
            <span className="mono">{o.n} modules</span><b className="mono wc-opp-v">{eur(o.value)}</b><Icon name="arrow_right" size={12}/>
          </button>))}</div>
      </div>}

      <div className="card"><table className="tbl">
        <thead><tr><th>Claim</th><th>Site</th><th>Manufacturer</th><th className="r">Modules</th><th className="r">Value</th><th>Status</th><th>Submitted</th><th>Mfr. reference</th></tr></thead>
        <tbody>{claims.map(c => (
          <tr key={c.id} onClick={() => setSel(c.id)} className={sel === c.id ? "sel" : ""}>
            <td className="mono"><b>{c.id}</b></td>
            <td>{(window.SITES || []).find(s => s.id === c.siteId)?.name}</td>
            <td className="sec">{c.kind === "insurance" ? <span className="wc-kind">Insurance</span> : <span className="wc-kind wc-kind-m">Warranty</span>} {c.mfr}</td>
            <td className="r mono">{c.items}</td>
            <td className="r mono">{eur(c.value)}</td>
            <td><span className={`wc-st wc-st-${c.status}`}>{WC_STATUS[c.status]}</span></td>
            <td className="mono sec">{c.submitted || "—"}</td>
            <td className="mono sec">{c.ref}</td>
          </tr>))}</tbody></table></div>

      {cur && <WcDrawer c={cur} onClose={() => setSel(null)}/>}
      {building && <WcBuilder siteId={building} setSiteId={setBuilding} onClose={() => setBuilding(null)} onCreated={(id) => { setBuilding(null); setSel(id); }}/>}
    </div>
  );
}

function WcBuilder({ siteId, setSiteId, onClose, onCreated }) {
  const claims = useWC();
  const site = (window.SITES || []).find(s => s.id === siteId);
  const all = uMWC(() => wcEligible(siteId), [siteId]);
  const claimed = new Set(claims.filter(c => c.siteId === siteId).flatMap(c => c.serials || []));
  const elig = all.filter(x => x.covered && !claimed.has(x.serial));
  const excl = all.filter(x => !x.covered);
  const [pick, setPick] = uSWC(() => new Set(elig.map(x => x.serial)));
  uEWC(() => setPick(new Set(elig.map(x => x.serial))), [siteId]);
  const [ev, setEv] = uSWC({ ir: true, rgb: true, meta: true, history: true, iv: false, el: false });
  const items = elig.filter(x => pick.has(x.serial));
  const value = items.reduce((a, x) => a + x.value, 0);
  const M = WC_MFR[wcModel(site)] || {};
  const tog = (s) => setPick(p => { const n = new Set(p); n.has(s) ? n.delete(s) : n.add(s); return n; });
  const create = (submit) => {
    const id = `WC-2026-${String(11 + claims.length).padStart(3, "0")}`;
    wcStore.set(l => [{ id, siteId, mfr: M.mfr, model: wcModel(site), ref: "—", status: submit ? "submitted" : "draft", created: window.SKY_TODAY, submitted: submit ? window.SKY_TODAY : null,
      items: items.length, value, credited: 0, serials: items.map(x => x.serial), evidence: ev, note: `${items.length} modules · ${[...new Set(items.map(x => x.label))].join(", ")}` }, ...l]);
    onCreated(id);
  };
  const EV = [["ir", "Radiometric IR image per module", "≥ 600 W/m² · emissivity 0.85 · IEC TS 62446-3"], ["rgb", "RGB image pair", "same capture timestamp"], ["meta", "Capture metadata", "irradiance, ambient, wind, GSD, drone, pilot"],
    ["history", "Temporal history", "first seen, cycles persistent, ΔT trend"], ["iv", "IV curve trace", "often requested by manufacturer"], ["el", "Electroluminescence image", "confirms micro-cracks"]];
  return (
    <div className="ni-scrim" onClick={onClose}><div className="ni-modal wc-modal" onClick={e => e.stopPropagation()} role="dialog">
      <div className="ni-hd"><div><div className="kicker">New warranty claim</div><h3>{site?.name} · {M.mfr}</h3></div><button className="ask-hd-btn" onClick={onClose}><Icon name="x" size={13}/></button></div>
      <div className="ni-body wc-body">
        <div className="wc-b-l">
          <div className="ni-grid">
            <label className="field"><span>Site</span><select className="sel" value={siteId} onChange={e => setSiteId(e.target.value)}>{(window.SITES || []).filter(s => WC_SITE_MODEL[s.id] || s.model).map(s => <option key={s.id} value={s.id}>{s.name}</option>)}</select></label>
            <div className="field"><span>Module</span><div className="inp">{wcModel(site)}</div></div>
            <div className="field"><span>Commissioned</span><div className="inp mono">{wcCod(site)}</div></div>
            <div className="field"><span>Warranty</span><div className="inp mono">{M.product} yr product · {M.perf} yr performance</div></div>
          </div>
          <div className="wc-list-h"><span className="caps">Eligible modules · {items.length}/{elig.length} selected</span>
            <button className="btn btn-ghost btn-xs" onClick={() => setPick(new Set(elig.map(x => x.serial)))}>All</button><button className="btn btn-ghost btn-xs" onClick={() => setPick(new Set())}>None</button></div>
          <div className="wc-list">
            {elig.map(x => (
              <label key={x.serial} className={`wc-row ${pick.has(x.serial) ? "on" : ""}`}>
                <input type="checkbox" checked={pick.has(x.serial)} onChange={() => tog(x.serial)}/>
                <span className="wc-th" style={{ background: `linear-gradient(135deg,#1e3a5f, ${x.dT > 15 ? "#ef4444" : "#eab308"})` }}/>
                <span className="wc-r-m"><b className="mono">{x.serial}</b><em>{x.label} · {x.string.split(".").slice(0, 2).join(" · ")}</em></span>
                <span className="mono wc-r-d">ΔT +{x.dT.toFixed(1)} °C</span>
                <span className="wc-r-c">{x.cycles > 1 ? `${x.cycles} cycles · since ${x.firstSeen}` : "first seen this cycle"}</span>
                <span className="mono">{eur(x.value)}</span>
              </label>))}
            {elig.length === 0 && <div className="sec" style={{ padding: 14, fontSize: 12 }}>No unclaimed eligible modules on this site.</div>}
          </div>
          {excl.length > 0 && <div className="wc-excl"><Icon name="alert" size={11}/>{excl.length} detections excluded — {[...new Set(excl.map(x => x.reason))].join(" · ")}</div>}
        </div>
        <div className="wc-b-r">
          <div className="caps">Evidence pack</div>
          {EV.map(([k, l, d]) => <label key={k} className={`ni-inh ${ev[k] ? "on" : ""}`}><input type="checkbox" checked={ev[k]} onChange={e => setEv(x => ({ ...x, [k]: e.target.checked }))}/><span><b>{l}</b><em>{d}</em></span></label>)}
          <div className="wc-sum">
            <div className="ps-kv"><span>Modules</span><b className="mono">{items.length}</b></div>
            <div className="ps-kv"><span>Module value</span><b className="mono">{eur(items.length * (M.price || 0))}</b></div>
            <div className="ps-kv"><span>Swap labour</span><b className="mono">{eur(items.length * WC_LABOR)}</b></div>
            <div className="ps-kv wc-tot"><span>Claim value</span><b className="mono">{eur(value)}</b></div>
            <div className="ps-kv"><span>Send to</span><b className="mono">{M.contact}</b></div>
          </div>
          {!ev.iv && items.some(x => x.kind === "pid" || x.kind === "activated_bypass") && <div className="wc-excl"><Icon name="alert" size={11}/>PID and bypass-diode claims are usually returned without IV curves.</div>}
        </div>
      </div>
      <div className="ni-ft"><button className="btn btn-ghost" onClick={onClose}>Cancel</button><span className="grow"/>
        <button className="btn btn-secondary" disabled={!items.length} onClick={() => create(false)}>Save draft</button>
        <button className="btn btn-primary" disabled={!items.length} onClick={() => create(true)}><Icon name="send" size={12}/>Generate pack & submit</button></div>
    </div></div>
  );
}

/* Per-module history across inspection cycles (from Temporal intelligence) */
function wcHistory(c) {
  const cyc = (window.TM && window.TM.TM_CYCLES || []).map(x => x.label);
  const labels = cyc.length ? cyc : ["Q3 25", "Q4 25", "Q1 26", "Q2 26"];
  const el = window.wcEligible ? window.wcEligible(c.siteId) : [];
  const ins = c.kind === "insurance";
  const serials = c.serials && c.serials.length ? c.serials : el.filter(e => e.covered).slice(0, Math.min(c.items || 0, 8)).map(e => e.serial);
  const rows = ins ? Array.from({ length: Math.min(c.items, 8) }).map((_, i) => ({ id: `B-0${2 + (i % 3)}-${String(14 + i).padStart(2, "0")}`, label: "Activated bypass diode", dT: 9 + (i * 1.7) % 6 }))
    : serials.slice(0, 8).map(s => { const x = el.find(e => e.serial === s) || {}; return { id: s, label: x.label || "Module defect", dT: x.dT || 12 }; });
  return { labels, rows: rows.map((m, i) => {
    const first = ins ? 2 : 1 + (i % 2);
    return { ...m, cells: labels.map((_, t) => t < first ? null : +(m.dT * (0.55 + 0.15 * (t - first + 1))).toFixed(1)), first };
  }) };
}
function WcTemporal({ c }) {
  const { labels, rows } = wcHistory(c);
  if (!rows.length) return null;
  const ins = c.kind === "insurance";
  const more = (c.items || rows.length) - rows.length;
  return <div className="wo-dr-sec">
    <div className="caps">Temporal history per module <span className="wc-src">from Temporal intelligence</span></div>
    <div className="wc-th-note">{ins ? "Clean in every cycle before the 14 Nov 2025 hailstorm, defective from the next inspection on — proves the damage was caused by the event." : "Defect present and persistent or worsening across consecutive inspections — not a transient or soiling artefact."}</div>
    <div className="wc-hist" style={{ gridTemplateColumns: `minmax(0,1fr) repeat(${labels.length}, 54px)` }}>
      <span className="wc-hist-h">Module</span>{labels.map((l, i) => <span key={l} className="wc-hist-h mono">{l}{ins && i === 1 ? " ⚡" : ""}</span>)}
      {rows.map(m => <React.Fragment key={m.id}>
        <span className="wc-hist-m"><b className="mono">{m.id}</b><em>{m.label}</em></span>
        {m.cells.map((v, t) => <span key={t} className={`wc-hist-c ${v == null ? "ok" : v > 12 ? "hot" : "warm"}`}>{v == null ? "clean" : "+" + v + " °C"}</span>)}
      </React.Fragment>)}
    </div>
    {more > 0 && <div className="sec" style={{ fontSize: 10.5 }}>+{more} more modules in the exported pack</div>}
    {ins && <div className="sec" style={{ fontSize: 10.5 }}>⚡ hailstorm WX-07 · 2025-11-14, between Q4 25 and Q1 26</div>}
  </div>;
}

function WcDrawer({ c, onClose }) {
  const site = (window.SITES || []).find(s => s.id === c.siteId);
  const [ref, setRef] = uSWC(c.ref === "—" ? "" : c.ref);
  const upd = (p) => wcStore.set(l => l.map(x => x.id === c.id ? { ...x, ...p } : x));
  const idx = WC_FLOW.indexOf(c.status);
  const next = { draft: ["submitted", "Submit to manufacturer"], submitted: ["review", "Mark under review"], review: ["approved", "Mark approved"], info: ["review", "Info sent · back to review"], approved: ["credited", "Record credit"] }[c.status];
  return (<>
    <div className="wo-scrim" onClick={onClose}/>
    <aside className="wo-drawer" role="dialog" aria-label={c.id}>
      <div className="wo-dr-hd"><div>
        <div className="wo-dr-id"><span className="mono">{c.id}</span><span className={`wc-st wc-st-${c.status}`}>{WC_STATUS[c.status]}</span></div>
        <div className="wo-dr-t">{c.kind === "insurance" ? "Insurance claim" : "Warranty claim"} · {c.mfr} · {c.items} modules</div>
        <div className="sec wo-dr-s">{site?.name} · {c.model}</div></div>
        <button className="ask-hd-btn" onClick={onClose}><Icon name="x" size={13}/></button></div>
      <div className="wo-dr-body">
        <div className="wc-flow">{WC_FLOW.map((s, i) => <span key={s} className={`${i < idx || c.status === "credited" ? "done" : ""} ${s === c.status ? "cur" : ""}`}><i/>{WC_STATUS[s]}</span>)}</div>
        {(c.status === "rejected" || c.status === "info") && <div className="fl-alert" style={{ margin: 0 }}><Icon name="alert" size={12}/><span>{c.note}</span></div>}
        <div className="wo-dr-money">
          <div><span className="caps">Claim value</span><b className="mono">{eur(c.value)}</b></div>
          <div><span className="caps">Credited</span><b className="mono" style={{ color: c.credited ? "var(--sev-low)" : undefined }}>{eur(c.credited || 0)}</b></div>
          <div><span className="caps">Open for</span><b className="mono">{c.submitted ? Math.max(1, Math.round((new Date(window.SKY_TODAY) - new Date(c.submitted)) / 864e5)) + " d" : "—"}</b></div>
        </div>
        <div className="wo-dr-sec"><div className="caps">Manufacturer reference</div>
          <div style={{ display: "flex", gap: 6 }}><input className="inp mono" value={ref} onChange={e => setRef(e.target.value)} placeholder="RMA / case number"/><button className="btn btn-secondary btn-xs" onClick={() => upd({ ref: ref || "—" })}>Save</button></div></div>
        <div className="wo-dr-sec"><div className="caps">Evidence pack</div>
          {(c.kind === "insurance" ? ["Claim letter to insurer (PDF)", "Weather event report · WX-07 (IPMA)", "Storm path vs damage overlay", "Radiometric IR + RGB per module (ZIP)", "Temporal history · before / after event"] : ["Claim letter (PDF)", "Module list with serials (CSV)", "Radiometric IR + RGB per module (ZIP)", "Capture conditions & IEC TS 62446-3 statement", "Temporal history per module"]).map(f => <div key={f} className="wc-file"><Icon name="file" size={12}/><span>{f}</span><button className="btn btn-ghost btn-xs"><Icon name="download" size={11}/></button></div>)}
        </div>
        {(() => { const sw = (window.woStore?.list || []).filter(w => w.siteId === c.siteId && w.fieldReport?.part?.out); return sw.length ? <div className="wo-dr-sec"><div className="caps">Field swaps on this site · {sw.length}</div>{sw.map(w => <div key={w.id} className="ps-kv"><span className="mono">{w.id}</span><b className="mono">{w.fieldReport.part.out} → {w.fieldReport.part.in}</b></div>)}</div> : null; })()}
        <WcTemporal c={c}/>
        {c.serials && <div className="wo-dr-sec"><div className="caps">Modules · {c.serials.length}</div><div className="wc-serials">{c.serials.map(s => <span key={s} className="mono">{s}</span>)}</div></div>}
      </div>
      <div className="wo-dr-ft">
        {c.status !== "rejected" && c.status !== "credited" && c.status !== "draft" && <button className="btn btn-ghost btn-xs" onClick={() => upd({ status: "rejected" })}>Rejected</button>}
        {c.status === "review" && <button className="btn btn-ghost btn-xs" onClick={() => upd({ status: "info" })}>Info requested</button>}
        <span className="grow"/>
        {next && <button className="btn btn-primary btn-xs" onClick={() => upd({ status: next[0], ...(next[0] === "submitted" ? { submitted: window.SKY_TODAY } : {}), ...(next[0] === "credited" ? { credited: c.value } : {}) })}>{next[1]}<Icon name="arrow_right" size={11}/></button>}
      </div>
    </aside>
  </>);
}

Object.assign(window, { WarrantyPage, wcStore, wcEligible });
