/* SkyOps — Drone CRUD: model catalogue, full add/edit/duplicate form, readiness checks, retire/delete. */

const { useState: uSDF, useRef: uRDF, useMemo: uMDF } = React;
const DF_T = () => window.SKY_TODAY;
const dfToast = (m) => window.dispatchEvent(new CustomEvent("skyops:toast", { detail: m }));

const DM_MODELS = [
  { m: "DJI M350 RTK", cls: "C3", mtow: 9.2, wind: 12, end: 55, ip: "IP55", bat: "TB65", fw: "v09.01", payloads: ["Zenmuse H30T", "Zenmuse H20T", "Zenmuse H20N", "Zenmuse P1", "Zenmuse L2"], rtk: "built-in" },
  { m: "DJI M300 RTK", cls: "Legacy (no class)", mtow: 9.0, wind: 15, end: 55, ip: "IP45", bat: "TB60", fw: "v07.02", payloads: ["Zenmuse H20T", "Zenmuse H20N", "Zenmuse P1", "Zenmuse L2"], rtk: "built-in" },
  { m: "DJI Matrice 4T", cls: "C2", mtow: 1.42, wind: 12, end: 49, ip: "—", bat: "M4 Intelligent", fw: "v01.04", payloads: ["Integrated"], rtk: "module" },
  { m: "DJI Matrice 30T", cls: "C2", mtow: 3.77, wind: 15, end: 41, ip: "IP55", bat: "TB30", fw: "v08.00", payloads: ["Integrated"], rtk: "built-in" },
  { m: "DJI Mavic 3T", cls: "C2", mtow: 0.92, wind: 12, end: 45, ip: "—", bat: "Mavic 3E", fw: "v10.00", payloads: ["Integrated"], rtk: "module" },
  { m: "Autel EVO Max 4T", cls: "C2", mtow: 1.6, wind: 12, end: 42, ip: "IP43", bat: "EVO Max", fw: "v2.1.6", payloads: ["Integrated"], rtk: "module" },
];
const DM_PAYLOADS = {
  "Zenmuse H30T": { t: "Thermal 1280×1024 · radiometric · zoom 34×", thermal: true },
  "Zenmuse H20T": { t: "Thermal 640×512 · radiometric · zoom 23×", thermal: true },
  "Zenmuse H20N": { t: "Night thermal 640×512 · radiometric", thermal: true },
  "Zenmuse P1": { t: "RGB 45 MP full-frame · photogrammetry", thermal: false },
  "Zenmuse L2": { t: "LiDAR + 20 MP RGB", thermal: false },
  "Integrated": { t: "Wide + zoom + thermal 640×512 radiometric", thermal: true },
};
const DM_OPCAT = ["Open · A2", "Open · A3", "Specific · STS-01", "Specific · STS-02", "Specific · PDRA-G01", "Specific · SORA authorisation"];
const DM_OWN = { own: "Own fleet", contractor: "Contractor", leased: "Leased" };
const dmModel = (m) => DM_MODELS.find(x => x.m === m) || DM_MODELS[0];
const dfDays = (d) => d ? Math.round((Date.parse(d + "T00:00:00Z") - Date.parse(DF_T() + "T00:00:00Z")) / 864e5) : null;

