/* SkyOps — Stage 6 · Files
   File explorer for all artefacts produced by this inspection.
   Tree left · table right · preview rail. Multi-select → download / copy link. */

const { useState: useStateSF, useMemo: useMemoSF } = React;

/* Files for this inspection — deterministic from mic id */
function buildFilesFor(mic) {
  const id = mic.id;
  return [
    { path: "raw/rgb", kind: "dir", children: 4821, size: 84_000_000_000 },
    { path: "raw/rgb/DJI_0001.JPG", kind: "img", size: 18_400_000, gen: mic.startedAt, crs: "EPSG:4326" },
    { path: "raw/rgb/DJI_0002.JPG", kind: "img", size: 18_200_000, gen: mic.startedAt, crs: "EPSG:4326" },
    { path: "raw/rgb/DJI_0003.JPG", kind: "img", size: 17_900_000, gen: mic.startedAt, crs: "EPSG:4326" },
    { path: "raw/thermal", kind: "dir", children: 2110, size: 12_000_000_000 },
    { path: "raw/thermal/DJI_0001_T.R-JPEG", kind: "thermal", size: 4_120_000, gen: mic.startedAt },
    { path: "raw/thermal/DJI_0002_T.R-JPEG", kind: "thermal", size: 4_200_000, gen: mic.startedAt },
    { path: "raw/flightlog.srt", kind: "log", size: 2_140_000, gen: mic.startedAt },

    { path: "products/orthomosaic.tif", kind: "raster", size: 2_400_000_000, gen: mic.startedAt, crs: "EPSG:25829", fmt: "COG · RGB · 2 cm/px" },
    { path: "products/orthomosaic_thermal.tif", kind: "raster", size: 820_000_000, gen: mic.startedAt, crs: "EPSG:25829", fmt: "COG · LWIR · 8 cm/px" },
    { path: "products/dsm.tif", kind: "raster", size: 1_100_000_000, gen: mic.startedAt, crs: "EPSG:25829", fmt: "COG · Float32" },
    { path: "products/dtm.tif", kind: "raster", size: 980_000_000, gen: mic.startedAt, crs: "EPSG:25829", fmt: "COG · Float32" },
    { path: "products/pointcloud.laz", kind: "cloud", size: 4_200_000_000, gen: mic.startedAt, crs: "EPSG:25829", fmt: "LAZ 1.4 · 68M pts" },
    { path: "products/mesh.obj", kind: "mesh", size: 480_000_000, gen: mic.startedAt, fmt: "OBJ · 12.2M tri" },
    { path: "products/mesh.mtl", kind: "mesh", size: 8_400 },
    { path: "products/textures", kind: "dir", children: 42, size: 200_000_000 },
    { path: "products/splat.ksplat", kind: "splat", size: 1_800_000_000, gen: mic.startedAt, fmt: "3D Gaussian Splat · 4.1M splats" },

    { path: "reports/detections.geojson", kind: "vector", size: 3_200_000, gen: mic.startedAt, crs: "EPSG:4326", fmt: `${mic.detections || 0} features` },
    { path: "reports/detections.shp", kind: "vector", size: 2_800_000, gen: mic.startedAt, crs: "EPSG:25829" },
    { path: "reports/qc_report.pdf", kind: "doc", size: 1_420_000, gen: mic.startedAt, fmt: "42 pages" },
    { path: `reports/${id}.pdf`, kind: "doc", size: 4_820_000, gen: mic.startedAt, fmt: "Client report · 42 pages" },

    { path: "logs/pipeline.log", kind: "log", size: 1_240_000, gen: mic.startedAt, fmt: "14,420 lines" },
    { path: "logs/exif_catalog.csv", kind: "csv", size: 3_100_000, gen: mic.startedAt, fmt: `${mic.images || 0} rows` },
    { path: "logs/sortie_manifest.json", kind: "json", size: 84_200, gen: mic.startedAt },
  ];
}

