import { describe, expect, it } from "vitest";
import {
	extractCommitMessage,
	extractImageName,
	extractImageTag,
	extractImageTagFromRequest,
} from "@/pages/api/deploy/[refreshToken]";

describe("GitHub Webhook Skip CI", () => {
	const mockGithubHeaders = {
		"x-github-event": "push",
	};

	const createMockBody = (message: string) => ({
		head_commit: {
			message,
		},
	});

	const skipKeywords = [
		"[skip ci]",
		"[ci skip]",
		"[no ci]",
		"[skip actions]",
		"[actions skip]",
	];

	it("should detect skip keywords in commit message", () => {
		for (const keyword of skipKeywords) {
			const message = `feat: add new feature ${keyword}`;
			const commitMessage = extractCommitMessage(
				mockGithubHeaders,
				createMockBody(message),
			);
			expect(commitMessage.includes(keyword)).toBe(true);
		}
	});

	it("should not detect skip keywords in normal commit message", () => {
		const message = "feat: add new feature";
		const commitMessage = extractCommitMessage(
			mockGithubHeaders,
			createMockBody(message),
		);
		for (const keyword of skipKeywords) {
			expect(commitMessage.includes(keyword)).toBe(false);
		}
	});

	it("should handle different webhook sources", () => {
		// GitHub
		expect(
			extractCommitMessage(
				{ "x-github-event": "push" },
				{ head_commit: { message: "[skip ci] test" } },
			),
		).toBe("[skip ci] test");

		// GitLab
		expect(
			extractCommitMessage(
				{ "x-gitlab-event": "push" },
				{ commits: [{ message: "[skip ci] test" }] },
			),
		).toBe("[skip ci] test");

		// Bitbucket
		expect(
			extractCommitMessage(
				{ "x-event-key": "repo:push" },
				{
					push: {
						changes: [{ new: { target: { message: "[skip ci] test" } } }],
					},
				},
			),
		).toBe("[skip ci] test");

		// Gitea
		expect(
			extractCommitMessage(
				{ "x-gitea-event": "push" },
				{ commits: [{ message: "[skip ci] test" }] },
			),
		).toBe("[skip ci] test");

		// Soft Serve
		expect(
			extractCommitMessage(
				{ "x-softserve-event": "push" },
				{ commits: [{ message: "[skip ci] test" }] },
			),
		).toBe("[skip ci] test");
	});

	it("should handle missing commit message", () => {
		expect(extractCommitMessage(mockGithubHeaders, {})).toBe("NEW COMMIT");
		expect(extractCommitMessage({ "x-gitlab-event": "push" }, {})).toBe(
			"NEW COMMIT",
		);
		expect(
			extractCommitMessage(
				{ "x-event-key": "repo:push" },
				{ push: { changes: [] } },
			),
		).toBe("NEW COMMIT");
		expect(extractCommitMessage({ "x-gitea-event": "push" }, {})).toBe(
			"NEW COMMIT",
		);
		expect(extractCommitMessage({ "x-softserve-event": "push" }, {})).toBe(
			"NEW COMMIT",
		);
	});
});

