/* SkyOps — shared actions: real ZIP (store), CSV, clipboard, signed links, workspace export. */

const AC_CRC = (() => { const t = new Uint32Array(256); for (let n = 0; n < 256; n++) { let c = n; for (let k = 0; k < 8; k++) c = c & 1 ? 0xEDB88320 ^ (c >>> 1) : c >>> 1; t[n] = c >>> 0; } return t; })();
function acCrc(buf) { let c = 0xFFFFFFFF; for (let i = 0; i < buf.length; i++) c = AC_CRC[(c ^ buf[i]) & 0xFF] ^ (c >>> 8); return (c ^ 0xFFFFFFFF) >>> 0; }
/* files: [{ name, data: string | Uint8Array }] → Blob (application/zip, no compression) */
function skyZip(files) {
  const enc = new TextEncoder(), parts = [], central = []; let off = 0;
  const u16 = (v) => [v & 255, (v >> 8) & 255], u32 = (v) => [v & 255, (v >> 8) & 255, (v >> 16) & 255, (v >>> 24) & 255];
  files.forEach(f => {
    const name = enc.encode(f.name), data = typeof f.data === "string" ? enc.encode(f.data) : f.data, crc = acCrc(data);
    const head = [...u32(0x04034b50), ...u16(20), ...u16(0x0800), ...u16(0), ...u16(0), ...u16(0x21), ...u32(crc), ...u32(data.length), ...u32(data.length), ...u16(name.length), ...u16(0)];
    parts.push(new Uint8Array(head), name, data);
    central.push(new Uint8Array([...u32(0x02014b50), ...u16(20), ...u16(20), ...u16(0x0800), ...u16(0), ...u16(0), ...u16(0x21), ...u32(crc), ...u32(data.length), ...u32(data.length), ...u16(name.length), ...u16(0), ...u16(0), ...u16(0), ...u16(0), ...u32(0), ...u32(off)]), name);
    off += head.length + name.length + data.length;
  });
  const cdSize = central.reduce((a, p) => a + p.length, 0);
  const end = new Uint8Array([...u32(0x06054b50), ...u16(0), ...u16(0), ...u16(files.length), ...u16(files.length), ...u32(cdSize), ...u32(off), ...u16(0)]);
  return new Blob([...parts, ...central, end], { type: "application/zip" });
}
const skyCsv = (rows) => rows.map(r => r.map(v => { const s = String(v ?? ""); return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s; }).join(",")).join("\n");
function skyCopy(text, msg) {
  const done = () => window.skyToast && window.skyToast(msg || "Copied to clipboard");
  try { navigator.clipboard.writeText(text).then(done, () => { acFallbackCopy(text); done(); }); } catch { acFallbackCopy(text); done(); }
}
function acFallbackCopy(t) { const a = document.createElement("textarea"); a.value = t; a.style.position = "fixed"; a.style.opacity = "0"; document.body.appendChild(a); a.select(); try { document.execCommand("copy"); } catch {} a.remove(); }
const skySignedUrl = (scope, path) => `https://files.skyops.io/${scope}/${path}?sig=${Math.random().toString(36).slice(2, 10)}&exp=7d`;

/* Workspace export (Settings → Data) and portfolio/site CSVs */
function skySitesCsv() {
  return skyCsv([["site_id", "name", "region", "capacity_mw", "modules", "health", "critical", "warnings", "alerts", "last_inspection", "next_inspection"],
    ...(window.SITES || []).map(s => [s.id, s.name, s.region, s.capacity_mw, s.panels, s.health, s.criticals, s.warnings, s.alerts, s.lastInspection || "", s.nextInspection || ""])]);
}
function skyWorkspaceExport() {
  const I = window.INSPECTIONS || [], D = window.DETECTIONS || [], W = window.woStore?.list || [], R = window.resStore?.data || { people: [], drones: [] };
  const files = [
    { name: "README.txt", data: `SkyOps workspace export\nTenant: ${localStorage.getItem("skyops_tenant") || "Iberdrola Renovables"}\nGenerated: ${window.SKY_TODAY}\nCRS: EPSG:4326 · units SI (°C, m, kWh, EUR)\n` },
    { name: "sites.csv", data: skySitesCsv() },
    { name: "inspections.csv", data: skyCsv([["mic_id", "site_id", "cycle", "status", "lead", "drone", "coverage_pct", "detections", "critical"], ...I.map(i => [i.id, i.siteId, i.cycle, i.status, i.lead, i.drone, i.coverage, i.detections, i.critical])]) },
    { name: "detections.csv", data: skyCsv([["obs_id", "type", "severity", "string", "delta_t_c", "temporal", "review"], ...D.map(d => [d.id, d.label, d.severity, d.string, d.dT, d.temporal, d.review])]) },
    { name: "work_orders.csv", data: skyCsv([["wo_id", "site_id", "title", "type", "priority", "status", "assignee", "due", "revenue_at_risk_eur", "cost_eur"], ...W.map(w => [w.id, w.siteId, w.title, w.type, w.prio, w.status, w.assignee, w.due, w.rar, w.cost])]) },
    { name: "crew_certifications.csv", data: skyCsv([["person", "role", "certificate", "expires"], ...R.people.flatMap(p => (p.certs || []).map(c => [p.name, p.role, c[0], c[1]]))]) },
    { name: "fleet.csv", data: skyCsv([["drone_id", "model", "payload", "serial", "status", "hours", "flights", "next_service", "insurance_until"], ...R.drones.map(d => [d.id, d.model, d.payload, d.serial, d.status, d.hours, d.flights, d.nextMaint, d.insurance])]) },
  ];
  window.skyDownload(`skyops-export-${window.SKY_TODAY}.zip`, skyZip(files));
  window.skyToast && window.skyToast(`Workspace export downloaded · ${files.length} files`);
}