/* Readiness checklist — used in drawer, card and form preview */
function droneReadiness(dr) {
  const md = dmModel(dr.model), pl = DM_PAYLOADS[dr.payload] || {};
  const bats = window.droneBatteries ? window.droneBatteries(dr) : [];
  const live = bats.filter(b => b.status !== "retired");
  const ins = dfDays(dr.insurance), svc = dfDays(dr.nextMaint), cal = dr.calib ? -dfDays(dr.calib) : null;
  const c = [
    ["Registration", dr.regNo ? "ok" : "bad", dr.regNo || "Operator / UAS registration missing"],
    ["Insurance", ins == null ? "bad" : ins < 0 ? "bad" : ins < 30 ? "warn" : "ok", ins == null ? "No policy on file" : ins < 0 ? `Expired ${window.skyFmt.date(dr.insurance)}` : `Valid until ${window.skyFmt.date(dr.insurance)}${ins < 30 ? ` · ${ins} d` : ""}`],
    ["Service", svc == null ? "warn" : svc < 0 ? "bad" : svc < 14 ? "warn" : "ok", svc == null ? "No service date" : svc < 0 ? `Overdue since ${window.skyFmt.date(dr.nextMaint)}` : `Next ${window.skyFmt.date(dr.nextMaint)}${svc < 14 ? ` · ${svc} d` : ""}`],
    ["Firmware", !dr.firmware || dr.firmware === "—" ? "warn" : dr.firmware === md.fw ? "ok" : "warn", dr.firmware === md.fw ? `${dr.firmware} · current` : `${dr.firmware || "unknown"} · latest ${md.fw}`],
    ["Thermal calibration", !pl.thermal ? "warn" : cal == null ? "warn" : cal > 365 ? "bad" : cal > 300 ? "warn" : "ok", !pl.thermal ? "Payload is not thermal — cannot fly IEC 62446-3" : cal == null ? "No calibration record" : cal > 365 ? `Expired · last ${dr.calib}` : `Last ${dr.calib}`],
    ["Batteries", live.some(b => b.status === "swollen") ? "bad" : live.length < 2 ? "bad" : live.some(b => b.status === "degraded") ? "warn" : "ok", live.some(b => b.status === "swollen") ? "Swollen pack in set" : `${live.length} in service${live.some(b => b.status === "degraded") ? ` · ${live.filter(b => b.status === "degraded").length} degraded` : ""}`],
  ];
  const bad = c.filter(x => x[1] === "bad").length, warn = c.filter(x => x[1] === "warn").length;
  return { checks: c, bad, warn, st: ["maintenance", "grounded", "retired"].includes(dr.status) ? "bad" : bad ? "bad" : warn ? "warn" : "ok" };
}
function DroneReadyList({ dr, compact }) {
  const r = droneReadiness(dr);
  return <div className={`dm-ready ${compact ? "is-compact" : ""}`}>
    {r.checks.map(([k, s, t]) => <div key={k} className={`dm-chk dm-chk-${s}`}><Icon name={s === "ok" ? "check_circle" : "alert"} size={12}/><b>{k}</b><span>{t}</span></div>)}
  </div>;
}
function DroneReadyBadge({ dr }) {
  const r = droneReadiness(dr);
  const L = { ok: "Flight-ready", warn: `${r.warn} warning${r.warn > 1 ? "s" : ""}`, bad: r.bad ? `${r.bad} blocker${r.bad > 1 ? "s" : ""}` : "Not available" };
  return <span className={`dm-badge dm-badge-${r.st}`}><Icon name={r.st === "ok" ? "check_circle" : "alert"} size={10}/>{L[r.st]}</span>;
}

/* One-time enrichment of seed drones */
(function dmMigrate() {
  const R = window.resStore; if (!R || localStorage.getItem("skyops_drones_v2")) return;
  const A = window.skyAdd;
  R.set(x => ({ ...x, drones: x.drones.map((d, i) => d.regNo ? d : ({
    ...d, cls: dmModel(d.model).cls, ownership: d.owner === "Iberdrola O&M" ? "own" : "contractor",
    callsign: d.callsign || ["Falcão", "Lince", "Corvo", "Gaivota", "Milhafre"][i % 5],
    regNo: d.owner === "Iberdrola O&M" ? `PRT87gh${String(4021 + i * 37)}` : `ESP2kx${String(9180 + i * 11)}`,
    remoteId: `1581F${(d.serial || "").slice(-6)}RID`, opCat: d.model.includes("Mavic") ? "Open · A2" : "Specific · STS-01",
    insurer: d.owner === "Iberdrola O&M" ? "Allianz Aviation" : "Mapfre Global Risks", policy: `AV-${2026}-${String(10331 + i * 7)}`,
    purchased: A(-400 - i * 190), value: d.model.includes("Mavic") ? 6200 : d.model.includes("M300") ? 11800 : 14500,
    payloadSerial: `${(d.payload || "").replace(/\W/g, "").slice(-4).toUpperCase()}-${String(70212 + i * 13)}`, rtk: true,
    calib: i === 2 ? A(-380) : A(-60 - i * 40), lastService: A(-(90 - Math.max(1, dfDays(d.nextMaint) || 30))), svcDays: 90, svcHours: 100,
    batType: (d.batt.match(/^(TB\d+)/) || [0, dmModel(d.model).bat])[1], defaultPilot: ["T. Aragón", "M. Rivera", "T. Aragón", "L. Ferreira", "J. Castaño"][i % 5],
  })) }));
  localStorage.setItem("skyops_drones_v2", "1");
})();

