import { describe, it, expect, beforeEach } from 'vitest';
import type { Tool } from '../../../src/types/index.js';
import type { AgentInfo, AgentToolConfig } from '../../../src/agent/types.js';

/**
 * 模拟 Agent 类中的 filterToolsByAgentConfig 逻辑
 * 由于 Agent 类有复杂的依赖，我们提取核心过滤逻辑进行测试
 */
function filterToolsByAgentConfig(
  tools: Tool[],
  toolConfig: AgentToolConfig | undefined
): Tool[] {
  if (!toolConfig) return tools;

  let filteredTools = tools;

  // 如果设置了 enabled 列表，只保留这些工具
  if (toolConfig.enabled && toolConfig.enabled.length > 0) {
    const enabledSet = new Set(toolConfig.enabled);
    filteredTools = filteredTools.filter((t) => enabledSet.has(t.name));
  }

  // 如果设置了 disabled 列表，排除这些工具
  if (toolConfig.disabled && toolConfig.disabled.length > 0) {
    const disabledSet = new Set(toolConfig.disabled);
    filteredTools = filteredTools.filter((t) => !disabledSet.has(t.name));
  }

  // 如果禁止嵌套 Task，移除 task 工具
  if (toolConfig.noTask) {
    filteredTools = filteredTools.filter((t) => t.name !== 'task');
  }

  return filteredTools;
}

// 创建测试用的 mock 工具
function createMockTool(name: string): Tool {
  return {
    name,
    description: `Mock tool: ${name}`,
    parameters: { type: 'object', properties: {}, required: [] },
    execute: async () => ({ success: true, output: 'mock' }),
  };
}

describe('Agent 工具过滤 - filterToolsByAgentConfig', () => {
  let allTools: Tool[];

  beforeEach(() => {
    // 创建一组测试工具
    allTools = [
      createMockTool('read_file'),
      createMockTool('write_file'),
      createMockTool('bash'),
      createMockTool('task'),
      createMockTool('tool_search'),
      createMockTool('glob'),
      createMockTool('grep'),
    ];
  });

  describe('无过滤配置', () => {
    it('toolConfig 为 undefined 时返回所有工具', () => {
      const result = filterToolsByAgentConfig(allTools, undefined);
      expect(result).toHaveLength(allTools.length);
      expect(result).toEqual(allTools);
    });

    it('toolConfig 为空对象时返回所有工具', () => {
      const result = filterToolsByAgentConfig(allTools, {});
      expect(result).toHaveLength(allTools.length);
    });
  });

  describe('enabled 白名单过滤', () => {
    it('只保留 enabled 列表中的工具', () => {
      const config: AgentToolConfig = {
        enabled: ['read_file', 'glob', 'grep'],
      };
      const result = filterToolsByAgentConfig(allTools, config);

      expect(result).toHaveLength(3);
      expect(result.map((t) => t.name)).toEqual(['read_file', 'glob', 'grep']);
    });

    it('enabled 为空数组时返回空列表', () => {
      const config: AgentToolConfig = {
        enabled: [],
      };
      const result = filterToolsByAgentConfig(allTools, config);
      expect(result).toHaveLength(allTools.length); // 空数组不触发过滤
    });

    it('enabled 中不存在的工具被忽略', () => {
      const config: AgentToolConfig = {
        enabled: ['read_file', 'non_existent_tool'],
      };
      const result = filterToolsByAgentConfig(allTools, config);

      expect(result).toHaveLength(1);
      expect(result[0].name).toBe('read_file');
    });
  });

  describe('disabled 黑名单过滤', () => {
    it('排除 disabled 列表中的工具', () => {
      const config: AgentToolConfig = {
        disabled: ['bash', 'write_file'],
      };
      const result = filterToolsByAgentConfig(allTools, config);

      expect(result).toHaveLength(5);
      expect(result.map((t) => t.name)).not.toContain('bash');
      expect(result.map((t) => t.name)).not.toContain('write_file');
    });

    it('disabled 为空数组时返回所有工具', () => {
      const config: AgentToolConfig = {
        disabled: [],
      };
      const result = filterToolsByAgentConfig(allTools, config);
      expect(result).toHaveLength(allTools.length);
    });

    it('disabled 中不存在的工具被忽略', () => {
      const config: AgentToolConfig = {
        disabled: ['non_existent_tool'],
      };
      const result = filterToolsByAgentConfig(allTools, config);
      expect(result).toHaveLength(allTools.length);
    });
  });

  describe('noTask 过滤', () => {
    it('noTask=true 时移除 task 工具', () => {
      const config: AgentToolConfig = {
        noTask: true,
      };
      const result = filterToolsByAgentConfig(allTools, config);

      expect(result).toHaveLength(6);
      expect(result.map((t) => t.name)).not.toContain('task');
    });

    it('noTask=false 时保留 task 工具', () => {
      const config: AgentToolConfig = {
        noTask: false,
      };
      const result = filterToolsByAgentConfig(allTools, config);

      expect(result).toHaveLength(allTools.length);
      expect(result.map((t) => t.name)).toContain('task');
    });

    it('noTask 未设置时保留 task 工具', () => {
      const config: AgentToolConfig = {};
      const result = filterToolsByAgentConfig(allTools, config);

      expect(result.map((t) => t.name)).toContain('task');
    });
  });

  describe('组合过滤', () => {
    it('enabled + noTask 组合', () => {
      const config: AgentToolConfig = {
        enabled: ['read_file', 'task', 'glob'],
        noTask: true,
      };
      const result = filterToolsByAgentConfig(allTools, config);

      // enabled 先过滤为 [read_file, task, glob]
      // noTask 再移除 task
      expect(result).toHaveLength(2);
      expect(result.map((t) => t.name)).toEqual(['read_file', 'glob']);
    });

    it('disabled + noTask 组合', () => {
      const config: AgentToolConfig = {
        disabled: ['bash'],
        noTask: true,
      };
      const result = filterToolsByAgentConfig(allTools, config);

      // 原始 7 个工具，移除 bash 和 task
      expect(result).toHaveLength(5);
      expect(result.map((t) => t.name)).not.toContain('bash');
      expect(result.map((t) => t.name)).not.toContain('task');
    });

    it('enabled + disabled 组合（enabled 优先）', () => {
      const config: AgentToolConfig = {
        enabled: ['read_file', 'bash', 'glob'],
        disabled: ['bash'], // bash 在 enabled 中，也在 disabled 中
      };
      const result = filterToolsByAgentConfig(allTools, config);

      // enabled 先过滤为 [read_file, bash, glob]
      // disabled 再移除 bash
      expect(result).toHaveLength(2);
      expect(result.map((t) => t.name)).toEqual(['read_file', 'glob']);
    });

    it('enabled + disabled + noTask 全部组合', () => {
      const config: AgentToolConfig = {
        enabled: ['read_file', 'write_file', 'task', 'glob'],
        disabled: ['write_file'],
        noTask: true,
      };
      const result = filterToolsByAgentConfig(allTools, config);

      // enabled: [read_file, write_file, task, glob]
      // disabled: 移除 write_file -> [read_file, task, glob]
      // noTask: 移除 task -> [read_file, glob]
      expect(result).toHaveLength(2);
      expect(result.map((t) => t.name)).toEqual(['read_file', 'glob']);
    });
  });
});

