/**
 * @license
 * Copyright 2025 Vybestack LLC
 * SPDX-License-Identifier: Apache-2.0
 *
 * @plan PLAN-20251212issue488
 * Phase 1: Profile Application Failover Tests (TDD - RED)
 *
 * Tests MUST be written FIRST, implementation SECOND.
 * These tests verify that the profile application system correctly maps
 * the failover policy to the failover strategy.
 */
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
const switchActiveProviderMock = vi.fn();
const setActiveModelMock = vi.fn();
const updateActiveProviderBaseUrlMock = vi.fn();
const updateActiveProviderApiKeyMock = vi.fn();
const setActiveModelParamMock = vi.fn();
const clearActiveModelParamMock = vi.fn();
const getActiveModelParamsMock = vi.fn();
const setEphemeralSettingMock = vi.fn();
const getCliRuntimeServicesMock = vi.fn();
const getActiveProviderOrThrowMock = vi.fn();
const isCliStatelessProviderModeEnabledMock = vi
    .fn()
    .mockReturnValue(false);
const isCliRuntimeStatelessReadyMock = vi
    .fn()
    .mockReturnValue(true);
const configStub = {
    model: undefined,
    ephemerals: new Map(),
    getModel() {
        return this.model;
    },
    setModel(value) {
        this.model = value;
    },
    getEphemeralSetting(key) {
        return this.ephemerals.get(key);
    },
    setEphemeralSetting(key, value) {
        if (value === undefined) {
            this.ephemerals.delete(key);
            return;
        }
        this.ephemerals.set(key, value);
    },
    getEphemeralSettings() {
        return Object.fromEntries(this.ephemerals.entries());
    },
    getContentGeneratorConfig() {
        return { authType: 'key' };
    },
};
const settingsServiceStub = {
    currentProfile: null,
    providerSettings: new Map(),
    setCurrentProfileName(name) {
        this.currentProfile = name;
    },
    getCurrentProfileName() {
        return this.currentProfile;
    },
    set(key, value) {
        if (key === 'currentProfile') {
            this.currentProfile = value ?? null;
        }
    },
    get(key) {
        if (key === 'currentProfile') {
            return this.currentProfile;
        }
        return undefined;
    },
    getProviderSettings(providerName) {
        return (this.providerSettings.get(providerName) ??
            this.providerSettings.set(providerName, {}).get(providerName));
    },
    setProviderSetting(providerName, key, value) {
        const settings = this.getProviderSettings(providerName);
        settings[key] = value;
    },
};
const providerManagerStub = {
    providers: new Map(),
    activeProviderName: null,
    registerProvider(provider) {
        const providerWithName = provider;
        this.providers.set(providerWithName.name, provider);
    },
    getProviderByName(name) {
        return this.providers.get(name) ?? null;
    },
    switchProvider(name) {
        this.activeProviderName = name;
    },
    listProviders() {
        return Array.from(this.providers.keys());
    },
    getActiveProvider() {
        return this.activeProviderName
            ? (this.providers.get(this.activeProviderName) ?? null)
            : null;
    },
    getActiveProviderName() {
        return this.activeProviderName;
    },
};
const profileManagerStub = {
    loadProfile: vi.fn(),
};
const originalRegisterProvider = providerManagerStub.registerProvider;
function wrapRegisterProviderToCaptureLB() {
    let capturedLBProvider = null;
    let capturedLBConfig = null;
    const original = providerManagerStub.registerProvider.bind(providerManagerStub);
    providerManagerStub.registerProvider = vi.fn((provider) => {
        const providerWithName = provider;
        if (providerWithName.name === 'load-balancer') {
            capturedLBProvider = provider;
            capturedLBConfig = provider.config;
        }
        return original(provider);
    });
    return {
        getLBProvider: () => capturedLBProvider,
        getLBConfig: () => capturedLBConfig,
    };
}
beforeEach(() => {
    configStub.model = undefined;
    configStub.ephemerals.clear();
    settingsServiceStub.currentProfile = null;
    settingsServiceStub.providerSettings.clear();
    providerManagerStub.providers.clear();
    providerManagerStub.activeProviderName = null;
    providerManagerStub.registerProvider = originalRegisterProvider;
    providerManagerStub.registerProvider({
        name: 'gemini',
        getDefaultModel: () => 'gemini-2.0-flash-exp',
    });
    providerManagerStub.registerProvider({
        name: 'openai',
        getDefaultModel: () => 'gpt-4o-mini',
    });
    switchActiveProviderMock.mockImplementation(async (providerName) => {
        providerManagerStub.switchProvider(providerName);
        return {
            infoMessages: [],
            changed: true,
            authType: 'key',
        };
    });
    setActiveModelMock.mockResolvedValue({ nextModel: 'test-model' });
    updateActiveProviderBaseUrlMock.mockResolvedValue({
        message: 'Base URL set',
    });
    updateActiveProviderApiKeyMock.mockResolvedValue({ message: 'API key set' });
    setActiveModelParamMock.mockClear();
    clearActiveModelParamMock.mockClear();
    getActiveModelParamsMock.mockReturnValue({});
    setEphemeralSettingMock.mockImplementation((key, value) => {
        configStub.setEphemeralSetting(key, value);
    });
    getCliRuntimeServicesMock.mockReturnValue({
        config: configStub,
        settingsService: settingsServiceStub,
        providerManager: providerManagerStub,
        profileManager: profileManagerStub,
    });
    getActiveProviderOrThrowMock.mockReturnValue({ name: 'gemini' });
    isCliStatelessProviderModeEnabledMock.mockReturnValue(false);
    isCliRuntimeStatelessReadyMock.mockReturnValue(true);
});
afterEach(() => {
    vi.clearAllMocks();
});
vi.mock('../runtimeSettings.js', () => ({
    switchActiveProvider: switchActiveProviderMock,
    setActiveModel: setActiveModelMock,
    updateActiveProviderBaseUrl: updateActiveProviderBaseUrlMock,
    updateActiveProviderApiKey: updateActiveProviderApiKeyMock,
    setActiveModelParam: setActiveModelParamMock,
    clearActiveModelParam: clearActiveModelParamMock,
    getActiveModelParams: getActiveModelParamsMock,
    setEphemeralSetting: setEphemeralSettingMock,
    getCliRuntimeServices: getCliRuntimeServicesMock,
    getActiveProviderOrThrow: getActiveProviderOrThrowMock,
    isCliStatelessProviderModeEnabled: isCliStatelessProviderModeEnabledMock,
    isCliRuntimeStatelessReady: isCliRuntimeStatelessReadyMock,
}));
const { applyProfileWithGuards } = await import('../profileApplication.js');
describe('profileApplication - Failover Policy Mapping', () => {
    describe('Policy to strategy mapping', () => {
        it('should map policy "failover" to strategy "failover"', async () => {
            const lbProfile = {
                version: 1,
                type: 'loadbalancer',
                policy: 'failover',
                profiles: ['sub1', 'sub2'],
                provider: '',
                model: '',
                modelParams: {},
                ephemeralSettings: {},
            };
            const mockLoadProfile = vi.fn(async (profileName) => ({
                version: 1,
                provider: 'gemini',
                model: `model-${profileName}`,
                modelParams: {},
                ephemeralSettings: {
                    'auth-key': `key-${profileName}`,
                },
            }));
            profileManagerStub.loadProfile = mockLoadProfile;
            const { getLBConfig } = wrapRegisterProviderToCaptureLB();
            await applyProfileWithGuards(lbProfile, {
                profileName: 'myFailoverLB',
            });
            const config = getLBConfig();
            expect(config).not.toBeNull();
            expect(config?.strategy).toBe('failover');
        });
        it('should map policy "roundrobin" to strategy "round-robin"', async () => {
            const lbProfile = {
                version: 1,
                type: 'loadbalancer',
                policy: 'roundrobin',
                profiles: ['sub1', 'sub2'],
                provider: '',
                model: '',
                modelParams: {},
                ephemeralSettings: {},
            };
            const mockLoadProfile = vi.fn(async (profileName) => ({
                version: 1,
                provider: 'gemini',
                model: `model-${profileName}`,
                modelParams: {},
                ephemeralSettings: {
                    'auth-key': `key-${profileName}`,
                },
            }));
            profileManagerStub.loadProfile = mockLoadProfile;
            const { getLBConfig } = wrapRegisterProviderToCaptureLB();
            await applyProfileWithGuards(lbProfile, {
                profileName: 'myRoundRobinLB',
            });
            const config = getLBConfig();
            expect(config).not.toBeNull();
            expect(config?.strategy).toBe('round-robin');
        });
    });
    describe('LoadBalancingProvider creation with correct strategy', () => {
        it('should create LoadBalancingProvider with failover strategy from policy', async () => {
            const lbProfile = {
                version: 1,
                type: 'loadbalancer',
                policy: 'failover',
                profiles: ['sub1', 'sub2'],
                provider: '',
                model: '',
                modelParams: {},
                ephemeralSettings: {},
            };
            const mockLoadProfile = vi.fn(async () => ({
                version: 1,
                provider: 'gemini',
                model: 'test-model',
                modelParams: {},
                ephemeralSettings: {},
            }));
            profileManagerStub.loadProfile = mockLoadProfile;
            const { getLBProvider } = wrapRegisterProviderToCaptureLB();
            await applyProfileWithGuards(lbProfile, {
                profileName: 'myFailoverLB',
            });
            expect(getLBProvider()).not.toBeNull();
            expect(getLBProvider()?.name).toBe('load-balancer');
        });
        it('should register LoadBalancingProvider with providerManager', async () => {
            const lbProfile = {
                version: 1,
                type: 'loadbalancer',
                policy: 'failover',
                profiles: ['sub1', 'sub2'],
                provider: '',
                model: '',
                modelParams: {},
                ephemeralSettings: {},
            };
            const mockLoadProfile = vi.fn(async () => ({
                version: 1,
                provider: 'gemini',
                model: 'test-model',
                modelParams: {},
                ephemeralSettings: {},
            }));
            profileManagerStub.loadProfile = mockLoadProfile;
            await applyProfileWithGuards(lbProfile, {
                profileName: 'myFailoverLB',
            });
            const registeredProvider = providerManagerStub.getProviderByName('load-balancer');
            expect(registeredProvider).not.toBeNull();
        });
    });
    describe('Ephemeral settings passing', () => {
        it('should pass ephemeral settings to LoadBalancingProviderConfig', async () => {
            const lbProfile = {
                version: 1,
                type: 'loadbalancer',
                policy: 'failover',
                profiles: ['sub1', 'sub2'],
                provider: '',
                model: '',
                modelParams: {},
                ephemeralSettings: {
                    failover_retry_count: 3,
                    failover_retry_delay_ms: 1000,
                    'context-limit': 100000,
                },
            };
            const mockLoadProfile = vi.fn(async () => ({
                version: 1,
                provider: 'gemini',
                model: 'test-model',
                modelParams: {},
                ephemeralSettings: {},
            }));
            profileManagerStub.loadProfile = mockLoadProfile;
            const { getLBConfig } = wrapRegisterProviderToCaptureLB();
            await applyProfileWithGuards(lbProfile, {
                profileName: 'myFailoverLB',
            });
            const config = getLBConfig();
            expect(config).not.toBeNull();
            expect(config?.lbProfileEphemeralSettings).toBeDefined();
            expect(config?.lbProfileEphemeralSettings?.failover_retry_count).toBe(3);
            expect(config?.lbProfileEphemeralSettings?.failover_retry_delay_ms).toBe(1000);
            expect(config?.lbProfileEphemeralSettings?.['context-limit']).toBe(100000);
        });
        it('should pass empty ephemeral settings when none provided', async () => {
            const lbProfile = {
                version: 1,
                type: 'loadbalancer',
                policy: 'failover',
                profiles: ['sub1', 'sub2'],
                provider: '',
                model: '',
                modelParams: {},
                ephemeralSettings: {},
            };
            const mockLoadProfile = vi.fn(async () => ({
                version: 1,
                provider: 'gemini',
                model: 'test-model',
                modelParams: {},
                ephemeralSettings: {},
            }));
            profileManagerStub.loadProfile = mockLoadProfile;
            const { getLBConfig } = wrapRegisterProviderToCaptureLB();
            await applyProfileWithGuards(lbProfile, {
                profileName: 'myFailoverLB',
            });
            const config = getLBConfig();
            expect(config).not.toBeNull();
            expect(config?.lbProfileEphemeralSettings).toBeDefined();
            expect(Object.keys(config?.lbProfileEphemeralSettings ?? {})).toHaveLength(0);
        });
    });
    describe('Strategy in config matches policy', () => {
        it('should have failover strategy when policy is failover', async () => {
            const lbProfile = {
                version: 1,
                type: 'loadbalancer',
                policy: 'failover',
                profiles: ['sub1', 'sub2'],
                provider: '',
                model: '',
                modelParams: {},
                ephemeralSettings: {},
            };
            const mockLoadProfile = vi.fn(async () => ({
                version: 1,
                provider: 'gemini',
                model: 'test-model',
                modelParams: {},
                ephemeralSettings: {},
            }));
            profileManagerStub.loadProfile = mockLoadProfile;
            const { getLBConfig } = wrapRegisterProviderToCaptureLB();
            await applyProfileWithGuards(lbProfile, {
                profileName: 'myFailoverLB',
            });
            const config = getLBConfig();
            expect(config).not.toBeNull();
            expect(config?.strategy).toBe('failover');
        });
        it('should have round-robin strategy when policy is roundrobin', async () => {
            const lbProfile = {
                version: 1,
                type: 'loadbalancer',
                policy: 'roundrobin',
                profiles: ['sub1', 'sub2'],
                provider: '',
                model: '',
                modelParams: {},
                ephemeralSettings: {},
            };
            const mockLoadProfile = vi.fn(async () => ({
                version: 1,
                provider: 'gemini',
                model: 'test-model',
                modelParams: {},
                ephemeralSettings: {},
            }));
            profileManagerStub.loadProfile = mockLoadProfile;
            const { getLBConfig } = wrapRegisterProviderToCaptureLB();
            await applyProfileWithGuards(lbProfile, {
                profileName: 'myRoundRobinLB',
            });
            const config = getLBConfig();
            expect(config).not.toBeNull();
            expect(config?.strategy).toBe('round-robin');
        });
    });
    describe('Profile name in config', () => {
        it('should include profile name in LoadBalancingProviderConfig', async () => {
            const lbProfile = {
                version: 1,
                type: 'loadbalancer',
                policy: 'failover',
                profiles: ['sub1', 'sub2'],
                provider: '',
                model: '',
                modelParams: {},
                ephemeralSettings: {},
            };
            const mockLoadProfile = vi.fn(async () => ({
                version: 1,
                provider: 'gemini',
                model: 'test-model',
                modelParams: {},
                ephemeralSettings: {},
            }));
            profileManagerStub.loadProfile = mockLoadProfile;
            const { getLBConfig } = wrapRegisterProviderToCaptureLB();
            await applyProfileWithGuards(lbProfile, {
                profileName: 'myCustomFailoverLB',
            });
            const config = getLBConfig();
            expect(config).not.toBeNull();
            expect(config?.profileName).toBe('myCustomFailoverLB');
        });
    });
});
//# sourceMappingURL=profileApplication.failover.test.js.map