/* Seed dates were authored for Oct 2026 — align fleet status dates to the app's "today" */
(function dmDates() {
  const R = window.resStore; if (!R || localStorage.getItem("skyops_dates_fleet_v1")) return;
  const sh = (d) => typeof d === "string" && /^2026-1[0-2]-/.test(d) ? window.skyAdd(-183, d) : d;
  R.set(x => ({ ...x, drones: x.drones.map(d => ({ ...d, nextMaint: d.nextMaint && d.nextMaint.startsWith("2026-10") ? sh(d.nextMaint) : d.nextMaint,
    reason: d.reason ? { ...d.reason, since: sh(d.reason.since), back: sh(d.reason.back) } : d.reason,
    log: (d.log || []).map(l => [sh(l[0]), ...l.slice(1)]) })) }));
  localStorage.setItem("skyops_dates_fleet_v1", "1");
})();

/* Add / edit / duplicate */
function DmField({ err, l, req, children, span, hint }) { return <label className={`field ${span ? "ni-span" : ""} ${err ? "dm-err" : ""}`}><span>{l}{req ? " *" : ""}{hint && <em className="dm-hint"> · {hint}</em>}</span>{children}{err && <em className="dm-err-t">{err}</em>}</label>; }
function DroneFormModal({ mode, dr, onClose, onSaved }) {
  const all = window.useRes();
  const T = DF_T(), A = window.skyAdd;
  const nextId = () => { let n = all.drones.length + 1, id; do { id = `SKY-D${String(n++).padStart(2, "0")}`; } while (all.drones.some(d => d.id === id)); return id; };
  const base = dr || {};
  const dup = mode === "duplicate";
  const md0 = dmModel(base.model || "DJI M350 RTK");
  const [f, setF] = uSDF(() => ({
    id: mode === "edit" ? base.id : nextId(), callsign: dup ? "" : base.callsign || "", model: md0.m, payload: base.payload || md0.payloads[0],
    serial: dup ? "" : base.serial && base.serial !== "—" ? base.serial : "", ownership: base.ownership || "own", owner: base.owner || "Iberdrola O&M", base: base.base || "Évora depot",
    purchased: dup ? T : base.purchased || T, value: base.value ?? 14500, payloadSerial: dup ? "" : base.payloadSerial || "", rtk: base.rtk ?? true, calib: dup ? T : base.calib || T,
    regNo: dup ? "" : base.regNo || "", remoteId: dup ? "" : base.remoteId || "", opCat: base.opCat || "Specific · STS-01", insurer: base.insurer || "", policy: dup ? "" : base.policy || "", insurance: base.insurance && base.insurance !== "—" ? base.insurance : A(365),
    hours: mode === "edit" ? base.hours || 0 : 0, flights: mode === "edit" ? base.flights || 0 : 0, firmware: base.firmware && base.firmware !== "—" ? base.firmware : md0.fw,
    lastService: mode === "edit" ? base.lastService || T : T, svcDays: base.svcDays || 90, svcHours: base.svcHours || 100, nextOverride: mode === "edit" && base.nextMaint && !base.lastService ? base.nextMaint : "",
    batType: base.batType || md0.bat, batCount: mode === "edit" ? (window.droneBatteries ? window.droneBatteries(base).filter(b => b.status !== "retired").length : 4) : 6,
    defaultPilot: base.defaultPilot || "", status: mode === "edit" ? base.status : "available", notes: dup ? "" : base.notes || "",
  }));
  const [sec, setSec] = uSDF("identity");
  const body = uRDF(null);
  const set = (k, v) => setF(x => ({ ...x, [k]: v }));
  const inp = (k, type) => (e) => set(k, type === "num" ? e.target.value === "" ? "" : +e.target.value : e.target.value);
  const md = dmModel(f.model), pl = DM_PAYLOADS[f.payload] || {};
  const pickModel = (m) => { const nm = dmModel(m); setF(x => ({ ...x, model: m, payload: nm.payloads.includes(x.payload) ? x.payload : nm.payloads[0], batType: nm.bat, firmware: x.firmware === dmModel(x.model).fw ? nm.fw : x.firmware })); };
  const nextMaint = f.nextOverride || A(+f.svcDays || 90, f.lastService || T);
  const bases = [...new Set(["Évora depot", "Murcia depot", "Algarve depot", "Zaragoza", ...all.drones.map(d => d.base)])];
  const pilots = all.people.filter(p => (p.skills || []).includes("Pilot"));
  const others = all.drones.filter(d => mode !== "edit" || d.id !== base.id);
  const errs = {
    id: !f.id.trim() ? "Required" : others.some(d => d.id === f.id.trim()) ? "ID already in use" : null,
    serial: !f.serial.trim() ? "Required" : others.some(d => d.serial === f.serial.trim()) ? `Serial already on ${others.find(d => d.serial === f.serial.trim()).id}` : null,
    owner: f.ownership !== "own" && !f.owner.trim() ? "Required" : null,
    insurance: f.insurance && f.insurance <= f.purchased && mode !== "edit" ? "Must be after purchase" : null,
    hours: f.hours < 0 || f.flights < 0 ? "Cannot be negative" : null,
    batCount: !(f.batCount >= 0 && f.batCount <= 24) ? "0–24" : null,
  };
  const errList = Object.entries(errs).filter(([, v]) => v);
  const preview = { ...base, ...f, nextMaint, batteries: mode === "edit" ? base.batteries : Array.from({ length: +f.batCount || 0 }).map((_, i) => ({ id: "x" + i, health: 100, cycles: 0, status: "ok" })) };
  const ready = droneReadiness(preview);
  const SECS = [["identity", "Identity & ownership", !errs.id && !errs.serial && !errs.owner], ["payload", "Payload & sensors", !!f.payloadSerial], ["regulatory", "Regulatory & insurance", !!f.regNo && !!f.insurer && !!f.policy], ["maintenance", "Maintenance & batteries", !errs.hours && !errs.batCount], ["assignment", "Assignment", true]];
  const jump = (id) => { setSec(id); const el = body.current?.querySelector(`[data-sec="${id}"]`); if (el) body.current.scrollTop = el.offsetTop - body.current.offsetTop - 8; };
  const onScroll = () => { const b = body.current; if (!b) return; let cur = SECS[0][0]; SECS.forEach(([id]) => { const el = b.querySelector(`[data-sec="${id}"]`); if (el && el.offsetTop - b.offsetTop - 40 <= b.scrollTop) cur = id; }); if (cur !== sec) setSec(cur); };

  const save = () => {
    if (errList.length) { jump(["id", "serial", "owner"].includes(errList[0][0]) ? "identity" : errList[0][0] === "insurance" ? "regulatory" : "maintenance"); return; }
    const rec = { ...f, id: f.id.trim(), serial: f.serial.trim(), owner: f.ownership === "own" ? "Iberdrola O&M" : f.owner.trim(), cls: md.cls, nextMaint, hours: +f.hours || 0, flights: +f.flights || 0, value: +f.value || 0,
      svcDays: +f.svcDays || 90, svcHours: +f.svcHours || 100, batt: `${f.batType} ×${f.batCount}` };
    delete rec.batCount;
    window.resStore.set(x => {
      if (mode === "edit") {
        const prev = x.drones.find(d => d.id === base.id);
        const changed = ["model", "payload", "serial", "base", "owner", "firmware", "insurance", "regNo", "opCat", "status", "defaultPilot"].filter(k => (prev[k] || "") !== (rec[k] || ""));
        let bats = prev.batteries;
        const cur = window.droneBatteries(prev), live = cur.filter(b => b.status !== "retired").length;
        if (+f.batCount !== live) bats = +f.batCount > live ? [...cur, ...Array.from({ length: +f.batCount - live }).map((_, i) => ({ id: `${f.batType}-${rec.id.slice(-2)}${String.fromCharCode(65 + cur.length + i)}`, cycles: 0, health: 100, last: T, status: "ok" }))] : cur.map((b, i) => i >= +f.batCount && b.status !== "retired" ? { ...b, status: "retired" } : b);
        const log = [[T, "edit", changed.length ? `Details edited · ${changed.join(", ")}` : "Details edited", "You"], ...(prev.log || [])];
        return { ...x, drones: x.drones.map(d => d.id === base.id ? { ...prev, ...rec, batteries: bats, log, reason: rec.status === "available" ? null : prev.reason } : d) };
      }
      const bats = Array.from({ length: +f.batCount || 0 }).map((_, i) => ({ id: `${f.batType}-${rec.id.slice(-2)}${String.fromCharCode(65 + i)}`, cycles: 0, health: 100, last: T, status: "ok" }));
      return { ...x, drones: [...x.drones, { ...rec, batteries: bats, log: [[T, "ok", dup ? `Registered · duplicated from ${base.id}` : "Registered in fleet", "You"]] }] };
    });
    dfToast(mode === "edit" ? `${rec.id} updated` : `${rec.id} added to fleet`);
    onSaved && onSaved(rec.id); onClose();
  };

  return (
    <div className="ni-scrim" onClick={onClose}><div className="ni-modal dm-modal" onClick={e => e.stopPropagation()} role="dialog">
      <div className="ni-hd"><div><div className="kicker">Fleet · {mode === "edit" ? base.id : dup ? `duplicate of ${base.id}` : "new drone"}</div><h3>{mode === "edit" ? "Edit drone" : dup ? "Duplicate drone" : "Add drone"}</h3></div><button className="ask-hd-btn" onClick={onClose}><Icon name="x" size={13}/></button></div>
      <div className="dm-wrap">
        <nav className="dm-nav">{SECS.map(([id, l, ok], i) => <button key={id} className={sec === id ? "on" : ""} onClick={() => jump(id)}><span className={`dm-nav-n ${ok ? "ok" : ""}`}>{ok ? <Icon name="check" size={10}/> : i + 1}</span>{l}</button>)}</nav>
        <div className="dm-body" ref={body} onScroll={onScroll}>
          <section data-sec="identity"><h4>Identity & ownership</h4><div className="ni-grid">
            <DmField err={errs.id} l="Fleet ID" req><input className="inp mono" value={f.id} onChange={inp("id")}/></DmField>
            <DmField err={errs.callsign} l="Callsign" hint="optional"><input className="inp" value={f.callsign} onChange={inp("callsign")} placeholder="e.g. Falcão"/></DmField>
            <DmField err={errs.model} l="Model" req><select className="sel" value={f.model} onChange={e => pickModel(e.target.value)}>{DM_MODELS.map(m => <option key={m.m}>{m.m}</option>)}</select></DmField>
            <DmField err={errs.serial} l="Airframe serial" req><input className="inp mono" value={f.serial} onChange={inp("serial")} placeholder="e.g. 1581F5BKD23S"/></DmField>
            <div className="field ni-span"><span>Ownership</span><div className="ps-seg">{Object.entries(DM_OWN).map(([k, l]) => <button key={k} className={f.ownership === k ? "on" : ""} onClick={() => setF(x => ({ ...x, ownership: k, owner: k === "own" ? "Iberdrola O&M" : x.owner === "Iberdrola O&M" ? "" : x.owner }))}>{l}</button>)}</div></div>
            {f.ownership !== "own" && <DmField err={errs.owner} l={f.ownership === "leased" ? "Lessor" : "Contractor company"} req><input className="inp" list="dm-owners" value={f.owner} onChange={inp("owner")}/><datalist id="dm-owners">{all.companies.map(c => <option key={c.id} value={c.name}/>)}</datalist></DmField>}
            <DmField err={errs.purchased} l={f.ownership === "leased" ? "Lease start" : "In service since"}><input className="inp" type="date" value={f.purchased} onChange={inp("purchased")}/></DmField>
            <DmField err={errs.value} l="Asset value (€)"><input className="inp mono" type="number" min="0" value={f.value} onChange={inp("value", "num")}/></DmField>
          </div></section>

          <section data-sec="payload"><h4>Payload & sensors</h4><div className="ni-grid">
            <DmField err={errs.payload} l="Payload" req><select className="sel" value={f.payload} onChange={inp("payload")}>{md.payloads.map(p => <option key={p}>{p}</option>)}</select></DmField>
            <DmField err={errs.payloadSerial} l="Payload serial"><input className="inp mono" value={f.payloadSerial} onChange={inp("payloadSerial")} placeholder={f.payload === "Integrated" ? "Same as airframe" : "e.g. H30T-70212"}/></DmField>
            <div className={`dm-pl ni-span ${pl.thermal ? "" : "is-warn"}`}><Icon name={pl.thermal ? "thermometer" : "alert"} size={13}/><span><b>{f.payload}</b> · {pl.t}{!pl.thermal && " — not valid for thermographic inspections (IEC TS 62446-3)"}</span></div>
            <DmField err={errs.calib} l="Last radiometric calibration" hint="every 12 months"><input className="inp" type="date" value={f.calib} disabled={!pl.thermal} onChange={inp("calib")}/></DmField>
            <label className="dm-tog"><input type="checkbox" checked={!!f.rtk} onChange={e => set("rtk", e.target.checked)}/><span><b>RTK positioning</b><em>{md.rtk === "built-in" ? "Built-in" : "Requires RTK module"} · cm-level geotagging</em></span></label>
          </div></section>

          <section data-sec="regulatory"><h4>Regulatory & insurance</h4><div className="ni-grid">
            <div className="field"><span>EASA class</span><div className="inp dm-ro">{md.cls}<em>from model · MTOW {md.mtow} kg</em></div></div>
            <DmField err={errs.opCat} l="Operational category"><select className="sel" value={f.opCat} onChange={inp("opCat")}>{DM_OPCAT.map(o => <option key={o}>{o}</option>)}</select></DmField>
            <DmField err={errs.regNo} l="UAS / operator registration"><input className="inp mono" value={f.regNo} onChange={inp("regNo")} placeholder="e.g. PRT87gh4021"/></DmField>
            <DmField err={errs.remoteId} l="Remote ID"><input className="inp mono" value={f.remoteId} onChange={inp("remoteId")} placeholder="Broadcast serial"/></DmField>
            <DmField err={errs.insurer} l="Insurer"><input className="inp" value={f.insurer} onChange={inp("insurer")} placeholder="e.g. Allianz Aviation"/></DmField>
            <DmField err={errs.policy} l="Policy number"><input className="inp mono" value={f.policy} onChange={inp("policy")}/></DmField>
            <DmField err={errs.insurance} l="Insurance valid until"><input className="inp" type="date" value={f.insurance} onChange={inp("insurance")}/></DmField>
          </div></section>

          <section data-sec="maintenance"><h4>Maintenance & batteries</h4><div className="ni-grid">
            <DmField err={errs.hours} l="Flight hours"><input className="inp mono" type="number" min="0" value={f.hours} onChange={inp("hours", "num")}/></DmField>
            <DmField err={errs.flights} l="Flights"><input className="inp mono" type="number" min="0" value={f.flights} onChange={inp("flights", "num")}/></DmField>
            <DmField err={errs.firmware} l="Firmware" hint={`latest ${md.fw}`}><div className="dm-inline"><input className="inp mono" value={f.firmware} onChange={inp("firmware")}/>{f.firmware !== md.fw && <button className="btn btn-ghost btn-xs" onClick={() => set("firmware", md.fw)}>Set {md.fw}</button>}</div></DmField>
            <DmField err={errs.lastService} l="Last service"><input className="inp" type="date" value={f.lastService} onChange={e => setF(x => ({ ...x, lastService: e.target.value, nextOverride: "" }))}/></DmField>
            <DmField err={errs.svcDays} l="Service interval" hint="days · or flight hours, first reached"><div className="dm-inline"><input className="inp mono" type="number" min="7" value={f.svcDays} onChange={e => setF(x => ({ ...x, svcDays: e.target.value === "" ? "" : +e.target.value, nextOverride: "" }))}/><span className="sec">d</span><input className="inp mono" type="number" min="10" value={f.svcHours} onChange={inp("svcHours", "num")}/><span className="sec">h</span></div></DmField>
            <DmField err={errs.nextMaint} l="Next service" hint={f.nextOverride ? "manual" : "auto"}><div className="dm-inline"><input className="inp" type="date" value={nextMaint} onChange={e => set("nextOverride", e.target.value)}/>{f.nextOverride && <button className="btn btn-ghost btn-xs" onClick={() => set("nextOverride", "")}>Auto</button>}</div></DmField>
            <DmField err={errs.batType} l="Battery type"><input className="inp mono" value={f.batType} onChange={inp("batType")}/></DmField>
            <DmField err={errs.batCount} l={mode === "edit" ? "Batteries in service" : "Battery packs"} hint={mode === "edit" ? "lowering retires packs" : "created at 100 %"}><input className="inp mono" type="number" min="0" max="24" value={f.batCount} onChange={inp("batCount", "num")}/></DmField>
          </div></section>

          <section data-sec="assignment"><h4>Assignment</h4><div className="ni-grid">
            <DmField err={errs.base} l="Home base"><input className="inp" list="dm-bases" value={f.base} onChange={inp("base")}/><datalist id="dm-bases">{bases.map(b => <option key={b} value={b}/>)}</datalist></DmField>
            <DmField err={errs.defaultPilot} l="Default pilot"><select className="sel" value={f.defaultPilot} onChange={inp("defaultPilot")}><option value="">— none —</option>{pilots.map(p => { const c = window.crCompliance ? window.crCompliance(p) : { ok: true }; return <option key={p.id} value={p.name}>{p.name}{c.ok ? "" : " · not cleared"}</option>; })}</select></DmField>
            {mode !== "edit" && <DmField err={errs.status} l="Initial status"><select className="sel" value={f.status} onChange={inp("status")}>{["available", "maintenance", "grounded"].map(s => <option key={s} value={s}>{window.DR_STATUS[s]}</option>)}</select></DmField>}
            <DmField err={errs.notes} l="Notes" span><textarea className="inp" rows={3} style={{ height: "auto", resize: "vertical" }} value={f.notes} onChange={inp("notes")} placeholder="Modifications, known issues, accessories…"/></DmField>
          </div></section>
        </div>

        <aside className="dm-side">
          <div className="dm-spec"><div className="caps">{md.m}</div>
            {[["Class", md.cls], ["MTOW", `${md.mtow} kg`], ["Max wind", `${md.wind} m/s`], ["Endurance", `${md.end} min`], ["Ingress", md.ip], ["RTK", md.rtk]].map(([a, b]) => <div key={a} className="ps-kv"><span>{a}</span><b className="mono">{b}</b></div>)}
          </div>
          <div className="dm-side-ready"><div className="dm-side-hd"><span className="caps">Readiness preview</span><span className={`dm-badge dm-badge-${ready.st}`}>{ready.st === "ok" ? "Flight-ready" : ready.bad ? `${ready.bad} blocker${ready.bad > 1 ? "s" : ""}` : `${ready.warn} warning${ready.warn > 1 ? "s" : ""}`}</span></div>
            <DroneReadyList dr={preview} compact/></div>
        </aside>
      </div>
      <div className="ni-ft">
        {errList.length > 0 && <span className="cr-err">{errList.length} field{errList.length > 1 ? "s" : ""} need attention</span>}
        <span className="grow"/>
        <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
        <button className="btn btn-primary" disabled={errList.length > 0} onClick={save}><Icon name="check" size={12}/>{mode === "edit" ? "Save changes" : "Add to fleet"}</button>
      </div>
    </div></div>
  );
}

