/**
 * @license
 * Copyright 2025 Vybestack LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { profileCommand } from './profileCommand.js';
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
import { ProfileManager } from '@vybestack/llxprt-code-core';
import * as fs from 'fs';
// Mock the ProfileManager
vi.mock('@vybestack/llxprt-code-core', async () => {
    const actual = await vi.importActual('@vybestack/llxprt-code-core');
    return {
        ...actual,
        ProfileManager: vi.fn(),
    };
});
// Mock fs module
vi.mock('fs', async (importOriginal) => {
    const actual = (await importOriginal());
    return {
        ...actual,
        default: actual,
        promises: {
            readFile: vi.fn(),
        },
    };
});
// Mock os module
vi.mock('os', async (importOriginal) => {
    const actual = (await importOriginal());
    return {
        ...actual,
        homedir: vi.fn(() => '/home/user'),
    };
});
describe('profileCommand', () => {
    let context;
    let mockProfileManager;
    let mockProvider;
    let mockProviderManager;
    let mockGeminiClient;
    beforeEach(() => {
        // Reset all mocks
        vi.clearAllMocks();
        // Create mock profile manager
        mockProfileManager = {
            listProfiles: vi.fn().mockResolvedValue(['test-profile', 'prod-profile']),
            saveProfile: vi.fn().mockResolvedValue(undefined),
            loadProfile: vi.fn().mockResolvedValue({
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: { temperature: 0.7 },
                ephemeralSettings: {
                    'context-limit': 100000,
                    'compression-threshold': 0.8,
                    'base-url': 'https://api.openai.com/v1',
                },
            }),
            deleteProfile: vi.fn().mockResolvedValue(undefined),
        };
        // Mock the ProfileManager constructor
        ProfileManager.mockImplementation(() => mockProfileManager);
        // Create mock provider
        mockProvider = {
            name: 'openai',
            setModel: vi.fn(),
            setApiKey: vi.fn(),
            setBaseUrl: vi.fn(),
            setModelParams: vi.fn(),
            getModelParams: vi.fn().mockReturnValue({}),
        };
        // Create mock provider manager
        mockProviderManager = {
            getActiveProvider: vi.fn().mockReturnValue(mockProvider),
            setActiveProvider: vi.fn(),
        };
        // Create mock GeminiClient
        mockGeminiClient = {};
        // Create context with mocks
        context = createMockCommandContext({
            services: {
                config: {
                    getProvider: vi.fn().mockReturnValue('openai'),
                    getModel: vi.fn().mockReturnValue('gpt-4'),
                    setProvider: vi.fn(),
                    setModel: vi.fn(),
                    getProviderManager: vi.fn().mockReturnValue(mockProviderManager),
                    setProviderManager: vi.fn(),
                    getEphemeralSettings: vi.fn().mockReturnValue({}),
                    setEphemeralSetting: vi.fn(),
                    getEphemeralSetting: vi.fn(),
                    getGeminiClient: vi.fn().mockReturnValue(mockGeminiClient),
                    getContentGeneratorConfig: vi.fn().mockReturnValue({}),
                    refreshAuth: vi.fn().mockResolvedValue(undefined),
                },
                settings: {
                    merged: {},
                    setValue: vi.fn(),
                },
            },
        });
    });
    afterEach(() => {
        vi.restoreAllMocks();
    });
    describe('profile load command', () => {
        const loadCommand = profileCommand.subCommands[1]; // load is the second subcommand
        it('should load profile and apply compression settings', async () => {
            const result = await loadCommand.action(context, 'test-profile');
            // Verify profile was loaded
            expect(mockProfileManager.loadProfile).toHaveBeenCalledWith('test-profile');
            // Verify compression settings were applied via ephemeral settings
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('compression-threshold', 0.8);
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('context-limit', 100000);
            // Verify success message
            expect(result).toEqual({
                type: 'message',
                messageType: 'info',
                content: "Profile 'test-profile' loaded",
            });
        });
        it('should apply only context-limit when compression-threshold is not set', async () => {
            mockProfileManager.loadProfile.mockResolvedValue({
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {},
                ephemeralSettings: {
                    'context-limit': 50000,
                    // No compression-threshold
                },
            });
            await loadCommand.action(context, 'test-profile');
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('compression-threshold', undefined);
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('context-limit', 50000);
        });
        it('should apply only compression-threshold when context-limit is not set', async () => {
            mockProfileManager.loadProfile.mockResolvedValue({
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {},
                ephemeralSettings: {
                    'compression-threshold': 0.6,
                    // No context-limit
                },
            });
            await loadCommand.action(context, 'test-profile');
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('compression-threshold', 0.6);
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('context-limit', undefined);
        });
        it('should clear existing ephemeral settings before loading', async () => {
            await loadCommand.action(context, 'test-profile');
            // Verify ephemeral settings were cleared
            const expectedClears = [
                'auth-key',
                'auth-keyfile',
                'context-limit',
                'compression-threshold',
                'base-url',
                'tool-format',
                'api-version',
                'custom-headers',
                'authOnly',
            ];
            expectedClears.forEach((key) => {
                expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith(key, undefined);
            });
        });
        it('should reset compression settings when cleared', async () => {
            await loadCommand.action(context, 'test-profile');
            // Verify compression settings were reset with undefined values first
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('compression-threshold', undefined);
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('context-limit', undefined);
        });
        it('should handle base-url value of "none" correctly', async () => {
            mockProfileManager.loadProfile.mockResolvedValue({
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {},
                ephemeralSettings: {
                    'base-url': 'none',
                },
            });
            await loadCommand.action(context, 'test-profile');
            // Verify base URL was cleared (set to undefined)
            expect(mockProvider.setBaseUrl).toHaveBeenCalledWith(undefined);
        });
        it('should apply model parameters after clearing existing ones', async () => {
            mockProfileManager.loadProfile.mockResolvedValue({
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {
                    temperature: 0.9,
                    max_tokens: 2048,
                },
                ephemeralSettings: {},
            });
            await loadCommand.action(context, 'test-profile');
            // Verify model params were cleared first
            expect(mockProvider.setModelParams).toHaveBeenNthCalledWith(1, undefined);
            // Then set with new values
            expect(mockProvider.setModelParams).toHaveBeenNthCalledWith(2, {
                temperature: 0.9,
                max_tokens: 2048,
            });
        });
        it('should load API key from keyfile when specified', async () => {
            mockProfileManager.loadProfile.mockResolvedValue({
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {},
                ephemeralSettings: {
                    'auth-keyfile': '~/.keys/api-key',
                },
            });
            await loadCommand.action(context, 'test-profile');
            // Verify keyfile path was stored in ephemeral settings (but file is not read during profile load)
            // The AuthPrecedenceResolver will read the file when needed
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('auth-keyfile', '~/.keys/api-key');
            // API key is NOT set during profile load - the keyfile will be read by AuthPrecedenceResolver when needed
            expect(mockProvider.setApiKey).not.toHaveBeenCalled();
        });
        it('should handle keyfile read errors gracefully', async () => {
            mockProfileManager.loadProfile.mockResolvedValue({
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {},
                ephemeralSettings: {
                    'auth-keyfile': '~/.keys/missing-file',
                },
            });
            fs.promises.readFile.mockRejectedValue(new Error('ENOENT'));
            // Should not throw, just log error
            const result = await loadCommand.action(context, 'test-profile');
            expect(result).toEqual({
                type: 'message',
                messageType: 'info',
                content: "Profile 'test-profile' loaded",
            });
        });
        it('should apply authOnly flag when loading a profile', async () => {
            mockProfileManager.loadProfile.mockResolvedValue({
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {},
                ephemeralSettings: {
                    authOnly: true,
                },
            });
            await loadCommand.action(context, 'auth-only-profile');
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('authOnly', true);
        });
    });
    describe('profile save command', () => {
        const saveCommand = profileCommand.subCommands[0]; // save is the first subcommand
        it('should save compression settings from ephemeral settings', async () => {
            context.services.config.getEphemeralSettings = vi.fn().mockReturnValue({
                'context-limit': 75000,
                'compression-threshold': 0.65,
                'base-url': 'https://custom.api.com',
            });
            await saveCommand.action(context, 'new-profile');
            expect(mockProfileManager.saveProfile).toHaveBeenCalledWith('new-profile', {
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {},
                ephemeralSettings: {
                    'context-limit': 75000,
                    'compression-threshold': 0.65,
                    'base-url': 'https://custom.api.com',
                },
            });
        });
        it('should include model params when saving', async () => {
            mockProvider.getModelParams.mockReturnValue({
                temperature: 0.5,
                enable_thinking: true,
            });
            await saveCommand.action(context, 'model-test');
            expect(mockProfileManager.saveProfile).toHaveBeenCalledWith('model-test', {
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {
                    temperature: 0.5,
                    enable_thinking: true,
                },
                ephemeralSettings: expect.any(Object),
            });
        });
        it('should save tool-output settings from ephemeral settings', async () => {
            context.services.config.getEphemeralSettings = vi.fn().mockReturnValue({
                'tool-output-max-items': 100,
                'tool-output-max-tokens': 75000,
                'tool-output-truncate-mode': 'truncate',
                'tool-output-item-size-limit': 1048576,
                'max-prompt-tokens': 150000,
            });
            await saveCommand.action(context, 'tool-settings-profile');
            expect(mockProfileManager.saveProfile).toHaveBeenCalledWith('tool-settings-profile', {
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {},
                ephemeralSettings: {
                    'tool-output-max-items': 100,
                    'tool-output-max-tokens': 75000,
                    'tool-output-truncate-mode': 'truncate',
                    'tool-output-item-size-limit': 1048576,
                    'max-prompt-tokens': 150000,
                },
            });
        });
        it('should include authOnly flag when saving profile', async () => {
            context.services.config.getEphemeralSettings = vi.fn().mockReturnValue({
                authOnly: true,
            });
            await saveCommand.action(context, 'auth-only-profile');
            expect(mockProfileManager.saveProfile).toHaveBeenCalledWith('auth-only-profile', {
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {},
                ephemeralSettings: {
                    authOnly: true,
                },
            });
        });
    });
    describe('profile load command with tool-output settings', () => {
        const loadCommand = profileCommand.subCommands[1];
        it('should load profile with tool-output settings', async () => {
            mockProfileManager.loadProfile.mockResolvedValue({
                version: 1,
                provider: 'openai',
                model: 'gpt-4',
                modelParams: {},
                ephemeralSettings: {
                    'tool-output-max-items': 100,
                    'tool-output-max-tokens': 75000,
                    'tool-output-truncate-mode': 'truncate',
                    'tool-output-item-size-limit': 1048576,
                    'max-prompt-tokens': 150000,
                },
            });
            const result = await loadCommand.action(context, 'tool-settings-profile');
            // Verify ephemeral settings were applied
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('tool-output-max-items', 100);
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('tool-output-max-tokens', 75000);
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('tool-output-truncate-mode', 'truncate');
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('tool-output-item-size-limit', 1048576);
            expect(context.services.config.setEphemeralSetting).toHaveBeenCalledWith('max-prompt-tokens', 150000);
            expect(result).toEqual({
                type: 'message',
                messageType: 'info',
                content: "Profile 'tool-settings-profile' loaded",
            });
        });
    });
});
//# sourceMappingURL=profileCommand.test.js.map