/* SkyOps — Zone inspection report
   One flown zone → which modules have thermal faults, which need cleaning,
   per-module thermal heatmap, and an actionable work-order list. */

const { useState: useStateZR, useMemo: useMemoZR } = React;

const ZR_TYPE = {
  ok:       { label: "Healthy",         color: "#1d3b2c" },
  hot_cell: { label: "Hot cell",        color: null },
  bypass:   { label: "Bypass diode",    color: "#f97316" },
  cracked:  { label: "Micro-crack",     color: "#eab308" },
  pid:      { label: "PID",             color: "#8b5cf6" },
  offline:  { label: "String offline",  color: "#d946ef" },
};
const ZR_CLS = { 1: { label: "CoA 1", sub: "Minor · monitor", color: "#eab308" }, 2: { label: "CoA 2", sub: "Fault · repair", color: "#f97316" }, 3: { label: "CoA 3", sub: "Critical · safety", color: "#ef4444" } };

function zrColor(p, mode) {
  const Z = window.ZR;
  if (mode === "thermal") return window.zrIron((p.tmax - (Z.T_BASE - 3)) / 34);
  if (mode === "soiling") return `color-mix(in oklab, #c79a4a ${Math.round(p.soil * 100)}%, #13211a)`;
  if (p.type === "hot_cell") return ZR_CLS[p.cls].color;
  if (p.type !== "ok") return ZR_TYPE[p.type].color;
  if (p.soil > 0.6) return "url(#zr-soil-h)";
  if (p.soil > 0.35) return "url(#zr-soil-l)";
  return ZR_TYPE.ok.color;
}
const zrEur = (n) => "€" + Math.round(n).toLocaleString("en");

function ZoneReport(props) {
  const micId = props.mic?.id || "MIC-2026-04-033", zoneId = props.zone || "C3";
  window.ZR = window.zrGet(micId, zoneId);
  return <ZoneReportBody key={micId + zoneId} {...props} micId={micId} zoneId={zoneId}/>;
}

