import { describe, expect, test } from "vitest";

import { createGiteaHttpTransport, runPostRunGiteaLifecycle } from "./gitea";
import type { GitCommandRunner, GiteaTransport } from "./gitea";

const repository = {
  cloneUrl: "https://git.openputer.com/puter/zopu-code.git",
  defaultBranch: "main",
  htmlUrl: "https://git.openputer.com/puter/zopu-code",
  name: "zopu-code",
  sshUrl: "ssh://git@git.openputer.com:2222/puter/zopu-code.git",
};

const makeRunner = (): GitCommandRunner & { readonly commands: string[] } => {
  const commands: string[] = [];
  let statusCalls = 0;
  return {
    commands,
    run(command) {
      commands.push(command);
      if (command === "git branch --show-current") {
        return Promise.resolve({
          exitCode: 0,
          stderr: "",
          stdout: "work/issue-5\n",
        });
      }
      if (command === "git status --porcelain=v1") {
        statusCalls += 1;
        return Promise.resolve({
          exitCode: 0,
          stderr: "",
          stdout: statusCalls === 1 ? " M src/gitea.ts\n" : "",
        });
      }
      if (command === "git diff --no-ext-diff --binary") {
        return Promise.resolve({
          exitCode: 0,
          stderr: "",
          stdout: "diff --git ...",
        });
      }
      if (command === "git rev-parse HEAD") {
        return Promise.resolve({
          exitCode: 0,
          stderr: "",
          stdout: "abc123\n",
        });
      }
      if (command.includes("git status --porcelain=v1")) {
        return Promise.resolve({ exitCode: 0, stderr: "", stdout: "" });
      }
      return Promise.resolve({ exitCode: 0, stderr: "", stdout: "" });
    },
  };
};

describe("Gitea lifecycle adapter", () => {
  test("inspects, commits, pushes, and creates an open PR through mocked boundaries", async () => {
    const runner = makeRunner();
    const pullRequests: unknown[] = [];
    const transport: GiteaTransport = {
      createPullRequest(input) {
        pullRequests.push(input);
        return Promise.resolve({
          base: { ref: input.base },
          head: { ref: input.head },
          htmlUrl: "https://git.openputer.com/puter/zopu-code/pulls/5",
          number: 5,
          state: "open",
        });
      },
      getRepository() {
        return Promise.resolve(repository);
      },
    };

    const result = await runPostRunGiteaLifecycle({
      baseBranch: "main",
      body: "Generated by the verified project run.",
      issueNumber: 5,
      issueTitle: "Publish verified changes",
      repositoryPath: "puter/zopu-code",
      runner,
      transport,
      verification: "passed",
      workspace: "/workspace",
    });

    expect(result).toMatchObject({
      branch: "work/issue-5",
      commitSha: "abc123",
      pullRequest: {
        baseBranch: "main",
        branch: "work/issue-5",
        number: 5,
        status: "open",
      },
      status: "pull_request_open",
    });
    expect(runner.commands).toEqual([
      "git branch --show-current",
      "git status --porcelain=v1",
      "git diff --no-ext-diff --binary",
      "git add --all && git commit -m 'feat(issue-5): Publish verified changes'",
      "git rev-parse HEAD",
      "git status --porcelain=v1",
      "git push 'ssh://git@git.openputer.com:2222/puter/zopu-code.git' HEAD:'work/issue-5'",
    ]);
    expect(pullRequests).toHaveLength(1);
  });

  test("mocks the HTTP Gitea boundary without calling the network", async () => {
    const requests: Request[] = [];
    const transport = createGiteaHttpTransport({
      baseUrl: "https://git.openputer.com",
      fetch: (input, init) => {
        const request = new Request(String(input), init);
        requests.push(request);
        return Promise.resolve(
          new Response(
            request.method === "GET"
              ? JSON.stringify(repository)
              : JSON.stringify({
                  base: { ref: "main" },
                  head: { ref: "work/issue-5" },
                  html_url: "https://git.openputer.com/puter/zopu-code/pulls/5",
                  number: 5,
                  state: "open",
                }),
            { headers: { "content-type": "application/json" } }
          )
        );
      },
      token: "scoped-test-token",
    });

    await transport.getRepository("puter/zopu-code");
    await transport.createPullRequest({
      base: "main",
      body: "body",
      head: "work/issue-5",
      repositoryPath: "puter/zopu-code",
      title: "title",
    });

    expect(requests).toHaveLength(2);
    expect(requests[0]?.url).toBe(
      "https://git.openputer.com/api/v1/repos/puter/zopu-code"
    );
    expect(requests[1]?.headers.get("authorization")).toBe(
      "token scoped-test-token"
    );
  });
});
