import { execFileSync, spawn } from "node:child_process";
import { mkdtempSync, mkdirSync, writeFileSync } from "node:fs";
import { createServer } from "node:http";
import { join } from "node:path";
import { expect } from "e2e";
import { test, WEB } from "./t3.ts";

test("A draft opened during cloning adopts staging as its worktree base", WEB, async ({ t3, app, screen }) => {
  const root = mkdtempSync(join(process.env.PROOF_SCRATCH!, "clone-"));
  const source = join(root, "source");
  mkdirSync(source);
  const git = (args: string[], cwd = source) => execFileSync("git", args, { cwd, encoding: "utf8" });
  git(["init", "-q", "-b", "staging"]);
  writeFileSync(join(source, "README.md"), "# Clone demonstration\n");
  git(["add", "."]);
  git(["-c", "user.name=Scenario", "-c", "user.email=scenario@example.invalid", "commit", "-qm", "Initial staging commit"]);
  git(["clone", "--bare", source, join(root, "demo.git")]);
  let release!: () => void;
  const gate = new Promise<void>((resolve) => { release = resolve; });
  let uploading!: () => void;
  const uploadStarted = new Promise<void>((resolve) => { uploading = resolve; });
  const server = createServer(async (req, res) => {
    const url = new URL(req.url!, "http://localhost");
    if (req.method === "POST") { uploading(); await gate; }
    const child = spawn("git", ["http-backend"], { env: {
      ...process.env, GIT_PROJECT_ROOT: root, GIT_HTTP_EXPORT_ALL: "1",
      PATH_INFO: url.pathname, QUERY_STRING: url.search.slice(1),
      REQUEST_METHOD: req.method!, CONTENT_TYPE: req.headers["content-type"] ?? "",
      CONTENT_LENGTH: req.headers["content-length"] ?? "", SERVER_PROTOCOL: "HTTP/1.1",
    }});
    req.pipe(child.stdin);
    const chunks: Buffer[] = [];
    child.stdout.on("data", (chunk) => chunks.push(chunk));
    child.on("close", () => {
      const output = Buffer.concat(chunks);
      const split = output.indexOf("\r\n\r\n");
      const headers = output.subarray(0, split).toString();
      for (const line of headers.split("\r\n")) {
        const colon = line.indexOf(":");
        if (colon > 0) res.setHeader(line.slice(0, colon), line.slice(colon + 1).trim());
      }
      res.end(output.subarray(split + 4));
    });
  });
  await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
  const address = server.address() as { port: number };
  try {
    const welcome = await t3.project("Welcome");
    await t3.open();
    await screen.getByRole("button", "Add project").tap();
    await screen.getByText("Git URL", { exact: true }).tap();
    await screen.getByRole("combobox").fill(`http://127.0.0.1:${address.port}/demo.git`);
    await screen.getByRole("button", "Continue (Enter)").tap();
    await screen.getByRole("combobox").fill("./Staging demo");
    await screen.getByRole("button", "Create & Clone (Enter)").tap();
    await uploadStarted;
    await screen.getByRole("combobox", "Workspace").tap();
    await screen.getByRole("option", "New worktree").tap();
    await new Promise((resolve) => setTimeout(resolve, 3000));
    await app.screenshot("during-clone");
    release();
    await screen.getByText("Cloning Staging demo", { exact: false }).waitFor({ state: "hidden", timeout: 60000 });
    // Allow clone completion and the same post-clone observation period on both revisions.
    await new Promise((resolve) => setTimeout(resolve, 18000));
    console.log("Clone refs:", git(["branch", "-a"], join(welcome, "Staging demo")));
    await app.screenshot("completed-clone-base-picker");
    await expect(screen.getByText("From staging (remote)", { exact: true }).first()).toBeVisible();
    await screen.getByRole("textbox").fill("go");
    await screen.getByRole("textbox").press("Enter");
    await expect(screen.getByText("This turn is a replay.", { exact: false })).toBeVisible({ timeout: 90000 });
    await app.screenshot("worktree-created");
  } finally {
    release();
    await new Promise<void>((resolve) => server.close(() => resolve()));
  }
});