const KIND_ICON = {
  dir: "folder", img: "image", thermal: "thermometer", raster: "map", cloud: "layers",
  mesh: "cube", splat: "sparkles", vector: "pin", doc: "file", log: "terminal",
  csv: "grid", json: "terminal",
};
const KIND_COLOR = {
  dir: "var(--fg-secondary)", img: "#60a5fa", thermal: "#f87171",
  raster: "#22d3ee", cloud: "#a78bfa", mesh: "#34d399", splat: "#f472b6",
  vector: "#fbbf24", doc: "#e2e8f0", log: "var(--fg-muted)",
  csv: "var(--fg-muted)", json: "var(--fg-muted)",
};

function humanSize(b) {
  if (!b) return "—";
  if (b < 1024) return `${b} B`;
  if (b < 1024**2) return `${(b/1024).toFixed(1)} KB`;
  if (b < 1024**3) return `${(b/1024**2).toFixed(1)} MB`;
  return `${(b/1024**3).toFixed(2)} GB`;
}

function StageFiles({ mic, site, setStage }) {
  const allFiles = useMemoSF(() => buildFilesFor(mic), [mic.id]);
  const [curPath, setCurPath] = useStateSF("products");
  const [sel, setSel] = useStateSF(new Set());
  const [filter, setFilter] = useStateSF("all");
  const [preview, setPreview] = useStateSF(null);

  const tree = useMemoSF(() => {
    const folders = { raw: 0, "raw/rgb": 0, "raw/thermal": 0, products: 0, "products/textures": 0, reports: 0, logs: 0 };
    let total = 0, totalCount = 0;
    allFiles.forEach(f => {
      const parts = f.path.split("/");
      totalCount += f.kind === "dir" ? (f.children || 0) : 1;
      total += f.size || 0;
      for (let i = 1; i <= parts.length - 1; i++) {
        const p = parts.slice(0, i).join("/");
        if (folders[p] != null) folders[p] += f.kind === "dir" ? (f.children || 0) : 1;
      }
    });
    return { folders, total, totalCount };
  }, [allFiles]);

  const visibleFiles = useMemoSF(() => {
    return allFiles.filter(f => {
      if (f.kind === "dir") return false;
      if (!f.path.startsWith(curPath + "/") && curPath !== "all") return false;
      if (filter === "all") return true;
      if (filter === "rasters") return ["raster", "img"].includes(f.kind);
      if (filter === "vectors") return f.kind === "vector";
      if (filter === "3d") return ["mesh","cloud","splat"].includes(f.kind);
      if (filter === "reports") return f.kind === "doc";
      if (filter === "logs") return ["log","csv","json"].includes(f.kind);
      return true;
    });
  }, [allFiles, curPath, filter]);

  const selSize = useMemoSF(() => {
    let s = 0;
    sel.forEach(p => {
      const f = allFiles.find(x => x.path === p);
      if (f) s += f.size || 0;
    });
    return s;
  }, [sel, allFiles]);

  const toggleSel = (p) => {
    setSel(prev => {
      const n = new Set(prev);
      if (n.has(p)) n.delete(p); else n.add(p);
      return n;
    });
  };

  const selectAll = () => {
    setSel(new Set(visibleFiles.map(f => f.path)));
  };

  const TREE = [
    { path: "all", label: "All files", icon: "folder" },
    { path: "raw", label: "raw", icon: "folder", sub: [
      { path: "raw/rgb", label: "rgb", icon: "image" },
      { path: "raw/thermal", label: "thermal", icon: "thermometer" },
    ]},
    { path: "products", label: "products", icon: "folder" },
    { path: "reports", label: "reports", icon: "file" },
    { path: "logs", label: "logs", icon: "terminal" },
  ];

  return (
    <div className="ws-stage ws-stage-files">
      <div className="ws-stage-hd">
        <div className="title">
          <div className="kicker">Stage 6 · Files</div>
          <h1>Deliverables</h1>
          <div className="sub">
            All artefacts from this inspection · <span className="mono">{humanSize(tree.total)}</span>
            {" · "}<span className="mono">{tree.totalCount.toLocaleString()}</span> files
          </div>
        </div>
        <div className="actions">
          <button className="btn btn-secondary btn-xs" onClick={() => setStage("report")}>
            <Icon name="file" size={11}/> Open report
          </button>
          <button className="btn btn-secondary btn-xs">
            <Icon name="share" size={11}/> Share folder
          </button>
        </div>
      </div>

      <div className="fx-wrap">
        {/* Tree */}
        <aside className="fx-tree card ws-card">
          <div className="fx-tree-hd">
            <span className="caps">Folders</span>
            <span className="mono fx-tree-root">{mic.id}</span>
          </div>
          <div className="fx-tree-nav">
            {TREE.map(node => (
              <React.Fragment key={node.path}>
                <button className={`fx-tree-it ${curPath === node.path ? "is-on" : ""}`}
                        onClick={() => setCurPath(node.path)}>
                  <Icon name={node.icon} size={12}/>
                  <span>{node.label}</span>
                  {node.path !== "all" && tree.folders[node.path] != null && (
                    <span className="fx-tree-count mono">{tree.folders[node.path]}</span>
                  )}
                </button>
                {node.sub && node.sub.map(s => (
                  <button key={s.path} className={`fx-tree-it is-sub ${curPath === s.path ? "is-on" : ""}`}
                          onClick={() => setCurPath(s.path)}>
                    <Icon name={s.icon} size={11}/>
                    <span>{s.label}</span>
                    {tree.folders[s.path] != null && (
                      <span className="fx-tree-count mono">{tree.folders[s.path]}</span>
                    )}
                  </button>
                ))}
              </React.Fragment>
            ))}
          </div>

          <div className="fx-tree-foot">
            <div className="caps">Tips</div>
            <p>Select files to download as a zip. Click a row to preview.</p>
          </div>
        </aside>

        {/* Table */}
        <div className="fx-main card ws-card">
          <div className="fx-toolbar">
            <div className="fx-bc">
              <Icon name="folder" size={12}/>
              <span className="mono">{mic.id}</span>
              {curPath !== "all" && curPath.split("/").map((p, i, arr) => (
                <React.Fragment key={i}>
                  <span className="fx-bc-sep">/</span>
                  <span className={i === arr.length - 1 ? "fx-bc-cur" : ""}>{p}</span>
                </React.Fragment>
              ))}
            </div>
            <span className="grow"/>
            <div className="seg">
              {[
                ["all","All"],["rasters","Rasters"],["vectors","Vectors"],
                ["3d","3D"],["reports","Reports"],["logs","Logs"],
              ].map(([v,l]) => (
                <button key={v} className={filter === v ? "on" : ""} onClick={() => setFilter(v)}>{l}</button>
              ))}
            </div>
          </div>

          <div className="fx-table-wrap">
            <table className="fx-table">
              <thead>
                <tr>
                  <th style={{ width: 28 }}>
                    <input type="checkbox"
                           checked={visibleFiles.length > 0 && visibleFiles.every(f => sel.has(f.path))}
                           onChange={(e) => e.target.checked ? selectAll() : setSel(new Set())}/>
                  </th>
                  <th>Name</th>
                  <th style={{ width: 120 }}>Kind</th>
                  <th style={{ width: 180 }}>Format</th>
                  <th style={{ width: 100 }}>CRS</th>
                  <th style={{ width: 100, textAlign: "right" }}>Size</th>
                  <th style={{ width: 60 }}></th>
                </tr>
              </thead>
              <tbody>
                {visibleFiles.map(f => {
                  const name = f.path.split("/").pop();
                  const isSel = sel.has(f.path);
                  return (
                    <tr key={f.path}
                        className={`${isSel ? "is-sel" : ""} ${preview?.path === f.path ? "is-preview" : ""}`}
                        onClick={() => setPreview(f)}>
                      <td onClick={(e) => e.stopPropagation()}>
                        <input type="checkbox" checked={isSel} onChange={() => toggleSel(f.path)}/>
                      </td>
                      <td>
                        <div className="fx-name">
                          <Icon name={KIND_ICON[f.kind] || "file"} size={13} style={{ color: KIND_COLOR[f.kind] || "var(--fg-muted)" }}/>
                          <span className="fx-name-lbl mono">{name}</span>
                        </div>
                      </td>
                      <td className="sec" style={{ fontSize: 11 }}>{f.kind}</td>
                      <td className="sec mono" style={{ fontSize: 11 }}>{f.fmt || "—"}</td>
                      <td className="sec mono" style={{ fontSize: 11 }}>{f.crs || "—"}</td>
                      <td className="mono num" style={{ textAlign: "right", fontSize: 11 }}>{humanSize(f.size)}</td>
                      <td style={{ textAlign: "right" }}>
                        <button className="fx-dl" title="Download" onClick={(e) => e.stopPropagation()}>
                          <Icon name="download" size={11}/>
                        </button>
                      </td>
                    </tr>
                  );
                })}
                {visibleFiles.length === 0 && (
                  <tr><td colSpan="7" style={{ textAlign: "center", padding: 32, color: "var(--fg-muted)" }}>
                    No files here.
                  </td></tr>
                )}
              </tbody>
            </table>
          </div>

          {sel.size > 0 && (
            <div className="fx-selbar">
              <span className="mono">{sel.size} selected · {humanSize(selSize)}</span>
              <span className="grow"/>
              <button className="btn btn-ghost btn-xs" onClick={() => setSel(new Set())}>Clear</button>
              <button className="btn btn-secondary btn-xs"><Icon name="share" size={11}/>Copy links</button>
              <button className="btn btn-primary btn-xs"><Icon name="download" size={11}/>Download zip</button>
            </div>
          )}
        </div>

        {/* Preview */}
        <aside className="fx-preview card ws-card">
          {preview ? (
            <FilePreview file={preview} mic={mic}/>
          ) : (
            <div className="fx-preview-empty">
              <Icon name="file" size={22}/>
              <p>Click a file to preview.</p>
              <p className="sec">Rasters show thumbnails, point clouds show mini-viewer, reports render the cover.</p>
            </div>
          )}
        </aside>
      </div>
    </div>
  );
}

