// #region Test.EnvironmentContext.Exports [C:2] [TYPE Module] [SEMANTICS test, environment, context, store, exports]
// @BRIEF Supplementary tests for environment context exported functions — subscriber cleanup, getStoredSelectedEnvId, hasAuthToken edge cases, persistSelectedEnvId direct coverage.
// @RELATION DEPENDS_ON -> [EnvironmentContextStore]
// @TEST_CONTRACT: getStoredSelectedEnvId -> returns stored value when browser=true
// @TEST_CONTRACT: hasAuthToken -> returns correct boolean based on localStorage token
// @TEST_CONTRACT: setSelectedEnvironment with unknown env -> stores empty in localStorage
// @TEST_EDGE: missing_field -> subscribe cleanup removes fn from subscriber list
// @TEST_EDGE: invalid_type -> getStoredSelectedEnvId returns empty when browser=false
// @TEST_EDGE: external_fail -> notifyAll triggers all subscriber groups correctly

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

vi.mock('$lib/api', () => ({
	api: {
		getEnvironmentsList: vi.fn(),
	},
}));

const mockBrowser = vi.hoisted(() => ({ browser: true }));
vi.mock('$app/environment', () => mockBrowser);

const mockEnvironments = [
	{ id: 'env-dev', name: 'Development', stage: 'dev' },
	{ id: 'env-prod', name: 'Production', stage: 'prod', is_production: true },
];

