import { expect } from "e2e";
import { execFileSync } from "node:child_process";
import * as fs from "node:fs";
import * as path from "node:path";
import { test, WEB, makeState, runPromise } from "./t3.ts";
import { T3_HOME } from "../e2e.config.ts";

test("Annex worktree deletion, cleanup, orphans and refusal recovery", WEB, async ({t3, app, screen, browser}) => {
  const root=fs.mkdtempSync("/tmp/factory-pr-34065-a1794710111-evidence-2/run-");
  const project=path.join(root,"Annex-demo"); fs.mkdirSync(project);
  fs.writeFileSync(path.join(project,"README.md"),"Annex demo\n");
  fs.writeFileSync(path.join(project,"asset.txt"),"annex content\n");
  const git = (cwd:string,...args:string[]) => execFileSync("git",args,{cwd,encoding:"utf8"});
  git(project,"init","-b","main");
  git(project,"config","user.name","Scenario"); git(project,"config","user.email","scenario@example.invalid");
  git(project,"add","."); git(project,"commit","-m","Initial");
  git(project,"annex","init","Scenario"); git(project,"rm","--cached","asset.txt"); git(project,"annex","add","asset.txt"); git(project,"commit","-m","Annex asset");
  const {cli} = makeState(T3_HOME);
  await runPromise(cli(["project","add",project,"--title","Annex demo"]));
  await t3.open();
  await browser.evaluate(async (dir) => {
    const {serverEnvironment}=await import("/src/state/server.ts");
    const {appAtomRegistry}=await import("/src/rpc/atomRegistry.ts");
    const environmentId=(await (await fetch("/.well-known/t3/environment")).json()).environmentId;
    await serverEnvironment.updateSettings.run(appAtomRegistry,{environmentId,input:{patch:{worktreesDirectory:dir}}});
  },path.join(root,"worktrees"));
  const start = async (title:string, branch:string) => JSON.parse((await runPromise(cli(["thread","start",project,"go","--title",title,"--provider","devReplay","--model","multi-turn","--worktree","main","--branch",branch,"--wait","--json"]))).stdout);
  const manual = await start("Manual removal","t3/annex-a");
  const cleanup = await start("Storage cleanup","t3/annex-b");
  const dirty = await start("Dirty protection","t3/annex-dirty");
  const locked = await start("Locked protection","t3/annex-locked");
  const observer = await t3.thread({project,title:"Verification",messages:["inspect"]});
  const list = () => git(project,"worktree","list","--porcelain").trim().split("\n\n").map(x=>({folder:x.split("\n")[0].slice(9),branch:x.match(/branch refs\/heads\/(.*)/)?.[1]}));
  const folder = (branch:string) => list().find(x=>x.branch===branch)!.folder;
  const a=folder("t3/annex-a"), b=folder("t3/annex-b"), d=folder("t3/annex-dirty"), l=folder("t3/annex-locked");
  fs.writeFileSync(path.join(d,"README.md"),"local changes\n"); git(project,"worktree","lock","--reason","proof lock",l);
  const parent=path.dirname(b), oa=path.join(parent,"orphan-annex"), op=path.join(parent,"orphan-plain");
  git(project,"worktree","add","-b","orphan-annex",oa,"main"); git(project,"worktree","add","-b","orphan-plain",op,"main");
  const admin=fs.realpathSync(path.join(op,".git")); fs.unlinkSync(path.join(op,".git")); fs.writeFileSync(path.join(op,".git"),`gitdir: ${admin}\n`);
  const old = new Date(Date.now()-3*3600000); fs.utimesSync(oa,old,old); fs.utimesSync(op,old,old);
  await t3.open(cleanup);
  await screen.getByRole("button","Storage cleanup, Annex demo",{exact:true}).secondaryTap();
  await screen.getByRole("menuitem","Settle thread",{exact:true}).tap();
  await t3.open("/settings/worktrees");
  await screen.getByRole("button","Advanced",{exact:true}).tap();
  await screen.getByRole("switch","Delete unchanged worktrees",{exact:true}).tap();
  // The production settle grace is part of the reproduced flow.
  await new Promise(r=>setTimeout(r,61000));
  await t3.open("/settings/maintenance");
  await screen.getByRole("button","Delete now",{exact:true}).tap();
  await screen.getByRole("button",/Last run/).tap();
  await browser.evaluate((name)=>{[...document.querySelectorAll("span")].find(e=>e.textContent===name)?.scrollIntoView({block:"center"})},path.basename(b));
  await app.screenshot("storage-cleanup");
  await browser.evaluate((name)=>{[...document.querySelectorAll("span")].find(e=>e.textContent===name)?.scrollIntoView({block:"center"})},op);
  await app.screenshot("orphan-report");
  const cleanupRemoved=!fs.existsSync(b);
  const reportText = await browser.evaluate(()=>document.body.innerText);
  const orphanReported=reportText.includes("orphan-annex") && reportText.includes("No thread uses this worktree");
  await t3.open(manual);
  await screen.getByRole("button","Manual removal, Annex demo",{exact:true}).secondaryTap();
  await screen.getByRole("menuitem","Delete",{exact:true}).tap();
  await screen.getByRole("button","Confirm",{exact:true}).tap();
  await screen.getByRole("button","Confirm",{exact:true}).tap();
  await app.screenshot("manual-removal");
  const manualRemoved=!list().some(x=>x.folder===a) && !fs.existsSync(a);
  const refusals = await browser.evaluate(async ({project,d,l}) => {
    const {vcsEnvironment}=await import("/src/state/vcs.ts");
    const {appAtomRegistry}=await import("/src/rpc/atomRegistry.ts");
    const environmentId=(await (await fetch("/.well-known/t3/environment")).json()).environmentId;
    const results=[];
    for (const [label,p] of [["Dirty, force=false",d],["Locked, force=true",l]]) {
      const r=await vcsEnvironment.removeWorktree.run(appAtomRegistry,{environmentId,input:{cwd:project,path:p,force:p===l}});
      results.push({label,status:r._tag,error:r._tag==="Failure"?JSON.stringify(r.cause):null});
    }
    return results;
  },{project,d,l});
  fs.writeFileSync(path.join(root,"refusals.json"),JSON.stringify(refusals,null,2));
  const retained=[d,l].every(p=>fs.lstatSync(path.join(p,".git")).isSymbolicLink() && fs.readFileSync(path.join(p,"asset.txt"),"utf8")==="annex content\n" && git(p,"status","--porcelain")!==undefined);
  await t3.open(observer);
  fs.writeFileSync(path.join(root,"verify.py"), `import os,subprocess,json\nfrom pathlib import Path\ngit=lambda *a: subprocess.check_output(['git',*a],text=True)\nrecords=git('worktree','list','--porcelain').strip().split('\\n\\n')\nprint('REAL GIT WORKTREE REGISTRATION')\nfor branch in ['t3/annex-a','t3/annex-b','t3/annex-dirty','t3/annex-locked']:\n rows=[r for r in records if 'branch refs/heads/'+branch+'\\n' in r+'\\n']\n print(branch+': '+('REGISTERED' if rows else 'REMOVED'))\n if rows and branch in ['t3/annex-dirty','t3/annex-locked']:\n  p=Path(rows[0].splitlines()[0][9:]); print('  .git symlink:',(p/'.git').is_symlink(),'| annex content:',(p/'asset.txt').read_text().strip()); print('  Git status:',subprocess.check_output(['git','-C',str(p),'status','--porcelain'],text=True).strip() or 'clean')\nprint('SERVER REMOVAL RESPONSES')\nfor r in json.load(open('../refusals.json')): print(r['label']+': '+r['status']); print(r['error'])\n`);
  await browser.evaluate(async (threadId)=>{
    const {useTerminalUiStateStore}=await import("/src/terminalUiStateStore.ts");
    const environmentId=(await (await fetch("/.well-known/t3/environment")).json()).environmentId;
    useTerminalUiStateStore.getState().setTerminalHeight({environmentId,threadId},550);
  },observer.threadId);
  await browser.keyboard.press("Control+j");
  await browser.keyboard.type("PS1='$ '; clear; python3 ../verify.py");
  await browser.keyboard.press("Enter");
  await new Promise(r=>setTimeout(r,1000));
  await app.screenshot("visible-registration-and-refusal-recovery");
  expect({manualRemoved,cleanupRemoved,orphanReported,retained}).toEqual({manualRemoved:true,cleanupRemoved:true,orphanReported:true,retained:true});
});