describe('AgentInfo 工具配置集成', () => {
  it('explore agent 典型配置：只读工具', () => {
    const exploreAgent: AgentInfo = {
      name: 'explore',
      description: '代码探索 Agent',
      mode: 'subagent',
      tools: {
        enabled: ['read_file', 'glob', 'grep', 'tool_search'],
        noTask: true,
      },
    };

    const allTools = [
      createMockTool('read_file'),
      createMockTool('write_file'),
      createMockTool('bash'),
      createMockTool('task'),
      createMockTool('glob'),
      createMockTool('grep'),
      createMockTool('tool_search'),
    ];

    const result = filterToolsByAgentConfig(allTools, exploreAgent.tools);

    expect(result).toHaveLength(4);
    expect(result.map((t) => t.name).sort()).toEqual(['glob', 'grep', 'read_file', 'tool_search']);
  });

  it('code-reviewer agent 典型配置：禁用写操作', () => {
    const reviewerAgent: AgentInfo = {
      name: 'code-reviewer',
      description: '代码审查 Agent',
      mode: 'subagent',
      tools: {
        disabled: ['write_file', 'bash'],
        noTask: true,
      },
    };

    const allTools = [
      createMockTool('read_file'),
      createMockTool('write_file'),
      createMockTool('bash'),
      createMockTool('task'),
      createMockTool('glob'),
      createMockTool('grep'),
    ];

    const result = filterToolsByAgentConfig(allTools, reviewerAgent.tools);

    // 移除 write_file, bash, task
    expect(result).toHaveLength(3);
    expect(result.map((t) => t.name).sort()).toEqual(['glob', 'grep', 'read_file']);
  });

  it('build agent 典型配置：允许嵌套 Task', () => {
    const buildAgent: AgentInfo = {
      name: 'build',
      description: '构建 Agent',
      mode: 'primary',
      tools: {
        noTask: false, // 明确允许 task
      },
    };

    const allTools = [
      createMockTool('read_file'),
      createMockTool('write_file'),
      createMockTool('bash'),
      createMockTool('task'),
    ];

    const result = filterToolsByAgentConfig(allTools, buildAgent.tools);

    expect(result).toHaveLength(4);
    expect(result.map((t) => t.name)).toContain('task');
  });
});