function FilePreview({ file, mic }) {
  const name = file.path.split("/").pop();
  return (
    <>
      <div className="fx-prev-hd">
        <Icon name={KIND_ICON[file.kind] || "file"} size={14} style={{ color: KIND_COLOR[file.kind] }}/>
        <span className="mono fx-prev-name">{name}</span>
      </div>
      <div className="fx-prev-body">
        {file.kind === "raster" && file.path.includes("thermal") && <div className="thermal-ph" style={{ aspectRatio: "4/3" }}/>}
        {file.kind === "raster" && !file.path.includes("thermal") && !file.path.includes("dsm") && !file.path.includes("dtm") && <div className="rgb-ph" style={{ aspectRatio: "4/3" }}/>}
        {file.kind === "raster" && (file.path.includes("dsm") || file.path.includes("dtm")) && (
          <div style={{ aspectRatio: "4/3", background: "linear-gradient(135deg,#1e3a5f,#7c3aed,#be185d,#f59e0b)", borderRadius: 6 }}/>
        )}
        {file.kind === "cloud" && (
          <div style={{ aspectRatio: "4/3", background: "#0a0e1a", position: "relative", borderRadius: 6, overflow: "hidden" }}>
            <svg width="100%" height="100%" viewBox="0 0 200 150">
              {Array.from({length: 300}).map((_, i) => {
                const x = (i*37)%200, y = ((i*71)%150), o = 0.3 + (i*13)%70/100;
                return <circle key={i} cx={x} cy={y} r="0.8" fill={`rgba(167,139,250,${o})`}/>;
              })}
            </svg>
          </div>
        )}
        {file.kind === "mesh" && (
          <div style={{ aspectRatio: "4/3", background: "#0a0e1a", display:"grid", placeItems:"center", borderRadius: 6 }}>
            <Icon name="cube" size={48} style={{ color: "#34d399", opacity: 0.5 }}/>
          </div>
        )}
        {file.kind === "splat" && (
          <div style={{ aspectRatio: "4/3", background: "radial-gradient(ellipse at center, #be185d 0%, #0a0e1a 70%)", borderRadius: 6 }}/>
        )}
        {file.kind === "doc" && (
          <div style={{ aspectRatio: "3/4", background: "#fff", borderRadius: 6, padding: 20, color:"#000", fontSize: 8, lineHeight: 1.4 }}>
            <div style={{ borderBottom: "2px solid #2E75B6", paddingBottom: 8, marginBottom: 10, fontWeight: 700, fontSize: 11 }}>Iberdrola Renovables</div>
            <div style={{ fontWeight: 600, fontSize: 10 }}>PV Inspection Report</div>
            <div style={{ color: "#666", marginTop: 4 }}>{mic.id}</div>
            <div style={{ marginTop: 10, height: 6, background: "#eee", width: "80%" }}/>
            <div style={{ marginTop: 4, height: 6, background: "#eee", width: "60%" }}/>
            <div style={{ marginTop: 4, height: 6, background: "#eee", width: "70%" }}/>
          </div>
        )}
        {(file.kind === "log" || file.kind === "csv" || file.kind === "json") && (
          <pre style={{ background: "var(--bg-inset)", padding: 10, borderRadius: 6, fontSize: 9, color: "var(--fg-muted)", lineHeight: 1.5, overflow: "hidden", maxHeight: 180 }}>
{`[2026-04-15 08:12:44] ingest start
[2026-04-15 08:13:02] sortie 01/14 loaded · 612 fr
[2026-04-15 08:13:18] sortie 02/14 loaded · 598 fr
[2026-04-15 08:55:12] SfM complete · 412k tie points
[2026-04-15 09:18:44] dense MVS done
[2026-04-15 09:42:10] thermal register · RMSE 0.8 px
[2026-04-15 10:04:22] detections pass 1 · ${mic.detections || 0}`}
          </pre>
        )}
        {(file.kind === "img" || file.kind === "thermal") && (
          <div className={file.kind === "thermal" ? "thermal-ph" : "rgb-ph"} style={{ aspectRatio: "4/3" }}/>
        )}
        {file.kind === "vector" && (
          <div style={{ aspectRatio: "4/3", background: "var(--bg-inset)", borderRadius: 6, position: "relative" }}>
            <svg width="100%" height="100%" viewBox="0 0 200 150">
              <rect width="200" height="150" fill="url(#g)"/>
              <defs><pattern id="g" width="20" height="20" patternUnits="userSpaceOnUse"><path d="M20 0L0 0 0 20" fill="none" stroke="#1e293b"/></pattern></defs>
              {Array.from({length: 24}).map((_, i) => (
                <circle key={i} cx={(i*29)%200} cy={(i*41)%150} r="2" fill={i%3===0?"#ef4444":i%3===1?"#f97316":"#eab308"}/>
              ))}
            </svg>
          </div>
        )}
      </div>
      <div className="fx-prev-meta">
        <div className="fx-prev-kv"><span className="caps">Size</span><span className="mono num">{humanSize(file.size)}</span></div>
        {file.fmt && <div className="fx-prev-kv"><span className="caps">Format</span><span className="mono">{file.fmt}</span></div>}
        {file.crs && <div className="fx-prev-kv"><span className="caps">CRS</span><span className="mono">{file.crs}</span></div>}
        {file.gen && <div className="fx-prev-kv"><span className="caps">Generated</span><span className="mono">{file.gen}</span></div>}
        <div className="fx-prev-kv"><span className="caps">Checksum</span><span className="mono">sha256:{(file.path.length * 17).toString(16).padStart(8,"0")}…</span></div>
      </div>
      <div className="fx-prev-actions">
        <button className="btn btn-primary btn-xs"><Icon name="download" size={11}/>Download</button>
        <button className="btn btn-secondary btn-xs"><Icon name="share" size={11}/>Copy link</button>
        {(file.kind === "raster" || file.kind === "cloud" || file.kind === "mesh" || file.kind === "splat") && (
          <button className="btn btn-secondary btn-xs"><Icon name="eye" size={11}/>Open viewer</button>
        )}
      </div>
    </>
  );
}

window.StageFiles = StageFiles;