function ZoneReportBody({ go, embedded, mic, site, micId, zoneId, zones, onPickZone, onBack }) {
  const Z = window.ZR;
  const zInfo = (zones || []).find(z => z.id === zoneId) || { date: mic?.startedAt || "2026-04-15" };
  const block = /^Z\d/.test(zoneId) ? "Z" : zoneId[0], zn = /^Z\d/.test(zoneId) ? +zoneId.slice(1) : +zoneId[1];
  const firstIssue = Z.issues.find(i => i.cls === 3) || Z.issues[0];
  const [sel, setSel] = useStateZR(firstIssue.panels[0]);
  const [mode, setMode] = useStateZR("status");
  const [filter, setFilter] = useStateZR("all");
  const [tab, setTab] = useStateZR("thermal");
  const [picked, setPicked] = useStateZR(() => new Set(Z.issues.filter(i => i.cls >= 2).map(i => i.id)));
  const [toast, setToast] = useStateZR(null);
  const C = Z.counts;

  const pick = (id) => setPicked(s => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
  const flash = (m) => { setToast(m); setTimeout(() => setToast(null), 2200); };

  return (
    <div className={`zr ${embedded ? "is-embedded" : ""}`} data-screen-label="Zone report">
      <header className="zr-head">
        <div className="zr-head-l">
          {onBack && <button className="zr-back" onClick={onBack}><Icon name="chevron_down" size={11} style={{ transform: "rotate(90deg)" }}/>All zones · {micId}</button>}
          <div className="kicker">{site?.name || "Évora Plana PV"} · Zone {zoneId} · {micId}</div>
          <h1>Zone {zoneId} — inspection report</h1>
          <div className="sub">{block === "Z" ? `Zone ${zoneId}` : `Block ${block}, sector ${zn}`} · rows 1–12 · {Z.N.toLocaleString()} modules · flown {zInfo.date}, {10 + (zn % 3)}:{String(10 + zn * 9).padStart(2, "0")} UTC · {mic?.drone || "DJI M350 RTK · Zenmuse H30T"}</div>
        </div>
        <div className="zr-head-r">
          <button className="btn btn-secondary" onClick={() => flash("Share link copied")}><Icon name="share" size={12}/>Share with client</button>
          <button className="btn btn-secondary" onClick={() => window.print()}><Icon name="download" size={12}/>Export PDF</button>
          <button className="btn btn-primary" onClick={() => window.dispatchEvent(new CustomEvent("skyops:new-wo",{detail:{ title: `Zone report actions · ${picked.size} items`, mic: localStorage.getItem("skyops_mic") || "", siteId: localStorage.getItem("skyops_site") || undefined }}))}><Icon name="plus" size={12}/>Create work order · {picked.size}</button>
        </div>
      </header>

      <div className="zr-cond">
        {[["Irradiance", `${Z.IRR} W/m²`, "ok", "≥ 600 required · IEC TS 62446-3"], ["Ambient", `${Z.AMBIENT} °C`], ["Wind", "8 km/h"], ["Cloud", "0/8 okta"],
          ["Thermal GSD", "3.2 cm/px"], ["RGB GSD", "1.1 cm/px"], ["Coverage", "100%", "ok"], ["Emissivity", "0.85 · glass"]].map(([k, v, ok, tip]) => (
          <div key={k} className="zr-cond-i" title={tip || ""}>
            <span className="caps">{k}</span>
            <b className="mono">{v}{ok && <Icon name="check" size={10} style={{ color: "var(--sev-low)", marginLeft: 4 }}/>}</b>
          </div>
        ))}
      </div>

      <div className="zr-top">
        <FarmMini zones={zones || []} current={zoneId} onPick={onPickZone}/>
        <div className="zr-kpis">
          <div className="zr-kpi">
            <span className="caps">Modules inspected</span>
            <b className="mono">{C.total.toLocaleString()}</b>
            <em><span style={{ color: "var(--sev-low)" }}>{C.healthy.toLocaleString()}</span> healthy · {(C.healthy / C.total * 100).toFixed(1)}%</em>
          </div>
          <div className="zr-kpi zr-kpi-th" onClick={() => { setFilter("thermal"); setTab("thermal"); }}>
            <span className="caps">Thermal anomalies</span>
            <b className="mono">{C.thermal}</b>
            <div className="zr-stack">
              <i style={{ flex: C.cls3, background: ZR_CLS[3].color }}/><i style={{ flex: C.cls2, background: ZR_CLS[2].color }}/><i style={{ flex: C.cls1, background: ZR_CLS[1].color }}/>
            </div>
            <em><b style={{ color: ZR_CLS[3].color }}>{C.cls3}</b> CoA 3 · <b style={{ color: ZR_CLS[2].color }}>{C.cls2}</b> CoA 2 · <b style={{ color: ZR_CLS[1].color }}>{C.cls1}</b> CoA 1</em>
          </div>
          <div className="zr-kpi zr-kpi-cl" onClick={() => { setFilter("cleaning"); setTab("cleaning"); }}>
            <span className="caps">Need cleaning</span>
            <b className="mono">{C.cleaning}</b>
            <div className="zr-stack">
              <i style={{ flex: C.heavy, background: "#b8904a" }}/><i style={{ flex: C.cleaning - C.heavy - C.spot, background: "#7d6d3e" }}/><i style={{ flex: C.spot, background: "#e5d38a" }}/>
            </div>
            <em>{C.heavy} heavy · {C.cleaning - C.heavy - C.spot} light · {C.spot} spot (birds)</em>
          </div>
          <div className="zr-kpi">
            <span className="caps">Est. production loss</span>
            <b className="mono" style={{ color: "var(--sev-critical)" }}>{zrEur(C.lossThermal + C.lossSoil)}<small>/yr</small></b>
            <em>{zrEur(C.lossThermal)} thermal · {zrEur(C.lossSoil)} soiling</em>
          </div>
          <div className="zr-kpi zr-kpi-act">
            <span className="caps">Act within 48 h</span>
            <b className="mono">{Z.issues.filter(i => i.urgency === "48 h").length}</b>
            <em>CoA 3 modules · fire-risk hot spots</em>
          </div>
        </div>
      </div>

      <div className="zr-main">
        <ZoneMap sel={sel} setSel={setSel} mode={mode} setMode={setMode} filter={filter} setFilter={setFilter}/>
        <PanelInspector i={sel} setSel={setSel} picked={picked} pick={pick}/>
      </div>

      <section className="zr-lists card">
        <div className="zr-lists-tabs">
          <button className={tab === "thermal" ? "on" : ""} onClick={() => setTab("thermal")}><Icon name="thermometer" size={12}/>Thermal anomalies <em>{Z.issues.length}</em></button>
          <button className={tab === "cleaning" ? "on" : ""} onClick={() => setTab("cleaning")}><Icon name="sparkles" size={12}/>Cleaning plan <em>{C.cleaning}</em></button>
          <span className="grow"/>
          <span className="muted" style={{ fontSize: 11 }}>{picked.size} selected for work order</span>
        </div>
        {tab === "thermal" ? <ThermalTable sel={sel} setSel={setSel} picked={picked} pick={pick}/> : <CleaningPlan setSel={setSel} picked={picked} pick={pick}/>}
      </section>

      {toast && <div className="zr-toast"><Icon name="check_circle" size={13}/>{toast}</div>}
    </div>
  );
}

/* ── Farm minimap ─────────────────────────── */
function FarmMini({ zones, current, onPick }) {
  return (
    <div className="zr-farm card">
      <div className="zr-farm-hd"><span className="caps">Inspection · {zones.length} zones</span><span className="mono muted">{zones.filter(z => z.status === "ready").length} reports ready</span></div>
      <div className="zr-farm-grid" style={zones.length < 16 ? { gridTemplateColumns: `repeat(${Math.min(zones.length, 6)}, 1fr)` } : null}>
        {zones.map(z0 => z0.id).map(id => {
          const z = zones.find(x => x.id === id) || { status: "notflown" };
          const st = id === current ? "current" : z.status;
          return (
            <button key={id} className={`zr-zone zr-zone-${st}`} disabled={z.status !== "ready" || !onPick}
              onClick={() => onPick && onPick(id)} title={`${id} · ${z.status}${z.date ? " · " + z.date : ""}`}>
              <span className="mono">{id}</span>
            </button>
          );
        })}
      </div>
      <div className="zr-farm-lg">
        <span><i className="zr-zone-current"/>This report</span>
        <span><i className="zr-zone-ready"/>Ready</span>
        <span><i className="zr-zone-processing"/>Processing</span>
      </div>
    </div>
  );
}

function FarmMiniUnused() {
  const Z = window.ZR;
  return (
    <div className="zr-farm card">
      <div className="zr-farm-hd"><span className="caps">Farm · 16 zones</span><span className="mono muted">210.5 MW</span></div>
      <div className="zr-farm-grid">
        {Z.ZONES.map(z => (
          <div key={z.id} className={`zr-zone zr-zone-${z.status}`} title={`${z.id} · ${z.status} · ${z.date}`}>
            <span className="mono">{z.id}</span>
          </div>
        ))}
      </div>
      <div className="zr-farm-lg">
        <span><i className="zr-zone-current"/>This flight</span>
        <span><i className="zr-zone-done"/>Inspected</span>
        <span><i className="zr-zone-scheduled"/>Scheduled</span>
      </div>
    </div>
  );
}

/* ── Zone map ─────────────────────────────── */
function ZoneMap({ sel, setSel, mode, setMode, filter, setFilter }) {
  const Z = window.ZR;
  const [view3d, setView3d] = useStateZR(() => localStorage.getItem("skyops_zr_dim") || "2d");
  const pickDim = (d) => { setView3d(d); try { localStorage.setItem("skyops_zr_dim", d); } catch {} };
  const PW = 9, PH = 13, TG = 14, RG = 12, LX = 34, TY = 22;
  const TW = Z.TCOLS * PW, RH = Z.TROWS * PH;
  const W = LX + Z.TABLES * TW + (Z.TABLES - 1) * TG + 10;
  const H = TY + Z.ROWS * RH + (Z.ROWS - 1) * RG + 30;
  const pos = (p) => ({ x: LX + p.table * (TW + TG) + p.tc * PW, y: TY + p.row * (RH + RG) + p.tr * PH });
  const dim = (p) => filter === "thermal" ? p.type === "ok" : filter === "cleaning" ? p.soil <= 0.35 : false;
  const sp = Z.panels[sel];
  const sxy = pos(sp);

  return (
    <div className="zr-map card">
      <div className="zr-map-bar">
        <div className="seg">
          {[["status", "Status"], ["thermal", "Thermal"], ["soiling", "Soiling"]].map(([k, l]) => <button key={k} className={mode === k ? "on" : ""} onClick={() => setMode(k)}>{l}</button>)}
        </div>
        <div className="seg">
          {[["all", "All modules"], ["thermal", "Thermal only"], ["cleaning", "Cleaning only"]].map(([k, l]) => <button key={k} className={filter === k ? "on" : ""} onClick={() => setFilter(k)}>{l}</button>)}
        </div>
        <span className="grow"/>
        <ZoneLegend mode={mode}/>
      </div>
      <div className="zr-dim">
        <div className="seg">
          <button className={view3d === "2d" ? "on" : ""} onClick={() => pickDim("2d")}><Icon name="grid" size={11}/> 2D map</button>
          <button className={view3d === "3d" ? "on" : ""} onClick={() => pickDim("3d")}><Icon name="cube" size={11}/> 3D digital twin</button>
        </div>
      </div>
      {view3d === "3d" && <ZoneTwin3D sel={sel} setSel={setSel} mode={mode} filter={filter}/>}
      <div className="zr-map-stage" style={view3d === "3d" ? { display: "none" } : undefined}>
        <svg viewBox={`0 0 ${W} ${H}`} className="zr-map-svg">
          <defs>
            <pattern id="zr-soil-l" width="4" height="4" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"><rect width="4" height="4" fill="#2b3424"/><rect width="1.6" height="4" fill="#8a7a46"/></pattern>
            <pattern id="zr-soil-h" width="4" height="4" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"><rect width="4" height="4" fill="#4a3f24"/><rect width="2.4" height="4" fill="#c49a52"/></pattern>
          </defs>
          {Array.from({ length: Z.TABLES }).map((_, t) => <text key={t} x={LX + t * (TW + TG) + TW / 2} y={12} textAnchor="middle" className="zr-axis">T{t + 1}</text>)}
          {Array.from({ length: Z.ROWS }).map((_, r) => <text key={r} x={LX - 8} y={TY + r * (RH + RG) + RH / 2 + 3} textAnchor="end" className="zr-axis">R{String(r + 1).padStart(2, "0")}</text>)}
          {Z.panels.map(p => {
            const { x, y } = pos(p);
            return <rect key={p.i} x={x + 0.5} y={y + 0.5} width={PW - 1} height={PH - 1} rx="0.8"
              fill={zrColor(p, mode)} opacity={dim(p) ? 0.18 : 1} className="zr-cell" onClick={() => setSel(p.i)}>
              <title>{p.id} · {ZR_TYPE[p.type].label}{p.type !== "ok" ? ` · ΔT ${p.dT} K` : ""}{p.soil > 0.35 ? ` · soiling ${Math.round(p.soil * 100)}%` : ""}</title>
            </rect>;
          })}
          {mode === "status" && Z.panels.filter(p => p.cls === 3).map(p => { const { x, y } = pos(p); return <circle key={p.i} cx={x + PW / 2} cy={y + PH / 2} r="7" fill="none" stroke="#ef4444" strokeWidth="1" className="zr-pulse" pointerEvents="none"/>; })}
          <rect x={sxy.x - 1.5} y={sxy.y - 1.5} width={PW + 2} height={PH + 2} fill="none" stroke="#fff" strokeWidth="1.6" rx="1.5" pointerEvents="none"/>
          <g transform={`translate(${LX}, ${H - 14})`}>
            <rect width="54" height="3" fill="var(--fg-secondary)"/><text x="60" y="4" className="zr-axis" textAnchor="start">20 m</text>
            <text x={W - LX - 64} y="4" className="zr-axis">Road ↙ SW · dust source</text>
          </g>
        </svg>
      </div>
    </div>
  );
}

function ZoneLegend({ mode }) {
  if (mode === "thermal") return <div className="zr-lg"><span className="mono">44 °C</span><i className="zr-lg-iron"/><span className="mono">78 °C</span></div>;
  if (mode === "soiling") return <div className="zr-lg"><span>Clean</span><i className="zr-lg-soil"/><span>Heavy</span></div>;
  return (
    <div className="zr-lg">
      {[["#1d3b2c", "Healthy"], [ZR_CLS[1].color, "CoA 1"], [ZR_CLS[2].color, "CoA 2"], [ZR_CLS[3].color, "CoA 3"], ["#8b5cf6", "PID"], ["#d946ef", "Offline"]].map(([c, l]) => <span key={l}><i style={{ background: c }}/>{l}</span>)}
      <span><i className="zr-lg-hatch"/>Cleaning</span>
    </div>
  );
}

/* ── Panel inspector with thermal heatmap ─────── */
function PanelInspector({ i, setSel, picked, pick }) {
  const Z = window.ZR;
  const p = Z.panels[i];
  const [view, setView] = useStateZR("thermal");
  const cells = useMemoZR(() => Z.cells(p), [i]);
  const issue = Z.issues.find(x => x.panels.includes(i));
  const lo = Math.min(...cells), hi = Math.max(Z.T_BASE + 10, ...cells);
  const norm = (t) => (t - (lo - 0.5)) / (hi - lo + 0.5);
  const maxIdx = cells.indexOf(Math.max(...cells));
  const mc = maxIdx % Z.CELL_C, mr = Math.floor(maxIdx / Z.CELL_C);
  const CS = 22, GW = Z.CELL_C * CS, GH = Z.CELL_R * CS;
  const anomalies = Z.issues.map(x => x.panels[0]);
  const ai = anomalies.indexOf(issue ? issue.panels[0] : -1);
  const step = (d) => { const k = ai < 0 ? 0 : (ai + d + anomalies.length) % anomalies.length; setSel(anomalies[k]); };
  const clean = p.soil > 0.35 ? (p.bird && p.soil < 0.6 ? "Spot clean" : p.soil > 0.6 ? "Heavy wash" : "Light wash") : null;
  const ref = Z.T_BASE;

  const diag = {
    ok: "No thermal abnormality. Temperature distribution uniform within ±1.5 K of the row reference.",
    hot_cell: `Single-cell hotspot at cell ${String.fromCharCode(65 + mc)}${mr + 1}, ${p.dT} K above reference. Typical causes: cell crack, shading or solder bond failure. ${p.cls === 3 ? "ΔT > 20 K — risk of backsheet burn-through." : ""}`,
    bypass: `One of three substrings uniformly warmer (+${p.dT} K) — bypass diode conducting. Module output reduced ≈33%.`,
    cracked: `Diffuse warm area around cell ${String.fromCharCode(65 + mc)}${mr + 1}; pattern consistent with micro-cracks. Confirm with EL imaging.`,
    pid: "Frame-edge heating increasing toward the negative pole of the string — potential-induced degradation pattern.",
    offline: "Whole module uniformly +4–5 K, same as all 30 modules in the string — string is open-circuit, not producing.",
  }[p.type];

  return (
    <aside className="zr-insp card">
      <div className="zr-insp-hd">
        <div>
          <div className="caps">Module</div>
          <div className="zr-insp-id mono">{p.id}</div>
          <div className="muted mono" style={{ fontSize: 10.5 }}>{p.string} · row {p.row + 1} · table {p.table + 1} · pos {p.tr * Z.TCOLS + p.tc + 1}</div>
        </div>
        <div className="zr-insp-nav">
          <button onClick={() => step(-1)} title="Previous anomaly"><Icon name="chevron_down" size={12} style={{ transform: "rotate(90deg)" }}/></button>
          <span className="mono muted">{ai >= 0 ? `${ai + 1}/${anomalies.length}` : "—"}</span>
          <button onClick={() => step(1)} title="Next anomaly"><Icon name="chevron_down" size={12} style={{ transform: "rotate(-90deg)" }}/></button>
        </div>
      </div>

      <div className="zr-insp-tags">
        <span className="zr-tag" style={{ "--c": p.type === "hot_cell" ? ZR_CLS[p.cls].color : p.type === "ok" ? "#22c55e" : ZR_TYPE[p.type].color }}>{ZR_TYPE[p.type].label}</span>
        {p.cls > 0 && <span className="zr-tag" style={{ "--c": ZR_CLS[p.cls].color }}>{ZR_CLS[p.cls].label} · {ZR_CLS[p.cls].sub}</span>}
        {clean && <span className="zr-tag" style={{ "--c": "#c49a52" }}>{clean} · {Math.round(p.soil * 100)}%</span>}
        {p.conf > 0 && <span className="muted mono" style={{ fontSize: 10 }}>conf {Math.round(p.conf * 100)}%</span>}
      </div>

      <div className="zr-insp-view">
        <div className="seg">
          {[["thermal", "Thermal"], ["rgb", "RGB"], ["split", "Split"]].map(([k, l]) => <button key={k} className={view === k ? "on" : ""} onClick={() => setView(k)}>{l}</button>)}
        </div>
        <span className="mono muted" style={{ fontSize: 10 }}>{Z.CELL_C}×{Z.CELL_R} cells · radiometric</span>
      </div>

      <div className={`zr-hm ${view === "split" ? "split" : ""}`}>
        {(view === "thermal" || view === "split") && (
          <div className="zr-hm-pane">
            <svg viewBox={`-4 -4 ${GW + 8} ${GH + 8}`} className="zr-hm-svg">
              <rect x="-4" y="-4" width={GW + 8} height={GH + 8} rx="3" fill="#2a2f38"/>
              {cells.map((t, k) => {
                const c = k % Z.CELL_C, r = Math.floor(k / Z.CELL_C);
                return <rect key={k} x={c * CS} y={r * CS} width={CS - 1} height={CS - 1} fill={window.zrIron(norm(t))}><title>{String.fromCharCode(65 + c)}{r + 1}: {t.toFixed(1)} °C</title></rect>;
              })}
              {[1, 2].map(k => <line key={k} x1={k * 2 * CS - 0.5} x2={k * 2 * CS - 0.5} y1="0" y2={GH} stroke="#0b0420" strokeWidth="1.2" opacity="0.6"/>)}
              <g transform={`translate(${mc * CS + CS / 2}, ${mr * CS + CS / 2})`} pointerEvents="none">
                <circle r="9" fill="none" stroke="#fff" strokeWidth="1.4"/>
                <path d="M-14 0h8M6 0h8M0 -14v8M0 6v8" stroke="#fff" strokeWidth="1.4"/>
              </g>
            </svg>
            <div className="zr-hm-scale">
              <span className="mono">{hi.toFixed(1)}°</span>
              <i style={{ background: `linear-gradient(0deg, ${[0, 0.25, 0.5, 0.75, 1].map(window.zrIron).join(",")})` }}/>
              <span className="mono">{lo.toFixed(1)}°</span>
            </div>
          </div>
        )}
        {(view === "rgb" || view === "split") && (
          <div className="zr-hm-pane">
            <svg viewBox={`-4 -4 ${GW + 8} ${GH + 8}`} className="zr-hm-svg">
              <rect x="-4" y="-4" width={GW + 8} height={GH + 8} rx="3" fill="#b9bec6"/>
              {cells.map((_, k) => {
                const c = k % Z.CELL_C, r = Math.floor(k / Z.CELL_C);
                return <rect key={k} x={c * CS} y={r * CS} width={CS - 1} height={CS - 1} fill={(c + r) % 2 ? "#1b2b4a" : "#1e3052"}/>;
              })}
              {p.soil > 0.35 && <rect x="0" y={GH * 0.62} width={GW} height={GH * 0.38} fill="url(#zr-dust)"/>}
              {p.bird && <ellipse cx={3.5 * CS} cy={4.5 * CS} rx="7" ry="5" fill="#e8e4d6" opacity="0.9"/>}
              <defs><linearGradient id="zr-dust" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#a68a5a" stopOpacity="0"/><stop offset="1" stopColor="#a68a5a" stopOpacity={0.35 + p.soil * 0.5}/></linearGradient></defs>
              <rect x="0" y="0" width={GW} height={GH} fill="url(#zr-glare)" opacity="0.25"/>
              <defs><linearGradient id="zr-glare" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#fff" stopOpacity="0.4"/><stop offset="0.4" stopColor="#fff" stopOpacity="0"/></linearGradient></defs>
            </svg>
          </div>
        )}
      </div>

      <div className="zr-read">
        {[["T max", `${p.tmax.toFixed(1)} °C`, p.dT > 10], ["T mean", `${p.tmean} °C`], ["ΔT vs ref.", `${p.type === "ok" ? "+" + (p.tmax - ref).toFixed(1) : "+" + p.dT} K`, p.dT > 10], ["Reference", `${ref} °C`], ["Soiling", `${Math.round(p.soil * 100)}%`, p.soil > 0.6], ["Loss", `${zrEur(p.loss)}/yr`, p.loss > 5]].map(([k, v, warn]) => (
          <div key={k}><span className="caps">{k}</span><b className="mono" style={warn ? { color: "var(--sev-high)" } : null}>{v}</b></div>
        ))}
      </div>

      <div className="zr-diag">
        <div className="caps">Diagnosis</div>
        <p>{diag}{clean && ` Surface soiling ${Math.round(p.soil * 100)}%${p.bird ? " with bird dropping on upper cells" : ", concentrated on the lower edge"} — ${clean.toLowerCase()} recommended.`}</p>
        {issue && <div className="zr-diag-act"><Icon name="settings" size={11}/><span>{issue.action}</span><b className="mono">{issue.urgency}</b></div>}
      </div>

      <div className="zr-insp-ft">
        {issue ? (
          <button className={`btn ${picked.has(issue.id) ? "btn-secondary" : "btn-primary"} btn-xs`} onClick={() => pick(issue.id)}>
            <Icon name={picked.has(issue.id) ? "check" : "plus"} size={11}/>{picked.has(issue.id) ? "In work order" : "Add to work order"}
          </button>
        ) : <span className="muted" style={{ fontSize: 11 }}>No thermal action required</span>}
        <span className="grow"/>
        <span className="mono muted" style={{ fontSize: 10 }}>{Z.MODULE.model}</span>
      </div>
    </aside>
  );
}

/* ── Thermal table ─────────────────────────── */
function ThermalTable({ sel, setSel, picked, pick }) {
  const Z = window.ZR;
  const [cls, setCls] = useStateZR("all");
  const rows = Z.issues.filter(i => cls === "all" || i.cls === +cls);
  return (
    <>
      <div className="zr-tbar">
        <div className="seg">
          {[["all", "All"], ["3", "CoA 3"], ["2", "CoA 2"], ["1", "CoA 1"]].map(([k, l]) => <button key={k} className={cls === k ? "on" : ""} onClick={() => setCls(k)}>{l}</button>)}
        </div>
        <span className="muted" style={{ fontSize: 11 }}>Classification per IEC TS 62446-3 · ΔT measured against row reference at {Z.IRR} W/m²</span>
      </div>
      <div className="zr-tbl-wrap">
        <table className="tbl zr-tbl">
          <thead><tr><th style={{ width: 28 }}/><th>ID</th><th>Finding</th><th>Location</th><th>String</th><th className="r">ΔT</th><th>Class</th><th className="r">Conf.</th><th className="r">Loss/yr</th><th>Recommended action</th><th>Due</th></tr></thead>
          <tbody>
            {rows.map(x => (
              <tr key={x.id} className={x.panels.includes(sel) ? "sel" : ""} onClick={() => setSel(x.panels[0])}>
                <td onClick={e => { e.stopPropagation(); pick(x.id); }}><input type="checkbox" checked={picked.has(x.id)} readOnly/></td>
                <td className="mono">{x.id}</td>
                <td><span className="zr-dot" style={{ background: x.type === "hot_cell" ? ZR_CLS[x.cls].color : ZR_TYPE[x.type].color }}/>{x.label}</td>
                <td className="mono">{x.where}</td>
                <td className="mono">{x.string}</td>
                <td className="r mono num">+{x.dT.toFixed(1)} K</td>
                <td><span className="zr-cls" style={{ "--c": ZR_CLS[x.cls].color }}>{ZR_CLS[x.cls].label}</span></td>
                <td className="r mono num">{Math.round(x.conf * 100)}%</td>
                <td className="r mono num">{zrEur(x.loss)}</td>
                <td className="sec">{x.action}</td>
                <td><span className={`zr-due ${x.urgency === "48 h" ? "crit" : x.urgency === "7 days" ? "high" : ""}`}>{x.urgency}</span></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </>
  );
}

/* ── Cleaning plan (by row) ────────────────── */
function CleaningPlan({ setSel, picked, pick }) {
  const Z = window.ZR;
  const byRow = Array.from({ length: Z.ROWS }).map((_, r) => {
    const items = Z.cleaning.filter(c => Z.panels[c.i].row === r);
    const heavy = items.filter(c => c.level === "heavy").length, spot = items.filter(c => c.level === "spot").length;
    return { r, items, heavy, spot, light: items.length - heavy - spot, loss: items.reduce((a, c) => a + c.loss, 0),
      method: heavy > 30 ? "Full row wash (robot)" : items.length > 20 ? "Full row wash (robot)" : spot > 0 && items.length - spot < 6 ? "Manual spot clean" : items.length ? "Partial wash" : "—" };
  }).filter(x => x.items.length).sort((a, b) => b.items.length - a.items.length);
  const total = Z.cleaning.length, rec = byRow.reduce((a, x) => a + x.loss, 0);
  return (
    <>
      <div className="zr-tbar">
        <span className="sec" style={{ fontSize: 12 }}>Soiling increases toward the gravel access road (SW). Recommend robotic wash of the {byRow.filter(x => x.method.startsWith("Full")).length} worst rows and manual spot cleaning for bird droppings.</span>
        <span className="grow"/>
        <span className="mono" style={{ fontSize: 11 }}>{total} modules · recovers <b style={{ color: "var(--sev-low)" }}>{zrEur(rec)}/yr</b></span>
      </div>
      <div className="zr-tbl-wrap">
        <table className="tbl zr-tbl">
          <thead><tr><th style={{ width: 28 }}/><th>Row</th><th style={{ width: "34%" }}>Modules to clean</th><th className="r">Heavy</th><th className="r">Light</th><th className="r">Spot</th><th className="r">Recovers/yr</th><th>Method</th></tr></thead>
          <tbody>
            {byRow.map(x => {
              const id = `CL-R${String(x.r + 1).padStart(2, "0")}`;
              return (
                <tr key={x.r} onClick={() => setSel(x.items[0].i)}>
                  <td onClick={e => { e.stopPropagation(); pick(id); }}><input type="checkbox" checked={picked.has(id)} readOnly/></td>
                  <td className="mono"><b>R{String(x.r + 1).padStart(2, "0")}</b></td>
                  <td>
                    <div className="zr-rowbar">
                      <i style={{ width: `${x.heavy / Z.PER_ROW * 100}%`, background: "#b8904a" }}/>
                      <i style={{ width: `${x.light / Z.PER_ROW * 100}%`, background: "#7d6d3e" }}/>
                      <i style={{ width: `${x.spot / Z.PER_ROW * 100}%`, background: "#e5d38a" }}/>
                      <span className="mono">{x.items.length}/{Z.PER_ROW}</span>
                    </div>
                  </td>
                  <td className="r mono num">{x.heavy}</td>
                  <td className="r mono num">{x.light}</td>
                  <td className="r mono num">{x.spot}</td>
                  <td className="r mono num">{zrEur(x.loss)}</td>
                  <td className="sec">{x.method}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </>
  );
}

window.ZoneReport = ZoneReport;
