import { execFileSync } from "node:child_process";
import { existsSync } from "node:fs";
import { setTimeout } from "node:timers/promises";
import { dirname, join } from "node:path";
import { expect } from "e2e";
import { test, WEB, makeState, runPromise } from "./t3.ts";
import { T3_HOME } from "../e2e.config.ts";

test("Cleanup removes a settled worktree through its owning clone", WEB, async ({t3, app, screen, browser}) => {
  const cloneA = await t3.project("clone-a", {"README.md": "Synthetic worktree cleanup example\n"});
  const parent = dirname(cloneA);
  const bare = join(parent, "upstream.git");
  const cloneB = join(parent, "clone-b");
  const git = (...args: string[]) => execFileSync("git", args, {encoding:"utf8"}).trim();
  git("clone", "--bare", cloneA, bare);
  git("-C", cloneA, "remote", "add", "origin", bare);
  git("clone", bare, cloneB);
  const state = makeState(T3_HOME);
  const launched = await runPromise(state.cli(["thread", "start", cloneA, "Showcase", "--title", "Worktree cleanup example", "--worktree", "main", "--branch", "feature-x", "--provider", "devReplay", "--model", "showcase", "--wait", "--json"]));
  const thread = JSON.parse(launched.stdout);
  const worktree = git("-C", cloneA, "worktree", "list", "--porcelain").split("\n").filter(x => x.startsWith("worktree ")).map(x => x.slice(9)).find(x => x !== cloneA)!;
  if (!worktree || git("-C", worktree, "status", "--porcelain")) throw new Error("Fixture worktree must exist and be clean");
  await t3.open(thread);
  await browser.evaluate(async ({cloneB}) => {
    const response = await fetch("/api/projects");
    const snapshot = await response.json();
    const project = snapshot.projects.find((p: {title:string}) => p.title === "clone-a");
    const updated = await fetch("/api/projects/mutate", {method:"POST", headers:{"content-type":"application/json"}, body:JSON.stringify({type:"project.update", commandId:crypto.randomUUID(), projectId:project.id, workspaceRoot:cloneB})});
    if (!updated.ok) throw new Error(`Project update failed: ${updated.status}`);
  }, {cloneB});
  await screen.getByRole("button", "Settle thread", {exact:true}).first().focus();
  await browser.keyboard.press("Enter");
  await t3.open("/settings/worktrees");
  await screen.getByRole("button", "Advanced", {exact:true}).last().tap();
  await screen.getByRole("switch", "Delete settled worktrees", {exact:true}).tap();
  await screen.getByRole("textbox", "Delete settled worktrees in days", {exact:true}).fill("0");
  await browser.keyboard.press("Enter");
  // Let the automatic settings sweep finish inside the 60-second settle-script grace.
  await setTimeout(65_000);
  await t3.open("/settings/maintenance");
  await screen.getByRole("button", "Delete now", {exact:true}).tap();
  await screen.getByRole("button", "Delete now", {exact:true}).waitFor({state:"visible"});
  await screen.getByText(/\d+ removed, \d+ kept/).first().waitFor({state:"visible"});
  const dismiss = screen.getByRole("button", "Dismiss notification", {exact:true});
  if (await dismiss.first().isVisible()) await dismiss.first().tap();
  console.log(JSON.stringify({worktreeDirectoryExists:existsSync(worktree), registeredInCloneA:git("-C", cloneA, "worktree", "list", "--porcelain").includes(worktree)}));
  await app.screenshot("cleanup-result");
  try {
    await expect(screen.getByText("1 removed, 0 kept", {exact:true})).toBeVisible();
    expect(existsSync(worktree)).toBe(false);
    expect(git("-C", cloneA, "worktree", "list", "--porcelain").includes(worktree)).toBe(false);
  } finally {
    // The fixture removes projects by their original root after the test.
    await browser.evaluate(async ({cloneA}) => {
      const snapshot = await (await fetch("/api/projects")).json();
      const project = snapshot.projects.find((p: {title:string}) => p.title === "clone-a");
      const response = await fetch("/api/projects/mutate", {method:"POST", headers:{"content-type":"application/json"}, body:JSON.stringify({type:"project.update", commandId:crypto.randomUUID(), projectId:project.id, workspaceRoot:cloneA})});
      if (!response.ok) throw new Error("Could not restore fixture root");
    }, {cloneA});
  }
});