/* Integration configure / connect */
function IntegrationModal({ name, desc, connected, onClose, onChange }) {
  const [f, setF] = React.useState({ url: `https://api.${name.split(" · ").pop().toLowerCase().replace(/\s+/g, "")}.com/v1`, key: connected ? "sk_live_••••••••••••4f2a" : "", every: "5", sites: "all" });
  const [test, setTest] = React.useState(null);
  const run = () => { setTest("running"); setTimeout(() => setTest(f.key.trim() ? "ok" : "fail"), 900); };
  return <div className="ni-scrim" onClick={onClose}><div className="ni-modal" role="dialog" onClick={e => e.stopPropagation()} style={{ width: "min(540px,100%)" }}>
    <div className="ni-hd"><div><div className="kicker">Integration</div><h3>{connected ? "Configure" : "Connect"} {name}</h3><span className="sec">{desc}</span></div><button className="ask-hd-btn" onClick={onClose}><Icon name="x" size={13}/></button></div>
    <div className="ni-body"><div className="ni-grid">
      <label className="field ni-span"><span>Endpoint</span><input className="inp mono" value={f.url} onChange={e => setF(x => ({ ...x, url: e.target.value }))}/></label>
      <label className="field ni-span"><span>API key / client secret</span><input className="inp mono" value={f.key} onChange={e => { setTest(null); setF(x => ({ ...x, key: e.target.value })); }} placeholder="Paste key"/></label>
      <label className="field"><span>Sync every</span><select className="sel" value={f.every} onChange={e => setF(x => ({ ...x, every: e.target.value }))}><option value="1">1 min</option><option value="5">5 min</option><option value="60">1 hour</option><option value="1440">daily</option></select></label>
      <label className="field"><span>Sites</span><select className="sel" value={f.sites} onChange={e => setF(x => ({ ...x, sites: e.target.value }))}><option value="all">All sites</option>{(window.SITES || []).map(s => <option key={s.id} value={s.id}>{s.name}</option>)}</select></label>
    </div>
    {test && <div className={`ac-test ac-test-${test}`}><Icon name={test === "ok" ? "check_circle" : test === "fail" ? "alert" : "refresh"} size={12}/>{test === "running" ? "Testing connection…" : test === "ok" ? "Connection OK · 212 ms · credentials valid" : "Authentication failed — check the key"}</div>}
    </div>
    <div className="ni-ft">{connected && <button className="btn btn-ghost cr-del-btn" onClick={() => { onChange("disconnected"); onClose(); window.skyToast(`${name} disconnected`); }}>Disconnect</button>}<span className="grow"/>
      <button className="btn btn-secondary" onClick={run} disabled={test === "running"}>Test connection</button>
      <button className="btn btn-primary" disabled={!f.key.trim()} onClick={() => { onChange("connected"); onClose(); window.skyToast(`${name} ${connected ? "updated" : "connected"}`); }}><Icon name="check" size={12}/>{connected ? "Save" : "Connect"}</button></div>
  </div></div>;
}

Object.assign(window, { skyZip, skyCsv, skyCopy, skySignedUrl, skySitesCsv, skyWorkspaceExport, IntegrationModal });
