import { describe, expect, it } from "bun:test";
import {
	sanitizeAppName,
	getAppFileName,
	getBundleFileName,
	getPlatformPrefix,
	getTarballFileName,
	getWindowsSetupFileName,
	getLinuxAppImageBaseName,
	getLinuxAppImageFileName,
	sanitizeVolumeNameForHdiutil,
	getDmgVolumeName,
	getUpdateInfoUrl,
	getPatchFileUrl,
	getTarballUrl,
} from "./naming";

describe("sanitizeAppName", () => {
	it("removes spaces from app name", () => {
		expect(sanitizeAppName("My App")).toBe("MyApp");
		expect(sanitizeAppName("My  Multi  Spaced  App")).toBe("MyMultiSpacedApp");
	});

	it("preserves names without spaces", () => {
		expect(sanitizeAppName("MyApp")).toBe("MyApp");
	});

	it("handles empty string", () => {
		expect(sanitizeAppName("")).toBe("");
	});
});

describe("getAppFileName", () => {
	it("returns sanitized name without suffix for stable builds", () => {
		expect(getAppFileName("My App", "stable")).toBe("MyApp");
	});

	it("appends channel suffix for canary builds", () => {
		expect(getAppFileName("My App", "canary")).toBe("MyApp-canary");
	});

	it("appends channel suffix for dev builds", () => {
		expect(getAppFileName("My App", "dev")).toBe("MyApp-dev");
	});

	it("handles custom channels", () => {
		expect(getAppFileName("My App", "beta")).toBe("MyApp-beta");
		expect(getAppFileName("My App", "nightly")).toBe("MyApp-nightly");
	});
});

describe("getBundleFileName", () => {
	describe("macOS", () => {
		it("adds .app extension for stable builds", () => {
			expect(getBundleFileName("My App", "stable", "macos")).toBe("MyApp.app");
		});

		it("adds .app extension for canary builds", () => {
			expect(getBundleFileName("My App", "canary", "macos")).toBe(
				"MyApp-canary.app",
			);
		});
	});

	describe("Windows", () => {
		it("returns plain name for stable builds", () => {
			expect(getBundleFileName("My App", "stable", "win")).toBe("MyApp");
		});

		it("returns plain name with suffix for canary builds", () => {
			expect(getBundleFileName("My App", "canary", "win")).toBe("MyApp-canary");
		});
	});

	describe("Linux", () => {
		it("returns plain name for stable builds", () => {
			expect(getBundleFileName("My App", "stable", "linux")).toBe("MyApp");
		});

		it("returns plain name with suffix for canary builds", () => {
			expect(getBundleFileName("My App", "canary", "linux")).toBe(
				"MyApp-canary",
			);
		});
	});
});

describe("getPlatformPrefix", () => {
	it("constructs correct prefix format for all platform combinations", () => {
		expect(getPlatformPrefix("stable", "macos", "arm64")).toBe(
			"stable-macos-arm64",
		);
		expect(getPlatformPrefix("stable", "macos", "x64")).toBe(
			"stable-macos-x64",
		);
		expect(getPlatformPrefix("canary", "win", "x64")).toBe("canary-win-x64");
		expect(getPlatformPrefix("dev", "linux", "arm64")).toBe("dev-linux-arm64");
		expect(getPlatformPrefix("dev", "linux", "x64")).toBe("dev-linux-x64");
	});
});

