/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { ApprovalModeStrategy } from './approvalModeStrategy.js';
import { DEFAULT_GEMINI_MODEL, DEFAULT_GEMINI_FLASH_MODEL, PREVIEW_GEMINI_MODEL, PREVIEW_GEMINI_FLASH_MODEL, DEFAULT_GEMINI_MODEL_AUTO, PREVIEW_GEMINI_MODEL_AUTO, GEMINI_MODEL_ALIAS_AUTO, } from '../../config/models.js';
import { AuthType } from '../../core/contentGenerator.js';
import { ApprovalMode } from '../../policy/types.js';
describe('ApprovalModeStrategy', () => {
    let strategy;
    let mockContext;
    let mockConfig;
    let mockBaseLlmClient;
    beforeEach(() => {
        vi.clearAllMocks();
        strategy = new ApprovalModeStrategy();
        mockContext = {
            history: [],
            request: [{ text: 'test' }],
            signal: new AbortController().signal,
        };
        mockConfig = {
            getModel: vi.fn().mockReturnValue(DEFAULT_GEMINI_MODEL_AUTO),
            getApprovalMode: vi.fn().mockReturnValue(ApprovalMode.DEFAULT),
            getApprovedPlanPath: vi.fn().mockReturnValue(undefined),
            getPlanModeRoutingEnabled: vi.fn().mockResolvedValue(true),
            getGemini31Launched: vi.fn().mockResolvedValue(false),
            getHasAccessToPreviewModel: vi.fn().mockReturnValue(true),
            getUseCustomToolModel: vi.fn().mockImplementation(async () => {
                const launched = await mockConfig.getGemini31Launched();
                const authType = mockConfig.getContentGeneratorConfig?.()?.authType;
                return launched && authType === AuthType.USE_GEMINI;
            }),
            getContentGeneratorConfig: vi.fn().mockReturnValue({
                authType: AuthType.LOGIN_WITH_GOOGLE,
            }),
        };
        mockBaseLlmClient = {};
    });
    it('should return null if the model is not an auto model', async () => {
        vi.mocked(mockConfig.getModel).mockReturnValue(DEFAULT_GEMINI_MODEL);
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(decision).toBeNull();
    });
    it('should return null if plan mode routing is disabled', async () => {
        vi.mocked(mockConfig.getPlanModeRoutingEnabled).mockResolvedValue(false);
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.PLAN);
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(decision).toBeNull();
    });
    it('should route to PRO model if ApprovalMode is PLAN (Gemini 2.5)', async () => {
        vi.mocked(mockConfig.getModel).mockReturnValue(DEFAULT_GEMINI_MODEL_AUTO);
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.PLAN);
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(decision).toEqual({
            model: DEFAULT_GEMINI_MODEL,
            metadata: {
                source: 'approval-mode',
                latencyMs: expect.any(Number),
                reasoning: 'Routing to Pro model because ApprovalMode is PLAN.',
            },
        });
    });
    it('should route to PRO model if ApprovalMode is PLAN (Gemini 3)', async () => {
        vi.mocked(mockConfig.getModel).mockReturnValue(PREVIEW_GEMINI_MODEL_AUTO);
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.PLAN);
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(decision).toEqual({
            model: PREVIEW_GEMINI_MODEL,
            metadata: {
                source: 'approval-mode',
                latencyMs: expect.any(Number),
                reasoning: 'Routing to Pro model because ApprovalMode is PLAN.',
            },
        });
    });
    it('should route to FLASH model if an approved plan exists (Gemini 2.5)', async () => {
        vi.mocked(mockConfig.getModel).mockReturnValue(DEFAULT_GEMINI_MODEL_AUTO);
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.DEFAULT);
        vi.mocked(mockConfig.getApprovedPlanPath).mockReturnValue('/path/to/plan.md');
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(decision).toEqual({
            model: DEFAULT_GEMINI_FLASH_MODEL,
            metadata: {
                source: 'approval-mode',
                latencyMs: expect.any(Number),
                reasoning: 'Routing to Flash model because an approved plan exists at /path/to/plan.md.',
            },
        });
    });
    it('should route to FLASH model if an approved plan exists (Gemini 3)', async () => {
        vi.mocked(mockConfig.getModel).mockReturnValue(PREVIEW_GEMINI_MODEL_AUTO);
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.DEFAULT);
        vi.mocked(mockConfig.getApprovedPlanPath).mockReturnValue('/path/to/plan.md');
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(decision).toEqual({
            model: PREVIEW_GEMINI_FLASH_MODEL,
            metadata: {
                source: 'approval-mode',
                latencyMs: expect.any(Number),
                reasoning: 'Routing to Flash model because an approved plan exists at /path/to/plan.md.',
            },
        });
    });
    it('should return null if not in PLAN mode and no approved plan exists', async () => {
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.DEFAULT);
        vi.mocked(mockConfig.getApprovedPlanPath).mockReturnValue(undefined);
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(decision).toBeNull();
    });
    it('should prioritize requestedModel over config model if it is an auto model', async () => {
        mockContext.requestedModel = PREVIEW_GEMINI_MODEL_AUTO;
        vi.mocked(mockConfig.getModel).mockReturnValue(DEFAULT_GEMINI_MODEL_AUTO);
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.PLAN);
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(decision?.model).toBe(PREVIEW_GEMINI_MODEL);
    });
    it('should route to Preview models when using "auto" alias', async () => {
        vi.mocked(mockConfig.getModel).mockReturnValue(GEMINI_MODEL_ALIAS_AUTO);
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.PLAN);
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(decision?.model).toBe(PREVIEW_GEMINI_MODEL);
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.DEFAULT);
        vi.mocked(mockConfig.getApprovedPlanPath).mockReturnValue('/path/to/plan.md');
        const implementationDecision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(implementationDecision?.model).toBe(PREVIEW_GEMINI_FLASH_MODEL);
    });
    it('should route to Preview Flash model when an approved plan exists and Gemini 3.1 is launched', async () => {
        vi.mocked(mockConfig.getModel).mockReturnValue(GEMINI_MODEL_ALIAS_AUTO);
        vi.mocked(mockConfig.getGemini31Launched).mockResolvedValue(true);
        // Exit plan mode with approved plan
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.DEFAULT);
        vi.mocked(mockConfig.getApprovedPlanPath).mockReturnValue('/path/to/plan.md');
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        // Should resolve to Preview Flash (3.0) because resolveClassifierModel uses preview variants for Gemini 3
        expect(decision?.model).toBe(PREVIEW_GEMINI_FLASH_MODEL);
    });
    it('should route to DEFAULT_GEMINI_FLASH_MODEL when hasGemini35FlashGAAccess is true and plan is approved', async () => {
        vi.mocked(mockConfig.getModel).mockReturnValue(GEMINI_MODEL_ALIAS_AUTO);
        mockConfig.hasGemini35FlashGAAccess = vi.fn().mockReturnValue(true);
        vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.DEFAULT);
        vi.mocked(mockConfig.getApprovedPlanPath).mockReturnValue('/path/to/plan.md');
        const decision = await strategy.route(mockContext, mockConfig, mockBaseLlmClient);
        expect(decision?.model).toBe(DEFAULT_GEMINI_FLASH_MODEL);
    });
});
//# sourceMappingURL=approvalModeStrategy.test.js.map