import { expect } from "e2e";
import { mkdtemp, cp, rm, readFile, writeFile, utimes } from "node:fs/promises";
import { test, WEB, makeState, runPromise } from "./t3.ts";
import { APP_DIR, T3_HOME } from "../e2e.config.ts";

test("Completed prompts in a non-Git project allow conversation-only rewind", WEB, async ({ t3, app, screen, browser }) => {
  const stableScreenshot = async (label: string) => {
    let previous = await app.screenshot(`${label}-settling`);
    for (let attempt = 0; attempt < 10; attempt++) {
      await new Promise((resolve) => setTimeout(resolve, 500));
      const current = await app.screenshot(`${label}-check-${attempt}`);
      if ((await readFile(previous)).equals(await readFile(current))) {
        await app.screenshot(label);
        return;
      }
      previous = current;
    }
    throw new Error(`Capture did not settle: ${label}`);
  };
  const original = await t3.project("Notes", { "notes.txt": "Keep these file contents.\n" });
  const parent = await mkdtemp(`${process.env.T3_EVIDENCE_DIR ?? "/tmp"}/notes-`);
  const project = `${parent}/Notes`;
  await cp(original, project, { recursive: true });
  await rm(`${project}/.git`, { recursive: true });
  const { cli } = makeState(T3_HOME);
  await runPromise(cli(["project", "remove", original, "--force"]));
  await runPromise(cli(["project", "add", project, "--title", "Notes"]));
  await writeFile(`${project}/notes.txt`, "Keep these file contents.\nAn unsaved-to-Git edit.\n");
  try {
  await t3.open();
  await screen.getByRole("button", "Showcase", { exact: true }).tap();
  await screen.getByRole("option", "Multi turn", { exact: false }).tap();
  await browser.keyboard.press("Escape");
  await screen.getByTestId("composer-editor").fill("Summarize these notes");
  await screen.getByTestId("composer-editor").press("Enter");
  await expect(screen.getByText("first fixture turn complete", { exact: false })).toBeVisible();
  await expect(screen.getByRole("button", "Stop generation")).toBeHidden();
  await screen.getByTestId("composer-editor").fill("Suggest a follow-up");
  await screen.getByTestId("composer-editor").press("Enter");
  await expect(screen.getByText("second fixture turn complete", { exact: false })).toBeVisible();
  await expect(screen.getByRole("button", "Stop generation")).toBeHidden();
  await expect(screen.getByText("Working", { exact: true })).toBeHidden();
  await screen.getByRole("region", "Conversation", { exact: true }).getByText("Summarize these notes", { exact: true }).hover();
  await stableScreenshot("completed-prompt");
  const edit = screen.getByRole("button", "Edit from here").first();
  await expect(edit).toBeVisible();
  await edit.tap();
  await screen.getByRole("button", "Cancel", { exact: true }).focus();
  await browser.keyboard.press("Tab");
  await browser.keyboard.press("Shift+Tab");
  await stableScreenshot("dialog-cancel-focused");
  await browser.keyboard.press("Tab");
  await stableScreenshot("conversation-only-dialog");
  await expect(screen.getByRole("button", "Revert and keep changes")).toBeFocused();
  await expect(screen.getByRole("button", "Revert files too", { exact: true })).toBeDisabled();
  await screen.getByRole("button", "Revert and keep changes").tap();
  await expect(screen.getByTestId("composer-editor")).toHaveValue("Summarize these notes");
  await expect(screen.getByText("Suggest a follow-up", { exact: true })).toBeHidden();
  expect(await readFile(`${project}/notes.txt`, "utf8")).toBe("Keep these file contents.\nAn unsaved-to-Git edit.\n");
  await stableScreenshot("rewound-prompt-restored");
  await screen.getByRole("button", "Toggle terminal drawer").tap();
  const terminal = screen.getByRole("textbox", "Terminal input", { exact: true });
  await terminal.focus();
  await new Promise((resolve) => setTimeout(resolve, 1000));
  await terminal.fill("clear; printf '\\033[?25lFile: notes.txt\\n'; cat notes.txt; read -r");
  await terminal.press("Enter");
  await stableScreenshot("files-preserved");
  await screen.getByRole("button", "Toggle terminal drawer").tap();
  await screen.getByTestId("composer-editor").press("Enter");
  await expect(screen.getByText("first fixture turn complete", { exact: false })).toBeVisible();
  await expect(screen.getByRole("button", "Stop generation")).toBeHidden();
  await expect(screen.getByText("Working", { exact: true })).toBeHidden();
  await stableScreenshot("resent-complete");
  const route = new URL(await browser.url()).pathname;
  await browser.reload();
  await screen.getByRole("region", "Conversation", { exact: true }).getByText("Summarize these notes", { exact: true }).hover();
  await stableScreenshot("after-reload");
  await expect(screen.getByRole("button", "Edit from here").first()).toBeVisible();
  await app.clearState();
  await t3.open();
  await expect(screen.getByRole("button", "New thread", { exact: true })).toBeVisible();
  await app.open(route);
  await screen.getByRole("region", "Conversation", { exact: true }).getByText("Summarize these notes", { exact: true }).hover();
  await stableScreenshot("fresh-client");
  await expect(screen.getByRole("button", "Edit from here").first()).toBeVisible();
  const runtimeFile = `${T3_HOME}/userdata/server-runtime.json`;
  const beforeRestart = JSON.parse(await readFile(runtimeFile, "utf8")).pid;
  const { watch } = await import("node:fs");
  const restarted = new Promise<void>((resolve) => {
    const watcher = watch(`${T3_HOME}/userdata`, async (_event, name) => {
      if (name !== "server-runtime.json") return;
      try {
        const current = JSON.parse(await readFile(runtimeFile, "utf8"));
        if (current.pid !== beforeRestart) { watcher.close(); resolve(); }
      } catch {}
    });
  });
  const now = new Date();
  await utimes(`${APP_DIR}/apps/server/src/bin.ts`, now, now);
  await restarted;
  await app.clearState();
  await t3.open();
  await expect(screen.getByRole("button", "New thread", { exact: true })).toBeVisible();
  await app.open(route);
  await screen.getByRole("region", "Conversation", { exact: true }).getByText("Summarize these notes", { exact: true }).hover();
  await stableScreenshot("after-server-restart-fresh-client");
  await expect(screen.getByRole("button", "Edit from here").first()).toBeVisible();
  await screen.getByRole("button", "Edit from here").first().tap();
  await screen.getByRole("button", "Revert and keep changes").tap();
  await expect(screen.getByTestId("composer-editor")).toHaveValue("Summarize these notes");
  await stableScreenshot("second-rewind-after-restart");
  expect(await readFile(`${project}/notes.txt`, "utf8")).toBe("Keep these file contents.\nAn unsaved-to-Git edit.\n");
  } finally {
    await runPromise(cli(["project", "add", original, "--title", "Fixture setup"]));
  }
});