describe("GitHub Packages Docker Image Tag Extraction", () => {
	it("should extract tag from container_metadata", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {
				package_version: {
					version: "sha256:abc123...",
					container_metadata: {
						tag: {
							name: "v1.0.0",
							digest: "sha256:abc123...",
						},
					},
					package_url: "ghcr.io/owner/repo:v1.0.0",
				},
			},
		};

		const tag = extractImageTagFromRequest(headers, body);
		expect(tag).toBe("v1.0.0");
	});

	it("should extract tag from package_url when container_metadata tag matches version", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {
				package_version: {
					version: "sha256:abc123...",
					container_metadata: {
						tag: {
							name: "sha256:abc123...",
							digest: "sha256:abc123...",
						},
					},
					package_url: "ghcr.io/owner/repo:latest",
				},
			},
		};

		const tag = extractImageTagFromRequest(headers, body);
		expect(tag).toBe("latest");
	});

	it("should extract tag from package_url when container_metadata is missing", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {
				package_version: {
					version: "sha256:abc123...",
					package_url: "ghcr.io/owner/repo:1.2.3",
				},
			},
		};

		const tag = extractImageTagFromRequest(headers, body);
		expect(tag).toBe("1.2.3");
	});

	it("should handle different tag formats in package_url", () => {
		const headers = { "x-github-event": "registry_package" };
		const testCases = [
			{ url: "ghcr.io/owner/repo:latest", expected: "latest" },
			{ url: "ghcr.io/owner/repo:v1.0.0", expected: "v1.0.0" },
			{ url: "ghcr.io/owner/repo:1.2.3", expected: "1.2.3" },
			{ url: "ghcr.io/owner/repo:dev", expected: "dev" },
		];

		for (const testCase of testCases) {
			const body = {
				registry_package: {
					package_version: {
						version: "sha256:abc123...",
						package_url: testCase.url,
					},
				},
			};

			const tag = extractImageTagFromRequest(headers, body);
			expect(tag).toBe(testCase.expected);
		}
	});

	it("should return null for non-registry_package events", () => {
		const headers = { "x-github-event": "push" };
		const body = {
			registry_package: {
				package_version: {
					package_url: "ghcr.io/owner/repo:latest",
				},
			},
		};

		const tag = extractImageTagFromRequest(headers, body);
		expect(tag).toBeNull();
	});

	it("should return null when package_version is missing", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {},
		};

		const tag = extractImageTagFromRequest(headers, body);
		expect(tag).toBeNull();
	});

	it("should return null when package_url has no tag", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {
				package_version: {
					version: "sha256:abc123...",
					package_url: "ghcr.io/owner/repo",
				},
			},
		};

		const tag = extractImageTagFromRequest(headers, body);
		expect(tag).toBeNull();
	});

	it("should return null when package_url ends with colon (no tag)", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {
				package_version: {
					version: "sha256:abc123...",
					package_url: "ghcr.io/owner/repo:",
					container_metadata: {
						tag: {
							name: "",
							digest: "sha256:abc123...",
						},
					},
				},
			},
		};

		const tag = extractImageTagFromRequest(headers, body);
		expect(tag).toBeNull();
	});

	it("should return null when tag name is empty string", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {
				package_version: {
					version: "sha256:abc123...",
					container_metadata: {
						tag: {
							name: "",
							digest: "sha256:abc123...",
						},
					},
					package_url: "ghcr.io/owner/repo:",
				},
			},
		};

		const tag = extractImageTagFromRequest(headers, body);
		expect(tag).toBeNull();
	});

	it("should ignore tag if it matches the version (digest)", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {
				package_version: {
					version: "sha256:abc123...",
					container_metadata: {
						tag: {
							name: "sha256:abc123...",
							digest: "sha256:abc123...",
						},
					},
					package_url: "ghcr.io/owner/repo:latest",
				},
			},
		};

		const tag = extractImageTagFromRequest(headers, body);
		expect(tag).toBe("latest");
	});

	it("should handle registry_package commit message with package_url", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {
				package_version: {
					package_url: "ghcr.io/owner/repo:latest",
				},
			},
		};

		const message = extractCommitMessage(headers, body);
		expect(message).toBe("Docker GHCR image pushed: ghcr.io/owner/repo:latest");
	});

	it("should handle registry_package commit message when package_url is missing", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {
				package_version: {
					version: "sha256:abc123...",
				},
			},
		};

		const message = extractCommitMessage(headers, body);
		expect(message).toBe("Docker GHCR image pushed");
	});

	it("should handle registry_package commit message when package_version is missing", () => {
		const headers = { "x-github-event": "registry_package" };
		const body = {
			registry_package: {},
		};

		const message = extractCommitMessage(headers, body);
		expect(message).toBe("NEW COMMIT");
	});
});

