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

test("Resuming a missing worktree preserves work pushed to the sole upstream remote", WEB,
  async ({ t3, app, screen, browser }) => {
    const project = await t3.project("restore-demo", { "README.md": "Project base\n" });
    const git = (cwd: string, ...args: string[]) => execFileSync("git", args, { cwd, encoding: "utf8" }).trim();
    git(project, "config", "user.name", "Scenario");
    git(project, "config", "user.email", "scenario@example.invalid");
    const remote = join(project, "../pushed.git");
    git(project, "init", "--bare", "--initial-branch=main", remote);
    git(project, "remote", "add", "origin", remote);
    git(project, "push", "origin", "main");
    git(project, "remote", "set-head", "origin", "main");
    const { cli } = makeState(T3_HOME);
    const call = async (...args: string[]) => JSON.parse((await runPromise(cli(args))).stdout);
    const started = await call("thread", "start", project, "Start the restore demonstration", "--title", "Restore pushed thread work", "--provider", "devReplay", "--model", "multi-turn", "--worktree", "main", "--branch", "feature/restore", "--wait", "--json");
    const id = started.threadId;
    const details = await call("thread", "show", id, "--json");
    const worktree = details.thread.worktreePath;
    writeFileSync(join(worktree, "thread.txt"), "Pushed thread work is preserved.\n");
    git(worktree, "add", "thread.txt");
    git(worktree, "commit", "-m", "thread tip: preserve pushed work");
    const pushedTip = git(worktree, "rev-parse", "HEAD");
    git(worktree, "push", "origin", "HEAD:refs/heads/feature/restore");
    git(project, "switch", "-c", "project-current");
    writeFileSync(join(project, "project.txt"), "Unrelated project work\n");
    git(project, "add", "project.txt");
    git(project, "commit", "-m", "project tip: unrelated work");
    git(project, "switch", "--detach");
    git(project, "remote", "rename", "origin", "upstream");
    git(project, "worktree", "remove", "--force", worktree);
    git(project, "worktree", "prune");
    git(project, "branch", "-D", "feature/restore");

    await t3.open();
    await screen.getByRole("button", "Restore pushed thread work, Done, restore-demo").tap();
    await screen.getByRole("textbox").fill("Resume this thread after its worktree was removed");
    await screen.getByRole("textbox").press("Enter");
    await screen.getByText("second fixture turn complete", { exact: false }).waitFor({ state: "visible" });
    await screen.getByRole("button", "Toggle right panel").tap();
    await screen.getByRole("button", "Files F").tap();
    await screen.getByRole("treeitem", "README.md").waitFor({ state: "visible" });
    let previous = readFileSync(await app.screenshot("settling-files"));
    let stable = false;
    for (let attempt = 0; attempt < 8; attempt++) {
      await new Promise((resolve) => setTimeout(resolve, 500));
      const current = readFileSync(await app.screenshot("restored-thread-work"));
      if (previous.equals(current)) { stable = true; break; }
      previous = current;
    }
    if (!stable) throw new Error("File view did not settle for a capture");
    expect(git(worktree, "rev-parse", "HEAD")).toBe(pushedTip);
    expect(readFileSync(join(worktree, "thread.txt"), "utf8")).toBe("Pushed thread work is preserved.\n");
  });
