import { describe, expect, it, vi } from "vitest";

const envMock = vi.hoisted(() => ({
	GOOGLE_CLIENT_ID: undefined as string | undefined,
	GOOGLE_CLIENT_SECRET: undefined as string | undefined,
	GITHUB_CLIENT_ID: undefined as string | undefined,
	GITHUB_CLIENT_SECRET: undefined as string | undefined,
	LINKEDIN_CLIENT_ID: undefined as string | undefined,
	LINKEDIN_CLIENT_SECRET: undefined as string | undefined,
	OAUTH_CLIENT_ID: undefined as string | undefined,
	OAUTH_CLIENT_SECRET: undefined as string | undefined,
	OAUTH_PROVIDER_NAME: undefined as string | undefined,
}));

vi.mock("@reactive-resume/env/server", () => ({ env: envMock }));
// auth.ts also imports db client and storage; stub them with no-op surfaces.
vi.mock("@reactive-resume/db/client", () => ({ db: { delete: vi.fn() } }));
vi.mock("@reactive-resume/db/schema", () => ({ user: {} }));
vi.mock("../storage/service", () => ({ getStorageService: () => ({ delete: vi.fn() }) }));

const { authService } = await import("./service");

const resetEnv = () => {
	envMock.GOOGLE_CLIENT_ID = undefined;
	envMock.GOOGLE_CLIENT_SECRET = undefined;
	envMock.GITHUB_CLIENT_ID = undefined;
	envMock.GITHUB_CLIENT_SECRET = undefined;
	envMock.LINKEDIN_CLIENT_ID = undefined;
	envMock.LINKEDIN_CLIENT_SECRET = undefined;
	envMock.OAUTH_CLIENT_ID = undefined;
	envMock.OAUTH_CLIENT_SECRET = undefined;
	envMock.OAUTH_PROVIDER_NAME = undefined;
};

describe("authService.providers.list", () => {
	it("always includes credential and passkey providers", () => {
		resetEnv();
		const providers = authService.providers.list();
		expect(providers.credential).toBe("Password");
		expect(providers.passkey).toBe("Passkey");
	});

	it("omits social providers when credentials are not configured", () => {
		resetEnv();
		const providers = authService.providers.list();
		expect(providers.google).toBeUndefined();
		expect(providers.github).toBeUndefined();
		expect(providers.linkedin).toBeUndefined();
		expect(providers.custom).toBeUndefined();
	});

	it("includes Google when both client id and secret are present", () => {
		resetEnv();
		envMock.GOOGLE_CLIENT_ID = "id";
		envMock.GOOGLE_CLIENT_SECRET = "secret";
		const providers = authService.providers.list();
		expect(providers.google).toBe("Google");
	});

	it("does NOT include Google when only one of id/secret is set", () => {
		resetEnv();
		envMock.GOOGLE_CLIENT_ID = "id";
		const providers = authService.providers.list();
		expect(providers.google).toBeUndefined();
	});

	it("includes GitHub when both client id and secret are present", () => {
		resetEnv();
		envMock.GITHUB_CLIENT_ID = "id";
		envMock.GITHUB_CLIENT_SECRET = "secret";
		expect(authService.providers.list().github).toBe("GitHub");
	});

	it("includes LinkedIn when both client id and secret are present", () => {
		resetEnv();
		envMock.LINKEDIN_CLIENT_ID = "id";
		envMock.LINKEDIN_CLIENT_SECRET = "secret";
		expect(authService.providers.list().linkedin).toBe("LinkedIn");
	});

	it("labels the custom OAuth provider with OAUTH_PROVIDER_NAME when set", () => {
		resetEnv();
		envMock.OAUTH_CLIENT_ID = "id";
		envMock.OAUTH_CLIENT_SECRET = "secret";
		envMock.OAUTH_PROVIDER_NAME = "Acme SSO";
		expect(authService.providers.list().custom).toBe("Acme SSO");
	});

	it("falls back to 'Custom OAuth' when OAUTH_PROVIDER_NAME is not set", () => {
		resetEnv();
		envMock.OAUTH_CLIENT_ID = "id";
		envMock.OAUTH_CLIENT_SECRET = "secret";
		expect(authService.providers.list().custom).toBe("Custom OAuth");
	});

	it("can register multiple social providers at once", () => {
		resetEnv();
		envMock.GOOGLE_CLIENT_ID = "g";
		envMock.GOOGLE_CLIENT_SECRET = "g";
		envMock.GITHUB_CLIENT_ID = "h";
		envMock.GITHUB_CLIENT_SECRET = "h";
		const providers = authService.providers.list();
		expect(providers.google).toBe("Google");
		expect(providers.github).toBe("GitHub");
	});
});
