import { expect } from "e2e";
import { readFile, writeFile } from "node:fs/promises";
import { createHash } from "node:crypto";
import { test, WEB, makeState, runPromise } from "./t3.ts";
import { run } from "./shell.ts";
import { T3_HOME } from "../e2e.config.ts";

test("Static worktree prefix survives unavailable automatic naming", WEB, async ({ t3, app, screen, browser }) => {
  const capture = async (label: string) => {
    for (let attempt = 0; attempt < 6; attempt++) {
      const first = await app.screenshot(`${label}-stability`);
      await new Promise((resolve) => setTimeout(resolve, 500));
      const second = await app.screenshot(label);
      const digest = async (path: string) => createHash("sha256").update(await readFile(path)).digest("hex");
      if (await digest(first) === await digest(second)) return;
    }
    throw new Error(`Capture did not stabilize: ${label}`);
  };
  const normal = await t3.project("Prefix demo");
  const collision = await t3.project("Prefix collision");
  const override = await t3.project("Project override");
  await runPromise(run("git", ["branch", "my-prefix"], { cwd: collision }));
  await t3.open();
  await screen.getByRole("button", "Settings", { exact: true }).waitFor({ state: "visible" });
  await app.open("/settings/worktrees");
  await screen.getByRole("combobox", "Worktree branch naming").tap();
  await screen.getByRole("option", "Static prefix").tap();
  await screen.getByRole("textbox", "Branch prefix").fill("my-prefix");
  await screen.getByRole("textbox", "Branch prefix").press("Tab");
  await capture("configured-static-prefix");
  await screen.getByRole("button", "Project scope: All projects").tap();
  await screen.getByRole("menuitemradio", "Project override").tap();
  await screen.getByRole("textbox", "Branch prefix").fill("project-prefix");
  await screen.getByRole("textbox", "Branch prefix").press("Tab");
  await capture("configured-project-override");
  const { cli } = makeState(T3_HOME);
  const results: Array<{ branch: string; pattern: RegExp }> = [];
  for (const [project, title, label, pattern] of [
    [normal, "Naming unavailable", "prefix-after-naming-failure", /^my-prefix\/[0-9a-f]{8}$/],
    [collision, "Namespace collision", "prefix-with-namespace-collision", /^my-prefix-[0-9a-f]{8}$/],
    [override, "Override naming unavailable", "project-override-after-naming-failure", /^project-prefix\/[0-9a-f]{8}$/],
  ] as const) {
    await runPromise(cli(["thread", "start", project, "Give me a short tour", "--title", title, "--provider", "devReplay", "--model", "multi-turn", "--worktree", "main", "--wait", "--json"]));
    await app.open("/");
    await screen.getByRole("button", { name: new RegExp(`^${title}, Done,`) }).press("Enter");
    await screen.getByText("fixture turn complete", { exact: false }).first().waitFor({ state: "visible" });
    const worktrees = await runPromise(run("git", ["worktree", "list", "--porcelain"], { cwd: project }));
    const branch = [...worktrees.stdout.matchAll(/^branch refs\/heads\/(.+)$/gm)].map((m) => m[1]).find((name) => name !== "main")!;
    results.push({ branch, pattern });
    await capture(label);
  }
  if (process.env.PREFIX_EVIDENCE_FILE) await writeFile(process.env.PREFIX_EVIDENCE_FILE, JSON.stringify(results.map(({ branch, pattern }) => ({ branch, expected: pattern.source })), null, 2));
  for (const result of results) expect(result.branch).toMatch(result.pattern);
});