describe('environmentContext store — exports coverage', () => {
	beforeEach(() => {
		mockBrowser.browser = true;
		vi.resetModules();
		vi.clearAllMocks();
		localStorage.clear();
		localStorage.setItem('auth_token', 'test-token');
	});

	it('isProductionContextStore.subscribe fires after env change via setSelectedEnvironment', async () => {
		const { api } = await import('$lib/api');
		vi.mocked(api.getEnvironmentsList).mockResolvedValue(mockEnvironments);

		const {
			environmentContextStore,
			isProductionContextStore,
			refreshEnvironmentContext,
			setSelectedEnvironment,
		} = await import('../environmentContext.svelte.js');

		await refreshEnvironmentContext();
		expect(environmentContextStore.value.selectedEnvId).toBe('env-dev');

		// Subscribe to isProduction, then switch to production
		const spy = vi.fn();
		const unsubscribe = isProductionContextStore.subscribe(spy);

		// Switch to production env — subscribers should fire
		setSelectedEnvironment('env-prod');
		expect(isProductionContextStore.value).toBe(true);
		expect(spy).toHaveBeenCalledWith(true);
		unsubscribe();
	});

	it('selectedEnvironmentStore.subscribe fires after env change', async () => {
		const { api } = await import('$lib/api');
		vi.mocked(api.getEnvironmentsList).mockResolvedValue(mockEnvironments);

		const {
			selectedEnvironmentStore,
			refreshEnvironmentContext,
			setSelectedEnvironment,
		} = await import('../environmentContext.svelte.js');

		await refreshEnvironmentContext();

		const spy = vi.fn();
		const unsubscribe = selectedEnvironmentStore.subscribe(spy);

		setSelectedEnvironment('env-prod');
		expect(spy).toHaveBeenCalledWith(
			expect.objectContaining({ id: 'env-prod', name: 'Production' }),
		);
		unsubscribe();
	});

	it('subscribe cleanup — unsubscribe removes from subscriber list', async () => {
		const { environmentContextStore } = await import('../environmentContext.svelte.js');

		const spy1 = vi.fn();
		const spy2 = vi.fn();

		const unsub1 = environmentContextStore.subscribe(spy1);
		const unsub2 = environmentContextStore.subscribe(spy2);

		expect(spy1).toHaveBeenCalledTimes(1);
		expect(spy2).toHaveBeenCalledTimes(1);

		// Unsub spyr1, then trigger a state change
		unsub1();
		spy1.mockClear();
		spy2.mockClear();

		// Trigger refresh — should only notify spy2
		const { api } = await import('$lib/api');
		vi.mocked(api.getEnvironmentsList).mockResolvedValue(mockEnvironments);
		const { refreshEnvironmentContext } = await import('../environmentContext.svelte.js');
		await refreshEnvironmentContext();

		// spy1 should NOT have been called (was unsubscribed)
		// spy2 should have been called (still subscribed)
		expect(spy1).not.toHaveBeenCalled();
		expect(spy2).toHaveBeenCalled();

		unsub2();
	});

	it('environmentContextStore.value returns current state after refresh', async () => {
		const { api } = await import('$lib/api');
		vi.mocked(api.getEnvironmentsList).mockResolvedValue(mockEnvironments);

		const { environmentContextStore, refreshEnvironmentContext } = await import(
			'../environmentContext.svelte.js'
		);

		await refreshEnvironmentContext('env-prod');

		const state = environmentContextStore.value;
		expect(state.environments).toHaveLength(2);
		expect(state.selectedEnvId).toBe('env-prod');
		expect(state.isLoaded).toBe(true);
	});

	it('getStoredSelectedEnvId returns stored value when browser=true', async () => {
		mockBrowser.browser = true;
		localStorage.setItem('selected_env_id', 'env-stored');
		localStorage.setItem('auth_token', 'token');

		const { api } = await import('$lib/api');
		vi.mocked(api.getEnvironmentsList).mockResolvedValue(mockEnvironments);

		const { refreshEnvironmentContext, environmentContextStore } = await import(
			'../environmentContext.svelte.js'
		);

		// When preferredEnvId is empty and stored env is valid, resolveSelectedEnvId uses stored
		await refreshEnvironmentContext();

		// getStoredSelectedEnvId → 'env-stored' → but env-stored is not in mockEnvironments
		// so falls through to environments[0].id = 'env-dev'
		expect(environmentContextStore.value.selectedEnvId).toBe('env-dev');
	});

	it('hasAuthToken returns false when token is missing', async () => {
		localStorage.removeItem('auth_token');

		const { api } = await import('$lib/api');
		const { refreshEnvironmentContext } = await import('../environmentContext.svelte.js');

		await refreshEnvironmentContext();

		expect(api.getEnvironmentsList).not.toHaveBeenCalled();
	});

	it('hasAuthToken returns false when browser=false', async () => {
		mockBrowser.browser = false;

		const { api } = await import('$lib/api');
		const { refreshEnvironmentContext } = await import('../environmentContext.svelte.js');

		await refreshEnvironmentContext();

		expect(api.getEnvironmentsList).not.toHaveBeenCalled();
	});

	it('persistSelectedEnvId stores value in localStorage when browser=true', async () => {
		mockBrowser.browser = true;
		localStorage.removeItem('selected_env_id');
		localStorage.setItem('auth_token', 'token');

		const { api } = await import('$lib/api');
		vi.mocked(api.getEnvironmentsList).mockResolvedValue(mockEnvironments);

		const { refreshEnvironmentContext, setSelectedEnvironment, environmentContextStore } =
			await import('../environmentContext.svelte.js');

		await refreshEnvironmentContext();
		// Switch to env-prod — persistSelectedEnvId writes to localStorage
		setSelectedEnvironment('env-prod');
		expect(localStorage.getItem('selected_env_id')).toBe('env-prod');
		expect(environmentContextStore.value.selectedEnvId).toBe('env-prod');
	});

	it('resolveSelectedEnvId uses stored when preferred is empty and stored is valid', async () => {
		localStorage.setItem('selected_env_id', 'env-dev');
		localStorage.setItem('auth_token', 'token');

		const { api } = await import('$lib/api');
		vi.mocked(api.getEnvironmentsList).mockResolvedValue(mockEnvironments);

		const { refreshEnvironmentContext, environmentContextStore } = await import(
			'../environmentContext.svelte.js'
		);

		await refreshEnvironmentContext();

		// preferredEnvId is empty, stored is 'env-dev' which IS in mockEnvironments
		expect(environmentContextStore.value.selectedEnvId).toBe('env-dev');
	});

	it('resolveSelectedEnvId with invalid stored value falls through to first env', async () => {
		localStorage.setItem('selected_env_id', 'env-invalid');
		localStorage.setItem('auth_token', 'token');

		const { api } = await import('$lib/api');
		vi.mocked(api.getEnvironmentsList).mockResolvedValue(mockEnvironments);

		const { refreshEnvironmentContext, environmentContextStore } = await import(
			'../environmentContext.svelte.js'
		);

		await refreshEnvironmentContext();

		// stored env-invalid doesn't exist → fallthrough to first env
		expect(environmentContextStore.value.selectedEnvId).toBe('env-dev');
	});

	it('refreshEnvironmentContext with non-array envs + isEmpty check', async () => {
		const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
		const { api } = await import('$lib/api');
		vi.mocked(api.getEnvironmentsList).mockResolvedValue([]);

		const { environmentContextStore, refreshEnvironmentContext } = await import(
			'../environmentContext.svelte.js'
		);

		await refreshEnvironmentContext();

		expect(environmentContextStore.value.selectedEnvId).toBe('');
		expect(environmentContextStore.value.environments).toEqual([]);
		expect(environmentContextStore.value.isLoaded).toBe(true);
		consoleSpy.mockRestore();
	});
});
// #endregion Test.EnvironmentContext.Exports
