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

test("Forgejo fast-forward-only pull requests can merge", WEB, async ({ t3, app, screen }) => {
  const scratch = process.env.PROOF_SCRATCH!;
  const origin = process.env.PROOF_FORGEJO_URL!;
  const user = process.env.PROOF_FORGEJO_USER!;
  const password = process.env.PROOF_FORGEJO_PASSWORD!;
  const auth = `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`;
  async function api(path: string, method = "GET", body?: unknown) {
    const response = await fetch(`${origin}/api/v1/${path}`, {
      method, headers: { Authorization: auth, "Content-Type": "application/json" },
      ...(body === undefined ? {} : { body: JSON.stringify(body) }),
    });
    if (response.status === 204) return null;
    if (!response.ok) throw new Error(`Forgejo fixture ${method} ${path}: ${response.status} ${await response.text()}`);
    return response.json();
  }
  writeFileSync(join(T3_HOME, "bin", "tea"), `#!/bin/sh\nexport XDG_CONFIG_HOME='${scratch}/config'\nexec '${scratch}/tea' "$@"\n`, { mode: 0o755 });
  const repo = `fast-forward-${Date.now()}`;
  await api("user/repos", "POST", { name: repo, default_branch: "main", auto_init: true, private: false });
  await api(`repos/${user}/${repo}`, "PATCH", {
    allow_merge_commits: false, allow_squash_merge: false, allow_rebase: false,
    allow_rebase_explicit: false, allow_fast_forward_only_merge: true,
  });
  const project = await t3.project("Fast-forward demo", { "README.md": "# Fast-forward demo\n" });
  const git = (...args: string[]) => execFileSync("git", args, { cwd: project, encoding: "utf8" });
  const remote = `${origin}/${user}/${repo}.git`;
  git("remote", "add", "origin", remote);
  git("-c", `http.extraHeader=Authorization: ${auth}`, "push", "--force", "-u", "origin", "main");
  git("checkout", "-b", "feature");
  writeFileSync(join(project, "feature.txt"), "A fast-forward merge preserves this commit.\n");
  git("add", "feature.txt");
  git("-c", "user.name=Scenario", "-c", "user.email=scenario@example.invalid", "commit", "-m", "Add fast-forward feature");
  git("-c", `http.extraHeader=Authorization: ${auth}`, "push", "-u", "origin", "feature");
  const head = git("rev-parse", "HEAD").trim();
  const pr = await api(`repos/${user}/${repo}/pulls`, "POST", {
    title: "Fast-forward only: preserve the existing head", head: "feature", base: "main",
    body: "This repository allows only fast-forward merges. The feature branch contains main.",
  });
  await t3.open();
  await screen.getByText("Fast-forward demo", { exact: true }).first().waitFor();
  await app.open("/pull-requests");
  await screen.getByText("Fast-forward only: preserve the existing head", { exact: true }).first().tap();
  await screen.getByText("This repository allows only fast-forward merges.", { exact: false }).first().waitFor();
  await app.screenshot("fast-forward-only-control");
  const merge = screen.getByRole("button", "Fast-forward merge", { exact: true });
  await expect(merge).toBeVisible();
  await merge.tap();
  await screen.getByRole("button", "Confirm merge?", { exact: true }).tap();
  await expect(screen.getByText("Merged", { exact: true }).first()).toBeVisible();
  await app.screenshot("fast-forward-merged");
  const merged = await api(`repos/${user}/${repo}/pulls/${pr.number}`);
  const base = await api(`repos/${user}/${repo}/branches/main`);
  expect(merged.merged).toBe(true);
  expect(base.commit.id).toBe(head);
});