describe("getTarballFileName", () => {
	describe("macOS", () => {
		it("uses .app.tar.gz extension", () => {
			expect(getTarballFileName("MyApp", "macos")).toBe("MyApp.app.tar.gz");
		});

		it("preserves channel suffix in filename", () => {
			expect(getTarballFileName("MyApp-canary", "macos")).toBe(
				"MyApp-canary.app.tar.gz",
			);
		});
	});

	describe("Windows", () => {
		it("uses .tar.gz extension", () => {
			expect(getTarballFileName("MyApp", "win")).toBe("MyApp.tar.gz");
		});

		it("preserves channel suffix in filename", () => {
			expect(getTarballFileName("MyApp-canary", "win")).toBe(
				"MyApp-canary.tar.gz",
			);
		});
	});

	describe("Linux", () => {
		it("uses .tar.gz extension", () => {
			expect(getTarballFileName("MyApp", "linux")).toBe("MyApp.tar.gz");
		});

		it("preserves channel suffix in filename", () => {
			expect(getTarballFileName("MyApp-canary", "linux")).toBe(
				"MyApp-canary.tar.gz",
			);
		});
	});
});

describe("getWindowsSetupFileName", () => {
	it("returns AppName.exe for stable builds", () => {
		expect(getWindowsSetupFileName("MyApp", "stable")).toBe("MyApp.exe");
	});

	it("includes channel suffix for canary builds", () => {
		expect(getWindowsSetupFileName("MyApp", "canary")).toBe(
			"MyApp-canary.exe",
		);
	});

	it("includes channel suffix for dev builds", () => {
		expect(getWindowsSetupFileName("MyApp", "dev")).toBe("MyApp-dev.exe");
	});

	it("preserves spaces in app name", () => {
		expect(getWindowsSetupFileName("My App", "stable")).toBe(
			"My App.exe",
		);
		expect(getWindowsSetupFileName("My App", "canary")).toBe(
			"My App-canary.exe",
		);
	});
});

describe("getLinuxAppImageBaseName", () => {
	it("returns AppName-Setup for stable builds", () => {
		expect(getLinuxAppImageBaseName("MyApp", "stable")).toBe("MyApp-Setup");
	});

	it("includes channel suffix for canary builds", () => {
		expect(getLinuxAppImageBaseName("MyApp", "canary")).toBe(
			"MyApp-Setup-canary",
		);
	});

	it("preserves spaces in app name", () => {
		expect(getLinuxAppImageBaseName("My App", "stable")).toBe("My App-Setup");
		expect(getLinuxAppImageBaseName("My App", "canary")).toBe(
			"My App-Setup-canary",
		);
	});
});

describe("getLinuxAppImageFileName", () => {
	it("returns full filename with .AppImage extension for stable", () => {
		expect(getLinuxAppImageFileName("MyApp", "stable")).toBe(
			"MyApp-Setup.AppImage",
		);
	});

	it("returns full filename with .AppImage extension for canary", () => {
		expect(getLinuxAppImageFileName("MyApp", "canary")).toBe(
			"MyApp-Setup-canary.AppImage",
		);
	});

	it("preserves spaces in app name", () => {
		expect(getLinuxAppImageFileName("My App", "stable")).toBe(
			"My App-Setup.AppImage",
		);
		expect(getLinuxAppImageFileName("My App", "canary")).toBe(
			"My App-Setup-canary.AppImage",
		);
	});
});

describe("sanitizeVolumeNameForHdiutil", () => {
	it("removes special characters", () => {
		expect(sanitizeVolumeNameForHdiutil("My-App_v1.0")).toBe("MyAppv10");
	});

	it("removes parentheses and other punctuation", () => {
		expect(sanitizeVolumeNameForHdiutil("My App (Beta)")).toBe("My App Beta");
	});

	it("preserves spaces and alphanumerics", () => {
		expect(sanitizeVolumeNameForHdiutil("My App 2024")).toBe("My App 2024");
	});

	it("trims leading and trailing whitespace", () => {
		expect(sanitizeVolumeNameForHdiutil("  My App  ")).toBe("My App");
	});

	it("handles names with only special characters", () => {
		expect(sanitizeVolumeNameForHdiutil("---")).toBe("");
	});
});

