import assert from "node:assert/strict";
import { describe, it } from "node:test";

import { resolveBase } from "../git.ts";

describe("resolveBase", () => {
	it("uses explicit base ref when it exists", async () => {
		const calls: string[] = [];
		const pi = {
			exec: async (_cmd: string, args: string[]) => {
				calls.push(args.join(" "));
				return { code: args[2] === "release/1.2" ? 0 : 1, stdout: "", stderr: "" };
			},
		};

		const result = await resolveBase(pi as never, "/repo", "release/1.2");
		assert.deepEqual(result, { base: "release/1.2" });
		assert.deepEqual(calls, ["rev-parse --verify release/1.2"]);
	});

	it("defaults to remote/main when available", async () => {
		const pi = {
			exec: async (_cmd: string, args: string[]) => {
				const key = args.join(" ");
				if (key === "rev-parse --abbrev-ref HEAD") return { code: 0, stdout: "feature\n", stderr: "" };
				if (key === "for-each-ref --format=%(upstream:remotename) refs/heads/feature")
					return { code: 0, stdout: "origin\n", stderr: "" };
				if (key === "rev-parse --verify origin/main") return { code: 0, stdout: "abc\n", stderr: "" };
				return { code: 1, stdout: "", stderr: "" };
			},
		};

		const result = await resolveBase(pi as never, "/repo");
		assert.deepEqual(result, { base: "origin/main" });
	});

	it("uses custom remote name from upstream tracking", async () => {
		const pi = {
			exec: async (_cmd: string, args: string[]) => {
				const key = args.join(" ");
				if (key === "rev-parse --abbrev-ref HEAD") return { code: 0, stdout: "feature\n", stderr: "" };
				if (key === "for-each-ref --format=%(upstream:remotename) refs/heads/feature")
					return { code: 0, stdout: "upstream\n", stderr: "" };
				if (key === "rev-parse --verify upstream/main") return { code: 0, stdout: "abc\n", stderr: "" };
				return { code: 1, stdout: "", stderr: "" };
			},
		};

		const result = await resolveBase(pi as never, "/repo");
		assert.deepEqual(result, { base: "upstream/main" });
	});

	it("falls back to local main when no remote is available", async () => {
		const pi = {
			exec: async (_cmd: string, args: string[]) => {
				const key = args.join(" ");
				if (key === "rev-parse --abbrev-ref HEAD") return { code: 0, stdout: "feature\n", stderr: "" };
				if (key.startsWith("for-each-ref")) return { code: 0, stdout: "", stderr: "" };
				if (key === "remote") return { code: 0, stdout: "", stderr: "" };
				if (key === "rev-parse --verify main") return { code: 0, stdout: "abc\n", stderr: "" };
				return { code: 1, stdout: "", stderr: "" };
			},
		};

		const result = await resolveBase(pi as never, "/repo");
		assert.deepEqual(result, { base: "main" });
	});

	it("falls back to first remote when branch has no upstream", async () => {
		const pi = {
			exec: async (_cmd: string, args: string[]) => {
				const key = args.join(" ");
				if (key === "rev-parse --abbrev-ref HEAD") return { code: 0, stdout: "feature\n", stderr: "" };
				if (key.startsWith("for-each-ref")) return { code: 0, stdout: "", stderr: "" };
				if (key === "remote") return { code: 0, stdout: "myremote\n", stderr: "" };
				if (key === "rev-parse --verify myremote/master") return { code: 0, stdout: "abc\n", stderr: "" };
				return { code: 1, stdout: "", stderr: "" };
			},
		};

		const result = await resolveBase(pi as never, "/repo");
		assert.deepEqual(result, { base: "myremote/master" });
	});

	it("returns useful errors for missing explicit/default refs", async () => {
		const pi = {
			exec: async () => ({ code: 1, stdout: "", stderr: "missing" }),
		};

		const explicitResult = await resolveBase(pi as never, "/repo", "does-not-exist");
		assert.deepEqual(explicitResult, { error: 'Base ref "does-not-exist" does not exist' });

		const defaultResult = await resolveBase(pi as never, "/repo");
		assert.match((defaultResult as { error: string }).error, /Neither "main" nor "master" exists/);
	});
});
