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

test("Commit refuses notes.txt while its merge conflict remains unresolved", WEB, async ({ t3, app, screen, browser }) => {
  const project = await t3.project("sample-merge", { "notes.txt": "original note\n" });
  const git = (...args: string[]) => execFileSync("git", ["-c", "user.name=Scenario", "-c", "user.email=scenario@example.invalid", ...args], { cwd: project, encoding: "utf8" }).trim();
  git("checkout", "-b", "feature");
  writeFileSync(`${project}/notes.txt`, "feature note\n");
  git("commit", "-am", "Feature notes");
  git("checkout", "main");
  writeFileSync(`${project}/notes.txt`, "main note\n");
  git("commit", "-am", "Main notes");
  try { git("merge", "feature"); } catch { /* The fixture intentionally leaves an unmerged file. */ }
  const before = git("rev-parse", "HEAD");
  await t3.thread({ project, title: "Unresolved merge", messages: ["Show the repository summary"] });
  await t3.open();
  await screen.getByRole("button", "Unresolved merge, Done, sample-merge").tap();
  await screen.getByRole("button", "Git action options").tap();
  await screen.getByRole("menuitem", "Commit", { exact: true }).tap();
  await screen.getByPlaceholder("Leave empty to auto-generate").fill("Merge feature notes");
  // Redact the local checkout path in errors in both screenshots and recordings.
  await browser.evaluate(() => {
    new MutationObserver(() => {
      for (const element of document.querySelectorAll('[data-slot="toast-description"]')) {
        for (const child of element.childNodes) {
          if (child.nodeType === Node.TEXT_NODE && child.textContent?.includes("/home/")) {
            child.textContent = child.textContent.replace(/\(\/home\/[^)]*\)/g, "(repository)");
          }
        }
      }
    }).observe(document.body, { subtree: true, childList: true, characterData: true });
  });
  await new Promise((resolve) => setTimeout(resolve, 700));
  await app.screenshot("before-commit");
  await screen.getByRole("button", "Commit", { exact: true }).tap();
  // Both outcomes finish the same real request; capture before checking the refused-commit outcome.
  await expect(screen.getByText("Action failed", { exact: true }).or(screen.getByText("Committed", { exact: false }))).toBeVisible();
  await expect(screen.getByRole("dialog", "Commit changes")).toBeHidden();
  await new Promise((resolve) => setTimeout(resolve, 700));
  await app.screenshot("commit-result");
  await expect(screen.getByText("Cannot commit with unresolved merge conflicts in notes.txt. Resolve them, then commit.", { exact: false })).toBeVisible();
  expect(git("rev-parse", "HEAD")).toBe(before);
  expect(git("status", "--short")).toContain("UU notes.txt");
});
