import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';

/**
 * Unit tests for the API config module (config.ts).
 *
 * Tests getApiBaseUrl() and getCurrentTenant() which depend on:
 * - $app/environment (browser flag)
 * - $env/dynamic/public (environment variables)
 * - window.location (hostname, protocol)
 */

// Mutable env object so we can change values per-test
const mockEnv: Record<string, string | undefined> = {};

// Mock $app/environment - default to browser=true
let mockBrowser = true;
vi.mock('$app/environment', () => ({
	get browser() {
		return mockBrowser;
	}
}));

// Mock $env/dynamic/public
vi.mock('$env/dynamic/public', () => ({
	env: new Proxy(mockEnv, {
		get(target, prop: string) {
			return target[prop];
		}
	})
}));

describe('API config', () => {
	let configModule: typeof import('$lib/api/config');

	beforeEach(async () => {
		// Reset env between tests
		Object.keys(mockEnv).forEach((key) => delete mockEnv[key]);
		mockBrowser = true;

		// Reset modules to get a fresh import
		vi.resetModules();
		configModule = await import('$lib/api/config');
	});

	afterEach(() => {
		vi.restoreAllMocks();
	});

	// ==========================================================================
	// getApiBaseUrl
	// ==========================================================================
	describe('getApiBaseUrl', () => {
		it('should return protocol://hostname:port/api when in browser with PUBLIC_API_PORT', () => {
			mockBrowser = true;
			mockEnv['PUBLIC_API_PORT'] = '18000';

			// jsdom provides window.location - set it for the test
			// Default jsdom location is http://localhost, so we work with that
			const result = configModule.getApiBaseUrl();

			expect(result).toBe(`${window.location.protocol}//${window.location.hostname}:18000/api`);
		});

		it('should return /api when in browser without PUBLIC_API_PORT', () => {
			mockBrowser = true;
			// PUBLIC_API_PORT is not set (undefined)

			const result = configModule.getApiBaseUrl();

			expect(result).toBe('/api');
		});

		it('should return PUBLIC_API_URL when in SSR and PUBLIC_API_URL is set', () => {
			mockBrowser = false;
			mockEnv['PUBLIC_API_URL'] = 'https://api.classeo.fr/api';

			const result = configModule.getApiBaseUrl();

			expect(result).toBe('https://api.classeo.fr/api');
		});

		it('should return http://php:8000/api as SSR fallback', () => {
			mockBrowser = false;
			// PUBLIC_API_URL is not set

			const result = configModule.getApiBaseUrl();

			expect(result).toBe('http://php:8000/api');
		});
	});

	// ==========================================================================
	// getCurrentTenant
	// ==========================================================================
	describe('getCurrentTenant', () => {
		it('should return null when not in browser', () => {
			mockBrowser = false;

			const result = configModule.getCurrentTenant();

			expect(result).toBeNull();
		});

		it('should extract subdomain correctly from hostname', () => {
			mockBrowser = true;
			mockEnv['PUBLIC_BASE_DOMAIN'] = 'classeo.local';

			// Override window.location.hostname for this test
			// jsdom default is "localhost" which won't match "classeo.local"
			// We need to use Object.defineProperty since location is readonly
			const originalHostname = window.location.hostname;
			Object.defineProperty(window, 'location', {
				value: { ...window.location, hostname: 'ecole-alpha.classeo.local' },
				writable: true
			});

			const result = configModule.getCurrentTenant();

			expect(result).toBe('ecole-alpha');

			// Restore
			Object.defineProperty(window, 'location', {
				value: { ...window.location, hostname: originalHostname },
				writable: true
			});
		});

		it('should return null for www subdomain', () => {
			mockBrowser = true;
			mockEnv['PUBLIC_BASE_DOMAIN'] = 'classeo.fr';

			Object.defineProperty(window, 'location', {
				value: { ...window.location, hostname: 'www.classeo.fr' },
				writable: true
			});

			const result = configModule.getCurrentTenant();

			expect(result).toBeNull();

			// Restore
			Object.defineProperty(window, 'location', {
				value: { ...window.location, hostname: 'localhost' },
				writable: true
			});
		});

		it('should return null when hostname does not match base domain', () => {
			mockBrowser = true;
			mockEnv['PUBLIC_BASE_DOMAIN'] = 'classeo.fr';

			Object.defineProperty(window, 'location', {
				value: { ...window.location, hostname: 'other-domain.com' },
				writable: true
			});

			const result = configModule.getCurrentTenant();

			expect(result).toBeNull();

			// Restore
			Object.defineProperty(window, 'location', {
				value: { ...window.location, hostname: 'localhost' },
				writable: true
			});
		});
	});
});
