/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
import { renderHook } from '../../test-utils/render.js';
import { useAuthCommand, validateAuthMethodWithSettings } from './useAuth.js';
import { AuthType } from '@google/gemini-cli-core';
import { AuthState } from '../types.js';
import { waitFor } from '../../test-utils/async.js';
// Mock dependencies
const mockLoadApiKey = vi.fn();
const mockValidateAuthMethod = vi.fn();
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
    const actual = await importOriginal();
    return {
        ...actual,
        loadApiKey: () => mockLoadApiKey(),
    };
});
vi.mock('../../config/auth.js', () => ({
    validateAuthMethod: (authType) => mockValidateAuthMethod(authType),
}));
describe('useAuth', () => {
    beforeEach(() => {
        vi.resetAllMocks();
        delete process.env['GEMINI_API_KEY'];
        delete process.env['GEMINI_DEFAULT_AUTH_TYPE'];
    });
    afterEach(() => {
        vi.restoreAllMocks();
    });
    describe('validateAuthMethodWithSettings', () => {
        it('should return error if auth type is enforced and does not match', () => {
            const settings = {
                merged: {
                    security: {
                        auth: {
                            enforcedType: AuthType.LOGIN_WITH_GOOGLE,
                        },
                    },
                },
            };
            const error = validateAuthMethodWithSettings(AuthType.USE_GEMINI, settings);
            expect(error).toContain('Authentication is enforced to be oauth');
        });
        it('should return null if useExternal is true', () => {
            const settings = {
                merged: {
                    security: {
                        auth: {
                            useExternal: true,
                        },
                    },
                },
            };
            const error = validateAuthMethodWithSettings(AuthType.LOGIN_WITH_GOOGLE, settings);
            expect(error).toBeNull();
        });
        it('should return null if authType is USE_GEMINI', () => {
            const settings = {
                merged: {
                    security: {
                        auth: {},
                    },
                },
            };
            const error = validateAuthMethodWithSettings(AuthType.USE_GEMINI, settings);
            expect(error).toBeNull();
        });
        it('should call validateAuthMethod for other auth types', () => {
            const settings = {
                merged: {
                    security: {
                        auth: {},
                    },
                },
            };
            mockValidateAuthMethod.mockReturnValue('Validation Error');
            const error = validateAuthMethodWithSettings(AuthType.LOGIN_WITH_GOOGLE, settings);
            expect(error).toBe('Validation Error');
            expect(mockValidateAuthMethod).toHaveBeenCalledWith(AuthType.LOGIN_WITH_GOOGLE);
        });
    });
    describe('useAuthCommand', () => {
        const mockConfig = {
            refreshAuth: vi.fn(),
        };
        const createSettings = (selectedType) => ({
            merged: {
                security: {
                    auth: {
                        selectedType,
                    },
                },
            },
        });
        it('should initialize with Unauthenticated state', () => {
            const { result } = renderHook(() => useAuthCommand(createSettings(AuthType.LOGIN_WITH_GOOGLE), mockConfig));
            expect(result.current.authState).toBe(AuthState.Unauthenticated);
        });
        it('should set error if no auth type is selected and no env key', async () => {
            const { result } = renderHook(() => useAuthCommand(createSettings(undefined), mockConfig));
            await waitFor(() => {
                expect(result.current.authError).toBe('No authentication method selected.');
                expect(result.current.authState).toBe(AuthState.Updating);
            });
        });
        it('should set error if no auth type is selected but env key exists', async () => {
            process.env['GEMINI_API_KEY'] = 'env-key';
            const { result } = renderHook(() => useAuthCommand(createSettings(undefined), mockConfig));
            await waitFor(() => {
                expect(result.current.authError).toContain('Existing API key detected (GEMINI_API_KEY)');
                expect(result.current.authState).toBe(AuthState.Updating);
            });
        });
        it('should transition to AwaitingApiKeyInput if USE_GEMINI and no key found', async () => {
            mockLoadApiKey.mockResolvedValue(null);
            const { result } = renderHook(() => useAuthCommand(createSettings(AuthType.USE_GEMINI), mockConfig));
            await waitFor(() => {
                expect(result.current.authState).toBe(AuthState.AwaitingApiKeyInput);
            });
        });
        it('should authenticate if USE_GEMINI and key is found', async () => {
            mockLoadApiKey.mockResolvedValue('stored-key');
            const { result } = renderHook(() => useAuthCommand(createSettings(AuthType.USE_GEMINI), mockConfig));
            await waitFor(() => {
                expect(mockConfig.refreshAuth).toHaveBeenCalledWith(AuthType.USE_GEMINI);
                expect(result.current.authState).toBe(AuthState.Authenticated);
                expect(result.current.apiKeyDefaultValue).toBe('stored-key');
            });
        });
        it('should authenticate if USE_GEMINI and env key is found', async () => {
            mockLoadApiKey.mockResolvedValue(null);
            process.env['GEMINI_API_KEY'] = 'env-key';
            const { result } = renderHook(() => useAuthCommand(createSettings(AuthType.USE_GEMINI), mockConfig));
            await waitFor(() => {
                expect(mockConfig.refreshAuth).toHaveBeenCalledWith(AuthType.USE_GEMINI);
                expect(result.current.authState).toBe(AuthState.Authenticated);
                expect(result.current.apiKeyDefaultValue).toBe('env-key');
            });
        });
        it('should prioritize env key over stored key when both are present', async () => {
            mockLoadApiKey.mockResolvedValue('stored-key');
            process.env['GEMINI_API_KEY'] = 'env-key';
            const { result } = renderHook(() => useAuthCommand(createSettings(AuthType.USE_GEMINI), mockConfig));
            await waitFor(() => {
                expect(mockConfig.refreshAuth).toHaveBeenCalledWith(AuthType.USE_GEMINI);
                expect(result.current.authState).toBe(AuthState.Authenticated);
                // The environment key should take precedence
                expect(result.current.apiKeyDefaultValue).toBe('env-key');
            });
        });
        it('should set error if validation fails', async () => {
            mockValidateAuthMethod.mockReturnValue('Validation Failed');
            const { result } = renderHook(() => useAuthCommand(createSettings(AuthType.LOGIN_WITH_GOOGLE), mockConfig));
            await waitFor(() => {
                expect(result.current.authError).toBe('Validation Failed');
                expect(result.current.authState).toBe(AuthState.Updating);
            });
        });
        it('should set error if GEMINI_DEFAULT_AUTH_TYPE is invalid', async () => {
            process.env['GEMINI_DEFAULT_AUTH_TYPE'] = 'INVALID_TYPE';
            const { result } = renderHook(() => useAuthCommand(createSettings(AuthType.LOGIN_WITH_GOOGLE), mockConfig));
            await waitFor(() => {
                expect(result.current.authError).toContain('Invalid value for GEMINI_DEFAULT_AUTH_TYPE');
                expect(result.current.authState).toBe(AuthState.Updating);
            });
        });
        it('should authenticate successfully for valid auth type', async () => {
            const { result } = renderHook(() => useAuthCommand(createSettings(AuthType.LOGIN_WITH_GOOGLE), mockConfig));
            await waitFor(() => {
                expect(mockConfig.refreshAuth).toHaveBeenCalledWith(AuthType.LOGIN_WITH_GOOGLE);
                expect(result.current.authState).toBe(AuthState.Authenticated);
                expect(result.current.authError).toBeNull();
            });
        });
        it('should handle refreshAuth failure', async () => {
            mockConfig.refreshAuth.mockRejectedValue(new Error('Auth Failed'));
            const { result } = renderHook(() => useAuthCommand(createSettings(AuthType.LOGIN_WITH_GOOGLE), mockConfig));
            await waitFor(() => {
                expect(result.current.authError).toContain('Failed to login');
                expect(result.current.authState).toBe(AuthState.Updating);
            });
        });
    });
});
//# sourceMappingURL=useAuth.test.js.map