import { expect } from "e2e";
import { spawn, execFileSync } from "node:child_process";
import { cp, mkdtemp, writeFile, readFile } from "node:fs/promises";
import { watch } from "node:fs";
import { test, WEB } from "./t3.ts";

const scratch = process.env.SLOWFS_PROOF_ROOT ?? "/tmp/slow-watcher-proof";
test("A slow watcher read does not block unrelated server requests", WEB, async ({ t3, app, screen, browser }) => {
 const files = Object.fromEntries(Array.from({length:50},(_,i)=>[`src/f${i}.ts`,`export const f${i} = ${i};\n`]));
 const project = await t3.project("Slow watcher demo", files);
 const run = await mkdtemp(`${scratch}/run-`);
 await cp(project, `${run}/backing`, {recursive:true});
 const fuse = spawn(`${scratch}/venv/bin/python`, [`${scratch}/slowfs.py`, `${run}/backing`, project, `${run}/reading`], {stdio:["ignore","pipe","pipe"]});
 await writeFile(`${run}/fuse.pid`, String(fuse.pid));
 let errors = ""; fuse.stderr.on("data", c => errors += c);
 await new Promise<void>((resolve,reject)=>{fuse.stdout.on("data", c=>{if(String(c).includes("READY"))resolve();});fuse.on("exit",code=>reject(new Error(`FUSE ${code}: ${errors}`)));});
 try {
  await t3.open();
  await screen.getByRole("textbox").fill("@f1");
  await screen.getByText("f1.ts", {exact:true}).first().waitFor({state:"visible"});
  await app.screenshot("search-ready");
  const url = await browser.evaluate(()=>`${location.origin}/.well-known/t3/environment`);
  const baseline = performance.now(); await fetch(url); const baselineMs = performance.now()-baseline;
  const reading = new Promise<void>(resolve=>{const watcher=watch(run,(_event,name)=>{if(name==="reading"){watcher.close();resolve();}});});
  await writeFile(`${project}/src/slow.ts`, "export const slow = 1;\n");
  await reading;
  await screen.getByRole("textbox").press("1");
  // Allow the composer's debounce to dispatch the real search before probing HTTP.
  await new Promise(resolve=>setTimeout(resolve,1000));
  const start=performance.now();
  const response=fetch(url).then(r=>({status:r.status, ms:performance.now()-start}));
  await new Promise(resolve=>setTimeout(resolve,28000));
  await app.screenshot("watcher-busy");
  const result=await response;
  await writeFile(`${run}/timing.json`, JSON.stringify({baselineMs,...result},null,2));
  console.log(`HTTP baseline ${baselineMs.toFixed(1)} ms; during slow read ${result.ms.toFixed(1)} ms; status ${result.status}`);
  await app.screenshot("http-probe-complete");
  expect(result.ms).toBeLessThan(2000);
 } finally {
  const drained = new Promise<void>(resolve => {
   fuse.stdout.on("data", c => { if (String(c).includes("DRAINED")) resolve(); });
  });
  await writeFile(`${run}/reading.drain`, "drain");
  await drained;
  execFileSync("fusermount3",["-uz",project]);

 }
});
