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

test("Disabled Push explains outgoing commits and upstream divergence despite local edits", WEB, async ({ t3, app, screen, browser }) => {
  const reasons: string[] = [];
  for (const state of ["in-sync-dirty", "behind-dirty", "diverged-dirty", "ahead-dirty-push-enabled"]) {
    // Prepare each state before opening it so cached status cannot describe an earlier state.
    const project = await t3.project(state, { "README.md": "Push tooltip example\n" });
    const git = (...args: string[]) => execFileSync("git", args, { cwd: project, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
    const commit = (...args: string[]) => git("-c", "user.name=Scenario", "-c", "user.email=scenario@example.invalid", ...args);
    const remote = `${project}-remote.git`;
    git("init", "--bare", "--initial-branch=main", remote);
    git("checkout", "-b", "feature");
    commit("commit", "--allow-empty", "-m", "Feature commit");
    git("remote", "add", "origin", remote);
    git("push", "-u", "origin", "main", "feature");
    writeFileSync(`${project}/README.md`, "Push tooltip example\nUncommitted local edit\n");
    if (state !== "in-sync-dirty") {
      const second = `${project}-second`;
      git("clone", "--branch", "feature", remote, second);
      execFileSync("git", ["-c", "user.name=Scenario", "-c", "user.email=scenario@example.invalid", "commit", "--allow-empty", "-m", "Upstream commit"], { cwd: second, stdio: "pipe" });
      execFileSync("git", ["push"], { cwd: second, stdio: "pipe" });
      git("fetch", "origin");
    }
    if (state === "diverged-dirty" || state === "ahead-dirty-push-enabled") {
      writeFileSync(`${project}/local.txt`, "Local commit\n");
      git("add", "local.txt");
      commit("commit", "-m", "Local commit");
    }
    if (state === "ahead-dirty-push-enabled") {
      git("stash", "push");
      git("rebase", "origin/feature");
      git("stash", "pop");
    }
    console.log(state, git("status", "--short", "--branch"));
    const thread = await t3.thread({ project, title: state, messages: ["Start"] });
    await t3.open(thread);
    await screen.getByRole("button", "Git action options").tap();
    const push = screen.getByRole("menuitem", "Push", { exact: true });
    if (state === "ahead-dirty-push-enabled") {
      await expect(push).toBeEnabled();
    } else {
      await push.hover();
      const reason = screen.getByText(/Commit or stash local changes before pushing\.|No local commits to push\.|Branch is behind upstream\. Pull\/rebase before pushing\./);
      await reason.waitFor({ state: "visible" });
      reasons.push(await reason.textContent());
    }
    await app.screenshot(state);
    await browser.keyboard.press("Escape");
  }
  await expect(reasons).toEqual([
    "No local commits to push.",
    "Branch is behind upstream. Pull/rebase before pushing.",
    "Branch is behind upstream. Pull/rebase before pushing.",
  ]);
});
