/**
 * @license
 * Copyright 2025 Qwen
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { ExitPlanModeTool } from './exitPlanMode.js';
import { ApprovalMode } from '../config/config.js';
import { ToolConfirmationOutcome } from './tools.js';
describe('ExitPlanModeTool', () => {
    let tool;
    let mockConfig;
    let approvalMode;
    beforeEach(() => {
        approvalMode = ApprovalMode.PLAN;
        mockConfig = {
            getApprovalMode: vi.fn(() => approvalMode),
            setApprovalMode: vi.fn((mode) => {
                approvalMode = mode;
            }),
        };
        tool = new ExitPlanModeTool(mockConfig);
    });
    describe('constructor and metadata', () => {
        it('should have correct tool name', () => {
            expect(tool.name).toBe('exit_plan_mode');
            expect(ExitPlanModeTool.Name).toBe('exit_plan_mode');
        });
        it('should have correct display name', () => {
            expect(tool.displayName).toBe('ExitPlanMode');
        });
        it('should have correct kind', () => {
            expect(tool.kind).toBe('think');
        });
        it('should have correct schema', () => {
            expect(tool.schema).toEqual({
                name: 'exit_plan_mode',
                description: expect.stringContaining('Use this tool when you are in plan mode'),
                parametersJsonSchema: {
                    type: 'object',
                    properties: {
                        plan: {
                            type: 'string',
                            description: expect.stringContaining('The plan you came up with'),
                        },
                    },
                    required: ['plan'],
                    additionalProperties: false,
                    $schema: 'http://json-schema.org/draft-07/schema#',
                },
            });
        });
    });
    describe('validateToolParams', () => {
        it('should accept valid parameters', () => {
            const params = {
                plan: 'This is a comprehensive plan for the implementation.',
            };
            const result = tool.validateToolParams(params);
            expect(result).toBeNull();
        });
        it('should reject missing plan parameter', () => {
            const params = {};
            const result = tool.validateToolParams(params);
            expect(result).toBe('Parameter "plan" must be a non-empty string.');
        });
        it('should reject empty plan parameter', () => {
            const params = {
                plan: '',
            };
            const result = tool.validateToolParams(params);
            expect(result).toBe('Parameter "plan" must be a non-empty string.');
        });
        it('should reject whitespace-only plan parameter', () => {
            const params = {
                plan: '   \n\t  ',
            };
            const result = tool.validateToolParams(params);
            expect(result).toBe('Parameter "plan" must be a non-empty string.');
        });
        it('should reject non-string plan parameter', () => {
            const params = {
                plan: 123,
            };
            const result = tool.validateToolParams(params);
            expect(result).toBe('Parameter "plan" must be a non-empty string.');
        });
    });
    describe('tool execution', () => {
        it('should execute successfully through tool interface after approval', async () => {
            const params = {
                plan: 'This is my implementation plan:\n1. Step 1\n2. Step 2\n3. Step 3',
            };
            const signal = new AbortController().signal;
            // Use the tool's public build method
            const invocation = tool.build(params);
            expect(invocation).toBeDefined();
            expect(invocation.params).toEqual(params);
            const confirmation = await invocation.shouldConfirmExecute(signal);
            expect(confirmation).toMatchObject({
                type: 'plan',
                title: 'Would you like to proceed?',
                plan: params.plan,
            });
            if (confirmation) {
                await confirmation.onConfirm(ToolConfirmationOutcome.ProceedOnce);
            }
            const result = await invocation.execute(signal);
            expect(result.llmContent).toContain('User has approved your plan. You can now start coding');
            expect(result.returnDisplay).toEqual({
                type: 'plan_summary',
                message: 'User approved the plan.',
                plan: params.plan,
            });
            expect(mockConfig.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.DEFAULT);
            expect(approvalMode).toBe(ApprovalMode.DEFAULT);
        });
        it('should request confirmation with plan details', async () => {
            const params = {
                plan: 'Simple plan',
            };
            const signal = new AbortController().signal;
            const invocation = tool.build(params);
            const confirmation = await invocation.shouldConfirmExecute(signal);
            if (confirmation) {
                expect(confirmation.type).toBe('plan');
                if (confirmation.type === 'plan') {
                    expect(confirmation.plan).toBe(params.plan);
                }
                await confirmation.onConfirm(ToolConfirmationOutcome.ProceedAlways);
            }
            expect(mockConfig.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.AUTO_EDIT);
            expect(approvalMode).toBe(ApprovalMode.AUTO_EDIT);
        });
        it('should remain in plan mode when confirmation is rejected', async () => {
            const params = {
                plan: 'Remain in planning',
            };
            const signal = new AbortController().signal;
            const invocation = tool.build(params);
            const confirmation = await invocation.shouldConfirmExecute(signal);
            if (confirmation) {
                await confirmation.onConfirm(ToolConfirmationOutcome.Cancel);
            }
            const result = await invocation.execute(signal);
            expect(result.llmContent).toBe('Plan execution was not approved. Remaining in plan mode.');
            expect(result.returnDisplay).toBe('Plan execution was not approved. Remaining in plan mode.');
            expect(mockConfig.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.PLAN);
            expect(approvalMode).toBe(ApprovalMode.PLAN);
        });
        it('should have correct description', () => {
            const params = {
                plan: 'Test plan',
            };
            const invocation = tool.build(params);
            expect(invocation.getDescription()).toBe('Present implementation plan for user approval');
        });
        it('should return empty tool locations', () => {
            const params = {
                plan: 'Test plan',
            };
            const invocation = tool.build(params);
            expect(invocation.toolLocations()).toEqual([]);
        });
    });
    describe('tool description', () => {
        it('should contain usage guidelines', () => {
            expect(tool.description).toContain('Only use this tool when the task requires planning');
            expect(tool.description).toContain('Do not use the exit plan mode tool because you are not planning');
            expect(tool.description).toContain('Use the exit plan mode tool after you have finished planning');
        });
        it('should contain examples', () => {
            expect(tool.description).toContain('Search for and understand the implementation of vim mode');
            expect(tool.description).toContain('Help me implement yank mode for vim');
        });
    });
});
//# sourceMappingURL=exitPlanMode.test.js.map