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

test("Selected-file commit preserves a conflicted sequencer-only cherry-pick", WEB, async ({ t3, app, screen, browser }) => {
  const project = await t3.project("Cherry-pick conflict", { "README.md": "base\n" });
  const git = (...args: string[]) => execFileSync("git", args, { cwd: project, encoding: "utf8" });
  git("config", "user.name", "Scenario");
  git("config", "user.email", "scenario@example.invalid");
  git("checkout", "-b", "other");
  writeFileSync(`${project}/README.md`, "other\n");
  writeFileSync(`${project}/first.txt`, "first\n");
  git("add", "."); git("commit", "-m", "first");
  writeFileSync(`${project}/second.txt`, "second\n");
  git("add", "."); git("commit", "-m", "second");
  git("checkout", "main");
  writeFileSync(`${project}/README.md`, "mainchange\n");
  git("add", "."); git("commit", "-m", "mainchange");
  try { git("cherry-pick", "--no-commit", "other~1", "other"); } catch { /* expected conflict */ }
  const state = () => ({
    head: git("rev-parse", "HEAD"),
    index: readFileSync(`${project}/.git/index`).toString("base64"),
    unmerged: git("ls-files", "-u"),
    sequencer: readdirSync(`${project}/.git/sequencer`).sort().map(name => [name, readFileSync(`${project}/.git/sequencer/${name}`, "utf8")]),
  });
  const before = state();
  const thread = await t3.thread({ project, title: "Commit first.txt only", messages: ["first"] });
  await t3.open(thread);
  await screen.getByRole("button", "Git action options").tap();
  await screen.getByRole("menuitem", "Commit", { exact: true }).tap();
  await screen.getByRole("button", "Edit", { exact: true }).tap();
  await screen.getByRole("checkbox").nth(2).tap();
  await screen.getByPlaceholder("Leave empty to auto-generate").fill("Add first.txt only");
  await app.screenshot("selected-files");
  await browser.evaluate((repositoryPath) => {
    const redact = () => {
      const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
      for (let node = walker.nextNode(); node; node = walker.nextNode()) {
        if (node.textContent?.includes(repositoryPath)) node.textContent = node.textContent.replaceAll(repositoryPath, "[repository path redacted]");
      }
    };
    new MutationObserver(redact).observe(document.body, { childList: true, subtree: true, characterData: true });
    redact();
  }, project);
  await screen.getByRole("button", "Commit", { exact: true }).tap();
  await browser.evaluate(() => new Promise<void>((resolve, reject) => {
    const done = () => /Action failed|Committed|Commit created|Created commit/.test(document.body.innerText);
    if (done()) return resolve();
    const observer = new MutationObserver(() => { if (done()) { observer.disconnect(); resolve(); } });
    observer.observe(document.body, { childList: true, subtree: true, characterData: true });
    setTimeout(() => { observer.disconnect(); reject(new Error("Commit result did not appear")); }, 30000);
  }));
  await browser.evaluate(() => new Promise(resolve => setTimeout(resolve, 1000)));
  await app.screenshot("commit-result");
  await expect(state()).toEqual(before);
});
