/* FreeSize — Scan view */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

function VolumeSelect({ volumes, value, onChange, className }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  const cur = volumes.find((v) => v.id === value) || volumes[0];
  const { fmt, heatColor } = window.FZ;
  useEffect(() => {
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", h);
    return () => document.removeEventListener("mousedown", h);
  }, []);
  const usedPct = (v) => ((v.total - v.free) / v.total) * 100;
  return (
    <div className={"select" + (className ? " " + className : "")} ref={ref}>
      <button className="select-btn" onClick={() => setOpen((o) => !o)} title="Volume wählen">
        <span style={{ color: "var(--accent)", display: "grid", placeItems: "center" }}><IconHardDrive size={17} /></span>
        <span className="sb-main">
          <span className="sb-vol">{cur.label}</span>{" "}
          <span className="sb-cap">{cur.caption} · {fmt(cur.total)}</span>
        </span>
        <IconChevDown size={15} style={{ color: "var(--faint)" }} />
      </button>
      {open && (
        <div className="select-menu">
          {volumes.map((v) => (
            <div key={v.id} className={"select-opt" + (v.id === value ? " sel" : "")}
              onClick={() => { onChange(v.id); setOpen(false); }}>
              <span style={{ color: "var(--accent)", display: "grid", placeItems: "center" }}><IconHardDrive size={18} /></span>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: "flex", justifyContent: "space-between", gap: 8 }}>
                  <b style={{ fontWeight: 700 }}>{v.label}</b>
                  <span style={{ color: "var(--muted)", fontSize: 12, fontFamily: "var(--mono)" }}>{fmt(v.free)} frei</span>
                </div>
                <div style={{ fontSize: 12, color: "var(--muted)" }}>{v.caption} · {fmt(v.total)}</div>
                <div className="vol-meter"><i style={{ width: usedPct(v) + "%", background: heatColor(usedPct(v) / 100) }} /></div>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ---- Sunburst panel (radial space-filling, heatmap-coloured) ----
function Sunburst({ root, globalMax, onDrill, selected, onSelect }) {
  const { heatColor, heatT, fmt } = window.FZ;
  const [ref, size] = useSize();
  const cx = size.w / 2, cy = size.h / 2;
  const radius = Math.max(0, Math.min(size.w, size.h) / 2 - 6);
  const hole = radius * 0.22;
  const maxRings = 4;
  const ringW = (radius - hole) / maxRings;

  const pt = (r, a) => [cx + r * Math.cos(a), cy + r * Math.sin(a)];
  function annular(r0, r1, a0, a1) {
    const g = 0.004; a0 += g; a1 -= g; if (a1 <= a0) a1 = a0 + 0.001;
    const large = (a1 - a0) > Math.PI ? 1 : 0;
    const [x0o, y0o] = pt(r1, a0), [x1o, y1o] = pt(r1, a1), [x1i, y1i] = pt(r0, a1), [x0i, y0i] = pt(r0, a0);
    return `M${x0o.toFixed(2)} ${y0o.toFixed(2)} A${r1} ${r1} 0 ${large} 1 ${x1o.toFixed(2)} ${y1o.toFixed(2)} ` +
           `L${x1i.toFixed(2)} ${y1i.toFixed(2)} A${r0} ${r0} 0 ${large} 0 ${x0i.toFixed(2)} ${y0i.toFixed(2)} Z`;
  }
  const slices = [];
  function recurse(node, ring, a0, a1) {
    if (ring >= maxRings) return;
    const kids = (node.children || []).filter((c) => c.size > 0).sort((a, b) => b.size - a.size);
    let total = 0; kids.forEach((k) => (total += k.size));
    if (total <= 0) return;
    const inner = hole + ring * ringW, outer = inner + ringW - 1.2;
    let a = a0;
    kids.forEach((k) => {
      const span = (a1 - a0) * (k.size / total), b = a + span;
      if (span >= 0.012) { slices.push({ node: k, d: annular(inner, outer, a, b) }); recurse(k, ring + 1, a, b); }
      a = b;
    });
  }
  if (radius > 4 && root) recurse(root, 0, -Math.PI / 2, -Math.PI / 2 + 2 * Math.PI);

  return (
    <div className="sunburst" ref={ref}>
      {radius > 4 && root && (
        <svg width={size.w} height={size.h} viewBox={`0 0 ${size.w} ${size.h}`}>
          {slices.map((s) => {
            const isDir = s.node.type === "dir";
            const drill = isDir && s.node.children && s.node.children.length;
            return (
              <path key={s.node.id} d={s.d}
                fill={heatColor(heatT(s.node.size, globalMax), isDir ? 1 : 0.82)}
                className={"sb-slice" + (selected === s.node.id ? " active" : "") + (drill ? " drill" : "")}
                onClick={() => { onSelect(s.node.id); if (drill) onDrill(s.node); }}>
                <title>{s.node.name + " · " + fmt(s.node.size)}</title>
              </path>
            );
          })}
          <circle cx={cx} cy={cy} r={Math.max(0, hole - 2)} className="sb-center" />
          <text x={cx} y={cy - 2} textAnchor="middle" className="sb-c-name">
            {root.name.length > 14 ? root.name.slice(0, 13) + "…" : root.name}
          </text>
          <text x={cx} y={cy + 13} textAnchor="middle" className="sb-c-size">{fmt(root.size)}</text>
        </svg>
      )}
    </div>
  );
}
window.Sunburst = Sunburst;

// deep prune by min size
function pruneTree(node, minBytes) {
  if (node.type === "file") return node.size >= minBytes ? node : null;
  const kids = (node.children || []).map((c) => pruneTree(c, minBytes)).filter(Boolean);
  return { ...node, children: kids };
}
function maxNodeSize(node, skipRoot) {
  let m = skipRoot ? 0 : node.size;
  (node.children || []).forEach((c) => { m = Math.max(m, maxNodeSize(c, false)); });
  return m;
}
function findNode(node, id) {
  if (node.id === id) return node;
  for (const c of (node.children || [])) { const r = findNode(c, id); if (r) return r; }
  return null;
}
function pathTo(node, id, acc) {
  acc = acc || [];
  if (node.id === id) return [...acc, node];
  for (const c of (node.children || [])) { const r = pathTo(c, id, [...acc, node]); if (r) return r; }
  return null;
}

function ScanView({ tweaks, nav }) {
  const volumes = window.VOLUMES;
  const [volume, setVolume] = useState("c");
  const curVol = volumes.find((v) => v.id === volume);
  const [path, setPath] = useState(curVol.path);
  const [minSize, setMinSize] = useState(50);
  const [scanState, setScanState] = useState("idle"); // idle|scanning|done
  const [progress, setProgress] = useState({ files: 0, dirs: 0, bytes: 0, errors: 0, cur: "" });
  const [expanded, setExpanded] = useState(new Set());
  const [selected, setSelected] = useState(null);
  const [vizRootId, setVizRootId] = useState(null);
  const [vizMode, setVizMode] = useState("treemap"); // treemap|sunburst
  const timer = useRef(null);

  const { fmt, fmtInt, heatColor, heatT } = window.FZ;

  useEffect(() => { setPath(volumes.find((v) => v.id === volume).path); }, [volume]);

  const fullTree = useMemo(() => pruneTree(window.SCAN_DATA, minSize * 1024 * 1024), [minSize]);
  const globalMax = useMemo(() => maxNodeSize(fullTree, true), [fullTree]);
  const target = useMemo(() => ({ files: window.SCAN_DATA.files, dirs: window.SCAN_DATA.dirs, bytes: window.SCAN_DATA.size, errors: 7 }), []);

  const showTree = scanState !== "idle";
  const vizRoot = useMemo(() => (vizRootId ? findNode(fullTree, vizRootId) || fullTree : fullTree), [vizRootId, fullTree]);
  const crumbs = useMemo(() => pathTo(fullTree, vizRoot.id, []) || [fullTree], [fullTree, vizRoot]);

  const samplePaths = [
    "C:\\Users\\max\\AppData\\Local\\Docker", "C:\\Program Files (x86)\\Steam\\steamapps",
    "C:\\Windows\\WinSxS", "C:\\Users\\max\\Videos", "C:\\Users\\max\\Documents\\Projekte\\freesize\\node_modules",
    "C:\\ProgramData\\Package Cache", "C:\\hiberfil.sys",
  ];

  const startScan = useCallback(() => {
    clearInterval(timer.current);
    setScanState("scanning");
    setSelected(null);
    setVizRootId(null);
    setProgress({ files: 0, dirs: 0, bytes: 0, errors: 0, cur: samplePaths[0] });
    setExpanded(new Set([window.SCAN_DATA.id]));
    const dur = 1900;
    const start = performance.now();
    timer.current = setInterval(() => {
      const e = Math.min(1, (performance.now() - start) / dur);
      const ease = 1 - Math.pow(1 - e, 2.2);
      setProgress({
        files: Math.round(target.files * ease),
        dirs: Math.round(target.dirs * ease),
        bytes: target.bytes * ease,
        errors: Math.round(target.errors * Math.min(1, e * 1.3)),
        cur: samplePaths[Math.floor(e * (samplePaths.length - 0.001))],
      });
      if (e >= 1) {
        clearInterval(timer.current);
        setProgress({ ...target, cur: "" });
        setScanState("done");
      }
    }, 90);
  }, [target]);

  const cancelScan = useCallback(() => {
    clearInterval(timer.current);
    setScanState((s) => (s === "scanning" ? "done" : s));
    setProgress((p) => ({ ...p, cur: "" }));
  }, []);

  useEffect(() => () => clearInterval(timer.current), []);

  const toggle = useCallback((id) => {
    setExpanded((prev) => { const n = new Set(prev); n.has(id) ? n.delete(id) : n.add(id); return n; });
  }, []);
  const reveal = useCallback((node) => { setSelected(node.id); }, []);
  const drill = useCallback((node) => { setVizRootId(node.id); }, []);

  const rowH = tweaks.density === "compact" ? 28 : tweaks.density === "comfy" ? 40 : 34;

  return (
    <div className="scan">
      {/* merged app bar: brand + scan controls + view tabs */}
      <header className="appbar scanbar">
        <Logo iconSize={26} showSub={false} />
        <VolumeSelect volumes={volumes} value={volume} onChange={setVolume} className="tb-vol" />
        <div className="path-wrap tb-path">
          <input className="input mono" value={path} onChange={(e) => setPath(e.target.value)} spellCheck={false}
            placeholder="Pfad oder \\Server\Freigabe …" />
          <button className="btn btn-icon" title="Ordner durchsuchen…"><IconFolder size={16} /></button>
        </div>
        <div className="tb-min">
          <input className="input" type="number" min="0" value={minSize}
            onChange={(e) => setMinSize(Math.max(0, +e.target.value || 0))} title="Minimale Grösse (MB)" />
          <span className="unit">MB</span>
        </div>
        {scanState === "scanning"
          ? <button className="btn btn-danger tb-go" onClick={cancelScan}><IconX size={16} /> Abbrechen</button>
          : <button className="btn btn-primary tb-go" onClick={startScan}><IconRadar size={16} /> Scannen</button>}
        <div className="tabs">
          <button className="tab active" title="Scan" onClick={() => nav.setView("scan")}><IconRadar size={17} /></button>
          <button className="tab" title="Einstellungen" onClick={() => nav.setView("settings")}><IconSettings size={17} /></button>
        </div>
      </header>

      {/* status line */}
      {showTree && (
        <div className="statusline">
          {scanState === "scanning"
            ? <span className="status-state"><span className="spinner" /> Scanne…</span>
            : <span className="status-state done"><IconCheck size={16} stroke={2.4} /> Fertig</span>}
          <span className="status-counts">
            <b>{fmtInt(progress.files)}</b> Dateien <span className="dot">·</span>
            <b>{fmtInt(progress.dirs)}</b> Ordner <span className="dot">·</span>
            <b>{fmt(progress.bytes)}</b>
          </span>
          {progress.errors > 0 && (
            <span className="status-err" title="Ordner ohne Zugriffsberechtigung">
              <IconLock size={13} /> {fmtInt(progress.errors)} ohne Zugriff
            </span>
          )}
          {scanState === "scanning" && progress.cur && (
            <span className="status-path" title={progress.cur}>{progress.cur}</span>
          )}
        </div>
      )}

      {/* body */}
      {!showTree ? (
        <div className="empty">
          <div className="empty-inner">
            <div className="empty-glyph"><IconRadar size={42} stroke={1.4} /></div>
            <h3>Bereit zum Scannen</h3>
            <p>Volume oder Pfad wählen und „Scannen“ klicken. FreeSize zeigt dir dann, was deinen Speicher belegt — grösste Elemente zuerst.</p>
            <button className="btn btn-primary" onClick={startScan} style={{ marginTop: 4 }}><IconRadar size={16} /> Jetzt scannen</button>
          </div>
        </div>
      ) : (
        <div className="scan-body">
          <div className="tree-pane">
            <div className="tree-head">
              <span>Name</span>
              <span>Anteil</span>
              <span className="th-r">Grösse</span>
              <span></span>
            </div>
            <div className="tree-scroll" style={{ "--row-h": rowH + "px" }}>
              {fullTree.children && fullTree.children.length ? (
                fullTree.children.map((c) => (
                  <TreeRows key={c.id} node={c} depth={0} parentSize={fullTree.size} globalMax={globalMax}
                    expanded={expanded} onToggle={toggle} selected={selected} onSelect={setSelected}
                    onReveal={reveal} showMeta={tweaks.showCounts} />
                ))
              ) : (
                <div className="empty"><div className="empty-inner"><p>Keine Einträge über der Mindestgrösse.</p></div></div>
              )}
            </div>
          </div>

          {/* visual panel */}
          <div className="viz-pane">
            <div className="viz-head">
              <div className="viz-title">Visualisierung <small>{fmt(vizRoot.size)}</small></div>
              <div className="viz-toggle">
                <button className={vizMode === "treemap" ? "on" : ""} onClick={() => setVizMode("treemap")} title="Treemap"><IconGrid size={16} /></button>
                <button className={vizMode === "sunburst" ? "on" : ""} onClick={() => setVizMode("sunburst")} title="Sunburst"><IconSunburst size={16} /></button>
              </div>
            </div>
            <div style={{ padding: "0 16px" }}>
              <div className="crumbs">
                {crumbs.map((c, i) => (
                  <React.Fragment key={c.id}>
                    {i > 0 && <span className="crumb-sep">›</span>}
                    <span className={"crumb" + (i === crumbs.length - 1 ? " cur" : "")}
                      onClick={() => i < crumbs.length - 1 && setVizRootId(c.id === fullTree.id ? null : c.id)}>
                      {i === 0 ? "Wurzel" : c.name}
                    </span>
                  </React.Fragment>
                ))}
              </div>
            </div>

            <div className="treemap-wrap">
              {vizMode === "treemap"
                ? <Treemap root={vizRoot} globalMax={globalMax} onDrill={drill} selected={selected} onSelect={setSelected} />
                : <Sunburst root={vizRoot} globalMax={globalMax} onDrill={drill} selected={selected} onSelect={setSelected} />}
            </div>

            <div className="viz-foot">
              <div className="legend">
                <span>klein</span>
                <span className="grad" />
                <span>gross</span>
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
window.ScanView = ScanView;