describe("getDmgVolumeName", () => {
	it("returns plain name for stable builds", () => {
		expect(getDmgVolumeName("MyApp", "stable")).toBe("MyApp");
	});

	it("adds channel suffix for non-stable builds", () => {
		expect(getDmgVolumeName("MyApp", "canary")).toBe("MyApp-canary");
	});

	it("sanitizes special characters", () => {
		expect(getDmgVolumeName("My-App", "stable")).toBe("MyApp");
		expect(getDmgVolumeName("My-App", "canary")).toBe("MyApp-canary");
	});
});

describe("URL construction functions", () => {
	const baseUrl = "https://storage.example.com/releases";
	const platformPrefix = "canary-macos-arm64";

	describe("getUpdateInfoUrl", () => {
		it("constructs correct flat URL with prefix", () => {
			expect(getUpdateInfoUrl(baseUrl, platformPrefix)).toBe(
				"https://storage.example.com/releases/canary-macos-arm64-update.json",
			);
		});

		it("handles bucket URLs with trailing content", () => {
			expect(
				getUpdateInfoUrl("https://example.com/bucket", "stable-win-x64"),
			).toBe("https://example.com/bucket/stable-win-x64-update.json");
		});
	});

	describe("getPatchFileUrl", () => {
		it("constructs correct flat URL with prefix and hash", () => {
			expect(getPatchFileUrl(baseUrl, platformPrefix, "abc123def456")).toBe(
				"https://storage.example.com/releases/canary-macos-arm64-abc123def456.patch",
			);
		});
	});

	describe("getTarballUrl", () => {
		it("constructs correct flat URL for macOS tarball", () => {
			expect(getTarballUrl(baseUrl, platformPrefix, "MyApp.app.tar.gz")).toBe(
				"https://storage.example.com/releases/canary-macos-arm64-MyApp.app.tar.gz",
			);
		});

		it("constructs correct flat URL for Windows tarball", () => {
			expect(getTarballUrl(baseUrl, "stable-win-x64", "MyApp.tar.gz")).toBe(
				"https://storage.example.com/releases/stable-win-x64-MyApp.tar.gz",
			);
		});
	});
});

// Integration tests that verify CLI and Updater would produce matching values
describe("CLI and Updater consistency", () => {
	it("produces matching platform prefixes", () => {
		// CLI uses: `${buildEnvironment}-${currentTarget.os}-${currentTarget.arch}`
		// Updater uses: `${localInfo.channel}-${currentOS}-${currentArch}`
		// Both should use getPlatformPrefix()
		const cliResult = getPlatformPrefix("canary", "macos", "arm64");
		const updaterResult = getPlatformPrefix("canary", "macos", "arm64");
		expect(cliResult).toBe(updaterResult);
		expect(cliResult).toBe("canary-macos-arm64");
	});

	it("produces matching tarball names for macOS", () => {
		const appFileName = getAppFileName("My App", "canary");
		const tarballName = getTarballFileName(appFileName, "macos");
		expect(tarballName).toBe("MyApp-canary.app.tar.gz");
	});

	it("produces matching tarball names for Windows", () => {
		const appFileName = getAppFileName("My App", "stable");
		const tarballName = getTarballFileName(appFileName, "win");
		expect(tarballName).toBe("MyApp.tar.gz");
	});

	it("produces matching tarball names for Linux", () => {
		const appFileName = getAppFileName("My App", "dev");
		const tarballName = getTarballFileName(appFileName, "linux");
		expect(tarballName).toBe("MyApp-dev.tar.gz");
	});

	it("stable builds have no channel suffix in artifact names", () => {
		// This is the regression test for the -stable bug
		expect(getAppFileName("MyApp", "stable")).toBe("MyApp");
		expect(getAppFileName("MyApp", "stable")).not.toContain("-stable");
		expect(getTarballFileName(getAppFileName("MyApp", "stable"), "macos")).toBe(
			"MyApp.app.tar.gz",
		);
		expect(getWindowsSetupFileName("MyApp", "stable")).toBe("MyApp.exe");
		expect(getLinuxAppImageFileName("MyApp", "stable")).toBe(
			"MyApp-Setup.AppImage",
		);
	});
});
