/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { SubagentToolWrapper } from './subagent-tool-wrapper.js';
import { LocalSubagentInvocation } from './local-invocation.js';
import { makeFakeConfig } from '../test-utils/config.js';
import { Kind } from '../tools/tools.js';
import { createMockMessageBus } from '../test-utils/mock-message-bus.js';
// Mock dependencies to isolate the SubagentToolWrapper class
vi.mock('./local-invocation.js');
const MockedLocalSubagentInvocation = vi.mocked(LocalSubagentInvocation);
// Define reusable test data
let mockConfig;
let mockMessageBus;
const mockDefinition = {
    kind: 'local',
    name: 'TestAgent',
    displayName: 'Test Agent Display Name',
    description: 'An agent for testing.',
    inputConfig: {
        inputSchema: {
            type: 'object',
            properties: {
                goal: { type: 'string', description: 'The goal.' },
                priority: {
                    type: 'number',
                    description: 'The priority.',
                },
            },
            required: ['goal'],
        },
    },
    modelConfig: {
        model: 'gemini-test-model',
        generateContentConfig: {
            temperature: 0,
            topP: 1,
        },
    },
    runConfig: { maxTimeMinutes: 5 },
    promptConfig: { systemPrompt: 'You are a test agent.' },
};
describe('SubagentToolWrapper', () => {
    beforeEach(() => {
        vi.clearAllMocks();
        mockConfig = makeFakeConfig();
        // .config is already set correctly by the getter on the instance.
        Object.defineProperty(mockConfig, 'promptId', {
            get: () => 'test-prompt-id',
            configurable: true,
        });
        mockMessageBus = createMockMessageBus();
    });
    describe('constructor', () => {
        it('should correctly configure the tool properties from the agent definition', () => {
            const wrapper = new SubagentToolWrapper(mockDefinition, mockConfig, mockMessageBus);
            expect(wrapper.name).toBe(mockDefinition.name);
            expect(wrapper.displayName).toBe(mockDefinition.displayName);
            expect(wrapper.description).toBe(mockDefinition.description);
            expect(wrapper.kind).toBe(Kind.Agent);
            expect(wrapper.isOutputMarkdown).toBe(true);
            expect(wrapper.canUpdateOutput).toBe(true);
        });
        it('should fall back to the agent name for displayName if it is not provided', () => {
            const definitionWithoutDisplayName = {
                ...mockDefinition,
                displayName: undefined,
            };
            const wrapper = new SubagentToolWrapper(definitionWithoutDisplayName, mockConfig, mockMessageBus);
            expect(wrapper.displayName).toBe(definitionWithoutDisplayName.name);
        });
        it('should generate a valid tool schema using the definition and converted schema', () => {
            const wrapper = new SubagentToolWrapper(mockDefinition, mockConfig, mockMessageBus);
            const schema = wrapper.schema;
            expect(schema.name).toBe(mockDefinition.name);
            expect(schema.description).toBe(mockDefinition.description);
            expect(schema.parametersJsonSchema).toEqual({
                ...mockDefinition.inputConfig.inputSchema,
                properties: {
                    ...mockDefinition.inputConfig.inputSchema['properties'],
                    wait_for_previous: {
                        type: 'boolean',
                        description: 'Set to true to wait for all previously requested tools in this turn to complete before starting. Set to false (or omit) to run in parallel. Use true when this tool depends on the output of previous tools.',
                    },
                },
            });
        });
    });
    describe('createInvocation', () => {
        it('should create a LocalSubagentInvocation with the correct parameters', () => {
            const wrapper = new SubagentToolWrapper(mockDefinition, mockConfig, mockMessageBus);
            const params = { goal: 'Test the invocation', priority: 1 };
            // The public `build` method calls the protected `createInvocation` after validation
            const invocation = wrapper.build(params);
            expect(invocation).toBeInstanceOf(LocalSubagentInvocation);
            expect(MockedLocalSubagentInvocation).toHaveBeenCalledExactlyOnceWith(mockDefinition, mockConfig, params, mockMessageBus, mockDefinition.name, mockDefinition.displayName);
        });
        it('should pass the messageBus to the LocalSubagentInvocation constructor', () => {
            const specificMessageBus = {
                publish: vi.fn(),
                subscribe: vi.fn(),
                unsubscribe: vi.fn(),
            };
            const wrapper = new SubagentToolWrapper(mockDefinition, mockConfig, specificMessageBus);
            const params = { goal: 'Test the invocation', priority: 1 };
            wrapper.build(params);
            expect(MockedLocalSubagentInvocation).toHaveBeenCalledWith(mockDefinition, mockConfig, params, specificMessageBus, mockDefinition.name, mockDefinition.displayName);
        });
        it('should throw a validation error for invalid parameters before creating an invocation', () => {
            const wrapper = new SubagentToolWrapper(mockDefinition, mockConfig, mockMessageBus);
            // Missing the required 'goal' parameter
            const invalidParams = { priority: 1 };
            // The `build` method in the base class performs JSON schema validation
            // before calling the protected `createInvocation` method.
            expect(() => wrapper.build(invalidParams)).toThrow("params must have required property 'goal'");
            expect(MockedLocalSubagentInvocation).not.toHaveBeenCalled();
        });
    });
});
//# sourceMappingURL=subagent-tool-wrapper.test.js.map