/**
 * @license
 * Copyright 2026 HopCode Team Team
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { AuthType, resolveModelConfig, } from '@hoptrendy/hopcode-core';
import { getAuthTypeFromEnv, resolveCliGenerationConfig, } from './modelConfigUtils.js';
const mockWriteStderrLine = vi.hoisted(() => vi.fn());
vi.mock('@hoptrendy/hopcode-core', async (importOriginal) => {
    const original = await importOriginal();
    return {
        ...original,
        resolveModelConfig: vi.fn(),
    };
});
vi.mock('./stdioHelpers.js', () => ({
    writeStderrLine: mockWriteStderrLine,
    writeStdoutLine: vi.fn(),
    clearScreen: vi.fn(),
}));
describe('modelConfigUtils', () => {
    describe('getAuthTypeFromEnv', () => {
        const originalEnv = process.env;
        beforeEach(() => {
            vi.resetModules();
            // Start with a clean env - getAuthTypeFromEnv only checks auth-related vars
            process.env = {};
        });
        afterEach(() => {
            process.env = originalEnv;
        });
        it('should return USE_OPENAI when all OpenAI env vars are set', () => {
            process.env['OPENAI_API_KEY'] = 'test-key';
            process.env['OPENAI_MODEL'] = 'gpt-4';
            process.env['OPENAI_BASE_URL'] = 'https://api.openai.com';
            expect(getAuthTypeFromEnv()).toBe(AuthType.USE_OPENAI);
        });
        it('should return undefined when OpenAI env vars are incomplete', () => {
            process.env['OPENAI_API_KEY'] = 'test-key';
            process.env['OPENAI_MODEL'] = 'gpt-4';
            // Missing OPENAI_BASE_URL
            expect(getAuthTypeFromEnv()).toBeUndefined();
        });
        it('should return HOPCODE_OAUTH when HOPCODE_OAUTH is set', () => {
            process.env['HOPCODE_OAUTH'] = 'true';
            expect(getAuthTypeFromEnv()).toBe(AuthType.HOPCODE_OAUTH);
        });
        it('should return USE_GEMINI when Gemini env vars are set', () => {
            process.env['GEMINI_API_KEY'] = 'test-key';
            process.env['GEMINI_MODEL'] = 'gemini-pro';
            expect(getAuthTypeFromEnv()).toBe(AuthType.USE_GEMINI);
        });
        it('should return undefined when Gemini env vars are incomplete', () => {
            process.env['GEMINI_API_KEY'] = 'test-key';
            // Missing GEMINI_MODEL
            expect(getAuthTypeFromEnv()).toBeUndefined();
        });
        it('should return USE_VERTEX_AI when Google env vars are set', () => {
            process.env['GOOGLE_API_KEY'] = 'test-key';
            process.env['GOOGLE_MODEL'] = 'vertex-model';
            expect(getAuthTypeFromEnv()).toBe(AuthType.USE_VERTEX_AI);
        });
        it('should return undefined when Google env vars are incomplete', () => {
            process.env['GOOGLE_API_KEY'] = 'test-key';
            // Missing GOOGLE_MODEL
            expect(getAuthTypeFromEnv()).toBeUndefined();
        });
        it('should return USE_ANTHROPIC when Anthropic env vars are set', () => {
            process.env['ANTHROPIC_API_KEY'] = 'test-key';
            process.env['ANTHROPIC_MODEL'] = 'claude-3';
            process.env['ANTHROPIC_BASE_URL'] = 'https://api.anthropic.com';
            expect(getAuthTypeFromEnv()).toBe(AuthType.USE_ANTHROPIC);
        });
        it('should return undefined when Anthropic env vars are incomplete', () => {
            process.env['ANTHROPIC_API_KEY'] = 'test-key';
            process.env['ANTHROPIC_MODEL'] = 'claude-3';
            // Missing ANTHROPIC_BASE_URL
            expect(getAuthTypeFromEnv()).toBeUndefined();
        });
        it('should prioritize HOPCODE_OAUTH over other auth types when explicitly set', () => {
            process.env['HOPCODE_OAUTH'] = 'true';
            process.env['OPENAI_API_KEY'] = 'test-key';
            process.env['OPENAI_MODEL'] = 'gpt-4';
            process.env['OPENAI_BASE_URL'] = 'https://api.openai.com';
            // HOPCODE_OAUTH is checked first, so it should be returned even when other auth vars are set
            expect(getAuthTypeFromEnv()).toBe(AuthType.HOPCODE_OAUTH);
        });
        it('should return undefined when no auth env vars are set', () => {
            expect(getAuthTypeFromEnv()).toBeUndefined();
        });
    });
    describe('resolveCliGenerationConfig', () => {
        const originalEnv = process.env;
        beforeEach(() => {
            vi.resetModules();
            process.env = { ...originalEnv };
            mockWriteStderrLine.mockClear();
        });
        afterEach(() => {
            process.env = originalEnv;
            vi.clearAllMocks();
        });
        function makeMockSettings(overrides) {
            return {
                model: { name: 'default-model' },
                security: {
                    auth: {
                        apiKey: 'settings-api-key',
                        baseUrl: 'https://settings.example.com',
                    },
                },
                ...overrides,
            };
        }
        it('should resolve config from argv with highest precedence', () => {
            const argv = {
                model: 'argv-model',
                openaiApiKey: 'argv-key',
                openaiBaseUrl: 'https://argv.example.com',
            };
            const settings = makeMockSettings();
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'argv-model',
                    apiKey: 'argv-key',
                    baseUrl: 'https://argv.example.com',
                },
                sources: {
                    model: { kind: 'cli', detail: '--model' },
                    apiKey: { kind: 'cli', detail: '--openaiApiKey' },
                    baseUrl: { kind: 'cli', detail: '--openaiBaseUrl' },
                },
                warnings: [],
            });
            const result = resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(result.model).toBe('argv-model');
            expect(result.apiKey).toBe('argv-key');
            expect(result.baseUrl).toBe('https://argv.example.com');
            expect(vi.mocked(resolveModelConfig)).toHaveBeenCalledWith(expect.objectContaining({
                cli: {
                    model: 'argv-model',
                    apiKey: 'argv-key',
                    baseUrl: 'https://argv.example.com',
                },
            }));
        });
        it('should resolve config from settings when argv is not provided', () => {
            const argv = {};
            const settings = makeMockSettings({
                model: { name: 'settings-model' },
                security: {
                    auth: {
                        apiKey: 'settings-key',
                        baseUrl: 'https://settings.example.com',
                    },
                },
            });
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'settings-model',
                    apiKey: 'settings-key',
                    baseUrl: 'https://settings.example.com',
                },
                sources: {
                    model: { kind: 'settings', detail: 'model.name' },
                    apiKey: { kind: 'settings', detail: 'security.auth.apiKey' },
                    baseUrl: { kind: 'settings', detail: 'security.auth.baseUrl' },
                },
                warnings: [],
            });
            const result = resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(result.model).toBe('settings-model');
            expect(result.apiKey).toBe('settings-key');
            expect(result.baseUrl).toBe('https://settings.example.com');
        });
        it('should merge generationConfig from settings', () => {
            const argv = {};
            const settings = makeMockSettings({
                model: {
                    name: 'test-model',
                    generationConfig: {
                        samplingParams: {
                            temperature: 0.7,
                            max_tokens: 1000,
                        },
                        timeout: 5000,
                    },
                },
            });
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'test-model',
                    apiKey: '',
                    baseUrl: '',
                    samplingParams: {
                        temperature: 0.7,
                        max_tokens: 1000,
                    },
                    timeout: 5000,
                },
                sources: {},
                warnings: [],
            });
            const result = resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(result.generationConfig.samplingParams?.temperature).toBe(0.7);
            expect(result.generationConfig.samplingParams?.max_tokens).toBe(1000);
            expect(result.generationConfig.timeout).toBe(5000);
        });
        it('should resolve OpenAI logging from argv', () => {
            const argv = {
                openaiLogging: true,
                openaiLoggingDir: '/custom/log/dir',
            };
            const settings = makeMockSettings();
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'test-model',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            const result = resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(result.generationConfig.enableOpenAILogging).toBe(true);
            expect(result.generationConfig.openAILoggingDir).toBe('/custom/log/dir');
        });
        it('should resolve OpenAI logging from settings when argv is undefined', () => {
            const argv = {};
            const settings = makeMockSettings({
                model: {
                    name: 'test-model',
                    enableOpenAILogging: true,
                    openAILoggingDir: '/settings/log/dir',
                },
            });
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'test-model',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            const result = resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(result.generationConfig.enableOpenAILogging).toBe(true);
            expect(result.generationConfig.openAILoggingDir).toBe('/settings/log/dir');
        });
        it('should default OpenAI logging to false when not provided', () => {
            const argv = {};
            const settings = makeMockSettings();
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'test-model',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            const result = resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(result.generationConfig.enableOpenAILogging).toBe(false);
        });
        it('should find modelProvider from settings when authType and model match', () => {
            const argv = { model: 'provider-model' };
            const modelProvider = {
                id: 'provider-model',
                name: 'Provider Model',
                generationConfig: {
                    samplingParams: { temperature: 0.8 },
                },
            };
            const settings = makeMockSettings({
                modelProviders: {
                    [AuthType.USE_OPENAI]: [modelProvider],
                },
            });
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'provider-model',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(vi.mocked(resolveModelConfig)).toHaveBeenCalledWith(expect.objectContaining({
                modelProvider,
            }));
        });
        it('should find modelProvider from settings.model.name when argv.model is not provided', () => {
            const argv = {};
            const modelProvider = {
                id: 'settings-model',
                name: 'Settings Model',
                generationConfig: {
                    samplingParams: { temperature: 0.9 },
                },
            };
            const settings = makeMockSettings({
                model: { name: 'settings-model' },
                modelProviders: {
                    [AuthType.USE_OPENAI]: [modelProvider],
                },
            });
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'settings-model',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(vi.mocked(resolveModelConfig)).toHaveBeenCalledWith(expect.objectContaining({
                modelProvider,
            }));
        });
        it('should not find modelProvider when authType is undefined', () => {
            const argv = { model: 'test-model' };
            const settings = makeMockSettings({
                modelProviders: {
                    [AuthType.USE_OPENAI]: [{ id: 'test-model', name: 'Test Model' }],
                },
            });
            const selectedAuthType = undefined;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'test-model',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(vi.mocked(resolveModelConfig)).toHaveBeenCalledWith(expect.objectContaining({
                modelProvider: undefined,
            }));
        });
        it('should not find modelProvider when modelProviders is not an array', () => {
            const argv = { model: 'test-model' };
            const settings = makeMockSettings({
                modelProviders: {
                    [AuthType.USE_OPENAI]: null,
                },
            });
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'test-model',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(vi.mocked(resolveModelConfig)).toHaveBeenCalledWith(expect.objectContaining({
                modelProvider: undefined,
            }));
        });
        it('should return warnings from resolveModelConfig', () => {
            const argv = {};
            const settings = makeMockSettings();
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'test-model',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: ['Warning 1', 'Warning 2'],
            });
            const result = resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(result.warnings).toEqual(['Warning 1', 'Warning 2']);
        });
        it('should use custom env when provided', () => {
            const argv = {};
            const settings = makeMockSettings();
            const selectedAuthType = AuthType.USE_OPENAI;
            const customEnv = {
                OPENAI_API_KEY: 'custom-key',
                OPENAI_MODEL: 'custom-model',
            };
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'custom-model',
                    apiKey: 'custom-key',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
                env: customEnv,
            });
            expect(vi.mocked(resolveModelConfig)).toHaveBeenCalledWith(expect.objectContaining({
                env: customEnv,
            }));
        });
        it('should use process.env when env is not provided', () => {
            const argv = {};
            const settings = makeMockSettings();
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'test-model',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(vi.mocked(resolveModelConfig)).toHaveBeenCalledWith(expect.objectContaining({
                env: process.env,
            }));
        });
        it('should return empty strings for missing model, apiKey, and baseUrl', () => {
            const argv = {};
            const settings = makeMockSettings();
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: '',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            const result = resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(result.model).toBe('');
            expect(result.apiKey).toBe('');
            expect(result.baseUrl).toBe('');
        });
        it('should merge resolved config with logging settings', () => {
            const argv = {
                openaiLogging: true,
            };
            const settings = makeMockSettings({
                model: {
                    name: 'test-model',
                    generationConfig: {
                        timeout: 5000,
                    },
                },
            });
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: 'test-model',
                    apiKey: 'test-key',
                    baseUrl: 'https://test.com',
                    samplingParams: { temperature: 0.5 },
                },
                sources: {},
                warnings: [],
            });
            const result = resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(result.generationConfig).toEqual({
                model: 'test-model',
                apiKey: 'test-key',
                baseUrl: 'https://test.com',
                samplingParams: { temperature: 0.5 },
                enableOpenAILogging: true,
                openAILoggingDir: undefined,
            });
        });
        it('should handle settings without model property', () => {
            const argv = {};
            const settings = makeMockSettings({
                model: undefined,
            });
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: '',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            const result = resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(result.model).toBe('');
            expect(vi.mocked(resolveModelConfig)).toHaveBeenCalledWith(expect.objectContaining({
                settings: expect.objectContaining({
                    model: undefined,
                }),
            }));
        });
        it('should handle settings without security.auth property', () => {
            const argv = {};
            const settings = makeMockSettings({
                security: undefined,
            });
            const selectedAuthType = AuthType.USE_OPENAI;
            vi.mocked(resolveModelConfig).mockReturnValue({
                config: {
                    model: '',
                    apiKey: '',
                    baseUrl: '',
                },
                sources: {},
                warnings: [],
            });
            resolveCliGenerationConfig({
                argv,
                settings,
                selectedAuthType,
            });
            expect(vi.mocked(resolveModelConfig)).toHaveBeenCalledWith(expect.objectContaining({
                settings: expect.objectContaining({
                    apiKey: undefined,
                    baseUrl: undefined,
                }),
            }));
        });
    });
});
//# sourceMappingURL=modelConfigUtils.test.js.map