// useLiveScan — drives an illustrative scan ANIMATION (engine progress + log)
// via rAF. It intentionally produces NO findings: the real findings come from
// the actual scan we run on our infrastructure and email to the user. This is a
// progress teaser only, not a results preview.

function useLiveScan() {
  const { React } = window;
  const { useState, useRef, useCallback } = React;

  const [scan, setScan] = useState({
    status: 'idle',        // idle | running | done | error
    repoUrl: null,
    progress: 0,           // 0..1
    filesScanned: 0, totalFiles: 0,
    etaMs: 0, elapsedMs: 0,
    findings: [],          // always empty — no fabricated findings are shown
    log: [],
    error: null,
    cancelToken: 0,
  });

  const rafRef = useRef(0);
  const startedRef = useRef(0);
  const cacheRef = useRef(new Map()); // repoUrl → full result

  const cancel = useCallback(() => {
    cancelAnimationFrame(rafRef.current);
    setScan(s => ({ ...s, status: 'idle', cancelToken: s.cancelToken + 1 }));
  }, []);

  const run = useCallback((repoUrlRaw) => {
    const v = window.githubLib.validate(repoUrlRaw);
    if (!v.ok) { setScan(s => ({ ...s, status: 'error', error: v.error })); return; }
    const repoUrl = v.canonical;

    // cached?
    if (cacheRef.current.has(repoUrl)) {
      const cached = cacheRef.current.get(repoUrl);
      setScan({ ...cached, status: 'done' });
      return;
    }

    const plan = window.scanRunner.plan(repoUrl);
    startedRef.current = performance.now();
    cancelAnimationFrame(rafRef.current);

    const tools = ['semgrep', 'bandit', 'gitleaks', 'trivy', 'njsscan', 'checkov'];
    const logPhases = [
      { t: 0,     text: `cloning ${repoUrl} --depth 1` },
      { t: 400,   text: `repo size: ${Math.max(1, Math.round(plan.totalFiles / 14))}MB · ok · ${plan.totalFiles} files` },
      { t: 700,   text: 'phase 1 / 6 · whitebox + sast' },
      { t: 900,   text: 'semgrep: loading ruleset p/owasp-top-10,p/python · 312 rules' },
      { t: 1400,  text: 'bandit: python ast · B-series checks' },
      { t: 1900,  text: 'gitleaks: commit history scan depth=500' },
      { t: 2500,  text: 'trivy: dependency + container scan' },
    ];

    setScan(s => ({
      ...s, status: 'running', repoUrl, progress: 0,
      filesScanned: 0, totalFiles: plan.totalFiles,
      etaMs: plan.totalMs, elapsedMs: 0,
      findings: [], log: [], error: null,
    }));

    const tick = (now) => {
      const elapsed = now - startedRef.current;
      const p = Math.min(1, elapsed / plan.totalMs);
      const filesScanned = Math.min(plan.totalFiles, Math.floor(plan.totalFiles * p));
      const etaMs = Math.max(0, plan.totalMs - elapsed);

      // accumulate log phases + a streaming per-tool heartbeat line
      const logs = [];
      for (const lp of logPhases) if (lp.t <= elapsed) logs.push(lp.text);
      const beats = Math.floor(elapsed / 350);
      for (let i = 0; i < Math.min(beats, 18); i++) {
        const tool = tools[i % tools.length];
        logs.push(`${tool} ▸ scanned ${Math.floor(filesScanned * (i / 18))} files`);
      }

      setScan(s => ({
        ...s,
        progress: p,
        filesScanned, etaMs, elapsedMs: elapsed,
        log: logs.slice(-14),
      }));

      if (p < 1) {
        rafRef.current = requestAnimationFrame(tick);
      } else {
        const done = {
          status: 'done', repoUrl, progress: 1,
          filesScanned: plan.totalFiles, totalFiles: plan.totalFiles,
          etaMs: 0, elapsedMs: plan.totalMs,
          log: [...logs.slice(-13), 'phase-1 preview complete · queue the full scan below'],
          findings: [],
          error: null, cancelToken: 0,
        };
        cacheRef.current.set(repoUrl, done);
        setScan(done);
      }
    };
    rafRef.current = requestAnimationFrame(tick);
  }, []);

  return { scan, run, cancel };
}
window.useLiveScan = useLiveScan;
