// #region AuthStoreTest [C:3] [TYPE Module] [SEMANTICS test, auth, store, jwt, token, session]
// @BRIEF Unit tests for the authentication store — token management, user profile, login/logout lifecycle,
//   loading state, and subscriber notification.
// @LAYER Tests
// @RELATION BINDS_TO -> [AuthStore]
// @TEST_CONTRACT: auth.subscribe -> Initial state with loading=true
// @TEST_CONTRACT: setToken -> Updates token, sets isAuthenticated, stores in localStorage
// @TEST_CONTRACT: setUser -> Sets user, isAuthenticated true, loading false
// @TEST_CONTRACT: logout -> Clears all state, removes token from localStorage
// @TEST_CONTRACT: setLoading -> Updates loading state

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

// $app/environment is already mocked globally in setupTests.ts (browser: true)

describe('AuthStore', () => {
	beforeEach(() => {
		localStorage.clear();
		vi.resetModules();
	});

	it('subscribes and receives initial state with loading=true', async () => {
		const { auth } = await import('$lib/auth/store.svelte.js');
		const subFn = vi.fn();
		const unsub = auth.subscribe(subFn);

		expect(subFn).toHaveBeenCalledWith(
			expect.objectContaining({
				user: null,
				token: null,
				isAuthenticated: false,
				loading: true,
			}),
		);

		unsub();
	});

	it('setToken updates token, sets isAuthenticated, and persists to localStorage', async () => {
		const { auth } = await import('$lib/auth/store.svelte.js');
		const subFn = vi.fn();
		auth.subscribe(subFn);

		auth.setToken('jwt-token-abc');

		// Check localStorage was updated
		expect(localStorage.getItem('auth_token')).toBe('jwt-token-abc');

		// Check subscriber received update
		const lastCall = subFn.mock.calls[subFn.mock.calls.length - 1][0];
		expect(lastCall.token).toBe('jwt-token-abc');
		expect(lastCall.isAuthenticated).toBe(true);
	});

	it('setToken with empty string sets isAuthenticated false', async () => {
		const { auth } = await import('$lib/auth/store.svelte.js');
		const subFn = vi.fn();
		auth.subscribe(subFn);

		auth.setToken('');

		const lastCall = subFn.mock.calls[subFn.mock.calls.length - 1][0];
		expect(lastCall.token).toBe('');
		expect(lastCall.isAuthenticated).toBe(false);
	});

	it('setUser updates user profile, sets isAuthenticated, and clears loading', async () => {
		const { auth } = await import('$lib/auth/store.svelte.js');
		const subFn = vi.fn();
		auth.subscribe(subFn);

		const user = { id: 1, name: 'Alice', email: 'alice@example.com' };
		auth.setUser(user);

		const lastCall = subFn.mock.calls[subFn.mock.calls.length - 1][0];
		expect(lastCall.user).toEqual(user);
		expect(lastCall.isAuthenticated).toBe(true);
		expect(lastCall.loading).toBe(false);
	});

	it('setUser with null sets isAuthenticated false', async () => {
		const { auth } = await import('$lib/auth/store.svelte.js');
		const subFn = vi.fn();
		auth.subscribe(subFn);

		auth.setUser(null);

		const lastCall = subFn.mock.calls[subFn.mock.calls.length - 1][0];
		expect(lastCall.user).toBeNull();
		expect(lastCall.isAuthenticated).toBe(false);
		expect(lastCall.loading).toBe(false);
	});

	it('logout clears all state and removes token from localStorage', async () => {
		const { auth } = await import('$lib/auth/store.svelte.js');

		// First set some state
		auth.setToken('jwt-to-clear');
		auth.setUser({ id: 1, name: 'Alice' });

		expect(localStorage.getItem('auth_token')).toBe('jwt-to-clear');

		const subFn = vi.fn();
		auth.subscribe(subFn);

		auth.logout();

		expect(localStorage.getItem('auth_token')).toBeNull();

		const lastCall = subFn.mock.calls[subFn.mock.calls.length - 1][0];
		expect(lastCall.user).toBeNull();
		expect(lastCall.token).toBeNull();
		expect(lastCall.isAuthenticated).toBe(false);
		expect(lastCall.loading).toBe(false);
	});

	it('setLoading updates loading state only', async () => {
		const { auth } = await import('$lib/auth/store.svelte.js');
		const subFn = vi.fn();
		auth.subscribe(subFn);

		auth.setLoading(false);

		const lastCall = subFn.mock.calls[subFn.mock.calls.length - 1][0];
		expect(lastCall.loading).toBe(false);
		expect(lastCall.user).toBeNull();
		expect(lastCall.isAuthenticated).toBe(false);

		auth.setLoading(true);
		const finalCall = subFn.mock.calls[subFn.mock.calls.length - 1][0];
		expect(finalCall.loading).toBe(true);
	});

	it('subscribe returns unsubscribe function that removes the callback', async () => {
		const { auth } = await import('$lib/auth/store.svelte.js');
		const fn = vi.fn();
		const unsub = auth.subscribe(fn);

		// Initial call during subscribe
		expect(fn).toHaveBeenCalledTimes(1);

		unsub();
		auth.setToken('new-token');
		// fn should not be called again after unsubscribe
		expect(fn).toHaveBeenCalledTimes(1);
	});

	it('multiple subscribers all receive updates', async () => {
		const { auth } = await import('$lib/auth/store.svelte.js');
		const fn1 = vi.fn();
		const fn2 = vi.fn();
		auth.subscribe(fn1);
		auth.subscribe(fn2);

		auth.setToken('multi-token');

		expect(fn1).toHaveBeenCalledWith(
			expect.objectContaining({ token: 'multi-token' }),
		);
		expect(fn2).toHaveBeenCalledWith(
			expect.objectContaining({ token: 'multi-token' }),
		);
	});

	it('initializes token from localStorage if present', async () => {
		localStorage.setItem('auth_token', 'stored-token');
		const { auth } = await import('$lib/auth/store.svelte.js');

		const subFn = vi.fn();
		auth.subscribe(subFn);

		// Initial state: browser=true so token should be read from localStorage
		const initial = subFn.mock.calls[0][0];
		expect(initial.token).toBe('stored-token');
	});
});
// #endregion AuthStoreTest