describe("Docker Image Name and Tag Extraction", () => {
	describe("extractImageName", () => {
		it("should return image name without tag", () => {
			expect(extractImageName("my-image:latest")).toBe("my-image");
			expect(extractImageName("my-image:1.0.0")).toBe("my-image");
			expect(extractImageName("ghcr.io/owner/repo:latest")).toBe(
				"ghcr.io/owner/repo",
			);
		});

		it("should return full image name when no tag is present", () => {
			expect(extractImageName("my-image")).toBe("my-image");
			expect(extractImageName("ghcr.io/owner/repo")).toBe("ghcr.io/owner/repo");
		});

		it("should handle images with port numbers correctly", () => {
			expect(extractImageName("registry:5000/image:tag")).toBe(
				"registry:5000/image",
			);
			expect(extractImageName("localhost:5000/my-app:latest")).toBe(
				"localhost:5000/my-app",
			);
		});

		it("should handle complex image paths", () => {
			expect(
				extractImageName("myregistryhost:5000/fedora/httpd:version1.0"),
			).toBe("myregistryhost:5000/fedora/httpd");
			expect(extractImageName("registry.example.com:8080/ns/app:v1.2.3")).toBe(
				"registry.example.com:8080/ns/app",
			);
		});

		it("should return null for invalid inputs", () => {
			expect(extractImageName(null)).toBeNull();
			expect(extractImageName("")).toBeNull();
		});

		it("should handle edge cases with multiple colons", () => {
			expect(extractImageName("image:tag:extra")).toBe("image:tag");
			expect(extractImageName("registry:5000:invalid")).toBe("registry:5000");
		});
	});

	describe("extractImageTag", () => {
		it("should extract tag from image with tag", () => {
			expect(extractImageTag("my-image:latest")).toBe("latest");
			expect(extractImageTag("my-image:1.0.0")).toBe("1.0.0");
			expect(extractImageTag("ghcr.io/owner/repo:v1.2.3")).toBe("v1.2.3");
		});

		it("should return 'latest' when no tag is present", () => {
			expect(extractImageTag("my-image")).toBe("latest");
			expect(extractImageTag("ghcr.io/owner/repo")).toBe("latest");
		});

		it("should handle complex image paths with tags", () => {
			expect(
				extractImageTag("myregistryhost:5000/fedora/httpd:version1.0"),
			).toBe("version1.0");
			expect(extractImageTag("registry.example.com:8080/ns/app:v1.2.3")).toBe(
				"v1.2.3",
			);
		});

		it("should return null for invalid inputs", () => {
			expect(extractImageTag(null)).toBeNull();
			expect(extractImageTag("")).toBeNull();
		});

		it("should handle edge cases with multiple colons", () => {
			expect(extractImageTag("image:tag:extra")).toBe("extra");
			expect(extractImageTag("registry:5000/image:tag")).toBe("tag");
		});

		it("should handle numeric tags", () => {
			expect(extractImageTag("my-image:123")).toBe("123");
			expect(extractImageTag("my-image:1")).toBe("1");
		});

		it("should return 'latest' for registry with port but no tag", () => {
			expect(extractImageTag("registry.example.com:5000/myimage")).toBe(
				"latest",
			);
			expect(extractImageTag("registry:5000/fedora/httpd")).toBe("latest");
			expect(extractImageTag("localhost:5000/myapp")).toBe("latest");
			expect(extractImageTag("my-registry.io:443/org/app")).toBe("latest");
		});

		it("should extract tag from registry with port and tag", () => {
			expect(extractImageTag("registry:5000/image:tag")).toBe("tag");
			expect(extractImageTag("registry.example.com:5000/myimage:v2.0")).toBe(
				"v2.0",
			);
			expect(extractImageTag("localhost:5000/app:sha-abc123")).toBe(
				"sha-abc123",
			);
		});
	});
});