/* Retire or delete */
function DroneDeleteModal({ dr, wos, insps, onClose, onDone }) {
  const [opt, setOpt] = uSDF(dr.flights > 0 || insps.length ? "retire" : "delete");
  const [reason, setReason] = uSDF("End of service life");
  const [note, setNote] = uSDF("");
  const [typed, setTyped] = uSDF("");
  const T = DF_T();
  const go = () => {
    if (opt === "retire") {
      window.resStore.set(x => ({ ...x, drones: x.drones.map(d => d.id === dr.id ? { ...d, status: "retired", retired: T, reason: { cat: reason, text: note || reason, since: T, back: "", by: "You" }, log: [[T, "maint", `Retired · ${reason}${note ? ": " + note : ""}`, "You"], ...(d.log || [])] } : d) }));
      dfToast(`${dr.id} retired — history kept`);
    } else {
      window.resStore.set(x => ({ ...x, drones: x.drones.filter(d => d.id !== dr.id) }));
      dfToast(`${dr.id} deleted`);
    }
    onDone(); onClose();
  };
  return (
    <div className="ni-scrim" onClick={onClose}><div className="ni-modal" onClick={e => e.stopPropagation()} role="dialog" style={{ width: "min(560px,100%)" }}>
      <div className="ni-hd"><div><div className="kicker">Fleet · {dr.id}</div><h3>Remove {dr.model}</h3></div><button className="ask-hd-btn" onClick={onClose}><Icon name="x" size={13}/></button></div>
      <div className="ni-body">
        {(wos.length > 0 || insps.length > 0 || dr.flights > 0) && <div className="dm-impact"><Icon name="alert" size={12}/><span>Linked to <b>{dr.flights.toLocaleString()} flights</b>{insps.length ? <>, <b>{insps.length} inspection{insps.length > 1 ? "s" : ""}</b></> : null}{wos.length ? <> and <b>{wos.length} open work order{wos.length > 1 ? "s" : ""}</b></> : null}. Retiring keeps this traceability for reports and warranty evidence.</span></div>}
        <div className="dm-opts">
          <button className={`dm-opt ${opt === "retire" ? "on" : ""}`} onClick={() => setOpt("retire")}><Icon name="folder" size={14}/><b>Retire</b><span>Hide from assignment. Keeps logs, flights and inspection links. Reversible.</span></button>
          <button className={`dm-opt dm-opt-danger ${opt === "delete" ? "on" : ""}`} onClick={() => setOpt("delete")}><Icon name="trash" size={14}/><b>Delete permanently</b><span>Removes the record. Use only for entries created by mistake.</span></button>
        </div>
        {opt === "retire" ? <div className="ni-grid" style={{ marginTop: 12 }}>
          <label className="field"><span>Reason</span><select className="sel" value={reason} onChange={e => setReason(e.target.value)}>{["End of service life", "Crash / write-off", "Sold", "Returned to lessor", "Contract ended", "Replaced by newer model"].map(r => <option key={r}>{r}</option>)}</select></label>
          <label className="field ni-span"><span>Note</span><input className="inp" value={note} onChange={e => setNote(e.target.value)} placeholder="Optional details"/></label>
        </div> : <label className="field" style={{ marginTop: 12 }}><span>Type <b className="mono">{dr.id}</b> to confirm</span><input className="inp mono" value={typed} onChange={e => setTyped(e.target.value)} autoFocus/></label>}
      </div>
      <div className="ni-ft"><span className="grow"/><button className="btn btn-ghost" onClick={onClose}>Cancel</button>
        <button className={`btn ${opt === "delete" ? "cr-btn-danger" : "btn-primary"}`} disabled={opt === "delete" && typed.trim() !== dr.id} onClick={go}><Icon name={opt === "delete" ? "trash" : "check"} size={12}/>{opt === "delete" ? "Delete drone" : "Retire drone"}</button></div>
    </div></div>
  );
}

Object.assign(window, { DM_MODELS, DM_PAYLOADS, DM_OWN, dmModel, droneReadiness, DroneReadyList, DroneReadyBadge, DroneFormModal, DroneDeleteModal });
