import { fireEvent, render, screen } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import { createAuthContext } from '../../src/auth/createAuthContext';

type User = {
    id: string;
    username: string;
};

const defaultAuth = createAuthContext<User>();

function createUser(username: string): User {
    return {
        id: `id-${username}`,
        username,
    };
}

function AuthHarness() {
    const { authToken, refreshToken, currentUser, setSession, setCurrentUser, clearSession } =
        defaultAuth.useAuth();

    return (
        <div>
            <span data-testid="auth-token">{authToken ?? 'none'}</span>
            <span data-testid="refresh-token">{refreshToken ?? 'none'}</span>
            <span data-testid="username">{currentUser?.username ?? 'none'}</span>

            <button
                type="button"
                onClick={() => setSession('auth-next', 'refresh-next', createUser('after-set'))}
            >
                set-session
            </button>
            <button type="button" onClick={() => setCurrentUser(createUser('patched'))}>
                set-user
            </button>
            <button type="button" onClick={clearSession}>
                clear
            </button>
        </div>
    );
}

describe('createAuthContext', () => {
    it('throws when hook is used outside the provider', () => {
        function Invalid() {
            defaultAuth.useAuth();
            return null;
        }

        expect(() => render(<Invalid />)).toThrow('useAuth must be used within AuthProvider');
    });

    it('reads persisted tokens and cleans default legacy keys', () => {
        localStorage.setItem('authToken', 'auth-1');
        localStorage.setItem('refreshToken', 'refresh-1');
        localStorage.setItem('auth_token', 'legacy');
        localStorage.setItem('auth_user', 'legacy');
        localStorage.setItem('token', 'legacy');

        render(
            <defaultAuth.AuthProvider>
                <AuthHarness />
            </defaultAuth.AuthProvider>,
        );

        expect(screen.getByTestId('auth-token')).toHaveTextContent('auth-1');
        expect(screen.getByTestId('refresh-token')).toHaveTextContent('refresh-1');
        expect(localStorage.getItem('auth_token')).toBeNull();
        expect(localStorage.getItem('auth_user')).toBeNull();
        expect(localStorage.getItem('token')).toBeNull();
    });

    it('supports session lifecycle updates', () => {
        render(
            <defaultAuth.AuthProvider>
                <AuthHarness />
            </defaultAuth.AuthProvider>,
        );

        fireEvent.click(screen.getByRole('button', { name: 'set-session' }));
        expect(screen.getByTestId('auth-token')).toHaveTextContent('auth-next');
        expect(screen.getByTestId('refresh-token')).toHaveTextContent('refresh-next');
        expect(screen.getByTestId('username')).toHaveTextContent('after-set');
        expect(localStorage.getItem('authToken')).toBe('auth-next');
        expect(localStorage.getItem('refreshToken')).toBe('refresh-next');

        fireEvent.click(screen.getByRole('button', { name: 'set-user' }));
        expect(screen.getByTestId('username')).toHaveTextContent('patched');

        fireEvent.click(screen.getByRole('button', { name: 'clear' }));
        expect(screen.getByTestId('auth-token')).toHaveTextContent('none');
        expect(screen.getByTestId('refresh-token')).toHaveTextContent('none');
        expect(screen.getByTestId('username')).toHaveTextContent('none');
        expect(localStorage.getItem('authToken')).toBeNull();
        expect(localStorage.getItem('refreshToken')).toBeNull();
    });

    it('supports custom token keys and legacy cleanup keys', () => {
        const customAuth = createAuthContext<User>({
            authTokenKey: 'custom-auth',
            refreshTokenKey: 'custom-refresh',
            legacyKeys: ['legacy-a', 'legacy-b'],
        });

        function CustomHarness() {
            const { authToken, refreshToken, setSession } = customAuth.useAuth();
            return (
                <div>
                    <span data-testid="custom-auth-token">{authToken ?? 'none'}</span>
                    <span data-testid="custom-refresh-token">{refreshToken ?? 'none'}</span>
                    <button
                        type="button"
                        onClick={() => setSession('next-auth', 'next-refresh', createUser('custom'))}
                    >
                        set-custom-session
                    </button>
                </div>
            );
        }

        localStorage.setItem('custom-auth', 'auth-1');
        localStorage.setItem('custom-refresh', 'refresh-1');
        localStorage.setItem('legacy-a', 'legacy');
        localStorage.setItem('legacy-b', 'legacy');

        render(
            <customAuth.AuthProvider>
                <CustomHarness />
            </customAuth.AuthProvider>,
        );

        expect(screen.getByTestId('custom-auth-token')).toHaveTextContent('auth-1');
        expect(screen.getByTestId('custom-refresh-token')).toHaveTextContent('refresh-1');
        expect(localStorage.getItem('legacy-a')).toBeNull();
        expect(localStorage.getItem('legacy-b')).toBeNull();

        fireEvent.click(screen.getByRole('button', { name: 'set-custom-session' }));
        expect(localStorage.getItem('custom-auth')).toBe('next-auth');
        expect(localStorage.getItem('custom-refresh')).toBe('next-refresh');
    });
});
