import { describe, it, expect } from 'vitest';
import { searchTools } from '../../../src/tools/search.js';
import type { ToolMetadata, ToolCategory } from '../../../src/tools/types.js';

// 创建测试用的工具元数据
function createToolMetadata(
  name: string,
  options: Partial<{
    category: ToolCategory;
    description: string;
    keywords: string[];
    deferLoading: boolean;
  }> = {}
): ToolMetadata {
  return {
    name,
    category: options.category ?? 'core',
    description: options.description ?? `Description for ${name}`,
    keywords: options.keywords ?? [name],
    deferLoading: options.deferLoading ?? true,
  };
}

describe('searchTools - 工具搜索算法', () => {
  const testTools: ToolMetadata[] = [
    createToolMetadata('read_file', {
      category: 'filesystem',
      description: '读取文件内容',
      keywords: ['read', 'file', 'open', 'cat', '文件', '读取'],
    }),
    createToolMetadata('write_file', {
      category: 'filesystem',
      description: '写入文件内容',
      keywords: ['write', 'file', 'save', 'create', '文件', '写入'],
    }),
    createToolMetadata('bash', {
      category: 'shell',
      description: '执行 bash 命令',
      keywords: ['bash', 'shell', 'command', 'execute', 'run', '命令', '执行'],
    }),
    createToolMetadata('glob', {
      category: 'filesystem',
      description: '搜索匹配模式的文件',
      keywords: ['glob', 'pattern', 'find', 'search', 'file', '搜索', '模式'],
    }),
    createToolMetadata('grep', {
      category: 'filesystem',
      description: '在文件内容中搜索',
      keywords: ['grep', 'search', 'content', 'find', '搜索', '内容'],
    }),
    createToolMetadata('git_status', {
      category: 'git',
      description: '查看 Git 仓库状态',
      keywords: ['git', 'status', 'repository', '状态', '仓库'],
    }),
    createToolMetadata('git_commit', {
      category: 'git',
      description: '提交代码更改',
      keywords: ['git', 'commit', 'save', '提交', '保存'],
    }),
  ];

  describe('基础搜索功能', () => {
    it('按名称精确匹配得最高分', () => {
      const results = searchTools('bash', testTools);

      expect(results.length).toBeGreaterThan(0);
      expect(results[0].name).toBe('bash');
      expect(results[0].score).toBeGreaterThanOrEqual(10); // 名称精确匹配 +10
    });

    it('按名称包含匹配', () => {
      const results = searchTools('file', testTools);

      expect(results.length).toBeGreaterThan(0);
      // read_file 和 write_file 都应该匹配
      const fileTools = results.filter((r) => r.name.includes('file'));
      expect(fileTools.length).toBe(2);
    });

    it('按关键词精确匹配', () => {
      const results = searchTools('shell', testTools);

      expect(results.length).toBeGreaterThan(0);
      expect(results[0].name).toBe('bash');
    });

    it('按描述内容匹配', () => {
      const results = searchTools('仓库', testTools);

      expect(results.length).toBeGreaterThan(0);
      expect(results.some((r) => r.name === 'git_status')).toBe(true);
    });

    it('中文关键词搜索', () => {
      const results = searchTools('文件', testTools);

      expect(results.length).toBeGreaterThan(0);
      // read_file 和 write_file 都有 '文件' 关键词
      expect(results.some((r) => r.name === 'read_file')).toBe(true);
      expect(results.some((r) => r.name === 'write_file')).toBe(true);
    });
  });

  describe('分词功能', () => {
    it('空格分隔的多词查询', () => {
      const results = searchTools('read file', testTools);

      expect(results.length).toBeGreaterThan(0);
      // read_file 应该得到最高分（匹配 read 和 file）
      expect(results[0].name).toBe('read_file');
    });

    it('逗号分隔的多词查询', () => {
      const results = searchTools('git,status', testTools);

      expect(results.length).toBeGreaterThan(0);
      expect(results[0].name).toBe('git_status');
    });

    it('中文逗号分隔', () => {
      const results = searchTools('读取，文件', testTools);

      expect(results.length).toBeGreaterThan(0);
      expect(results[0].name).toBe('read_file');
    });

    it('下划线分隔', () => {
      const results = searchTools('git_commit', testTools);

      expect(results.length).toBeGreaterThan(0);
      expect(results[0].name).toBe('git_commit');
    });

    it('连字符分隔', () => {
      const results = searchTools('read-write', testTools);

      // 应该匹配到包含 read 或 write 关键词的工具
      expect(results.length).toBeGreaterThan(0);
    });

    it('顿号分隔（中文）', () => {
      const results = searchTools('搜索、文件', testTools);

      expect(results.length).toBeGreaterThan(0);
    });
  });

  describe('评分规则', () => {
    it('名称精确匹配优先于包含匹配', () => {
      const tools: ToolMetadata[] = [
        createToolMetadata('bash', { keywords: ['shell'] }),
        createToolMetadata('bash_advanced', { keywords: ['advanced'] }), // 移除 bash 关键词，避免额外得分
      ];

      const results = searchTools('bash', tools);

      expect(results[0].name).toBe('bash'); // 精确匹配得分更高
    });

    it('关键词精确匹配优先于包含匹配', () => {
      const tools: ToolMetadata[] = [
        createToolMetadata('tool_a', { keywords: ['git'] }),
        createToolMetadata('tool_b', { keywords: ['github', 'gitlab'] }),
      ];

      const results = searchTools('git', tools);

      expect(results[0].name).toBe('tool_a'); // 关键词精确匹配得分更高
    });

    it('多词查询累加分数', () => {
      const results = searchTools('git commit save', testTools);

      // git_commit 应该匹配 git, commit, save (在关键词中)
      expect(results[0].name).toBe('git_commit');
    });
  });

  describe('结果限制', () => {
    it('默认返回最多 5 个结果', () => {
      const results = searchTools('file', testTools);

      expect(results.length).toBeLessThanOrEqual(5);
    });

    it('自定义限制结果数量', () => {
      const results = searchTools('file', testTools, 2);

      expect(results.length).toBeLessThanOrEqual(2);
    });

    it('limit 为 0 时返回空数组', () => {
      const results = searchTools('file', testTools, 0);

      expect(results).toHaveLength(0);
    });
  });

  describe('只搜索延迟加载的工具', () => {
    it('跳过 deferLoading=false 的工具', () => {
      const tools: ToolMetadata[] = [
        createToolMetadata('core_tool', {
          keywords: ['test'],
          deferLoading: false,
        }),
        createToolMetadata('deferred_tool', {
          keywords: ['test'],
          deferLoading: true,
        }),
      ];

      const results = searchTools('test', tools);

      expect(results).toHaveLength(1);
      expect(results[0].name).toBe('deferred_tool');
    });

    it('全部为 deferLoading=false 时返回空数组', () => {
      const tools: ToolMetadata[] = [
        createToolMetadata('tool_a', { deferLoading: false }),
        createToolMetadata('tool_b', { deferLoading: false }),
      ];

      const results = searchTools('tool', tools);

      expect(results).toHaveLength(0);
    });
  });

  describe('边界情况', () => {
    it('空查询返回空数组', () => {
      const results = searchTools('', testTools);
      expect(results).toHaveLength(0);
    });

    it('只有空格的查询返回空数组', () => {
      const results = searchTools('   ', testTools);
      expect(results).toHaveLength(0);
    });

    it('空工具列表返回空数组', () => {
      const results = searchTools('test', []);
      expect(results).toHaveLength(0);
    });

    it('无匹配时返回空数组', () => {
      const results = searchTools('xyznonexistent', testTools);
      expect(results).toHaveLength(0);
    });

    it('大小写不敏感', () => {
      const results = searchTools('BASH', testTools);

      expect(results.length).toBeGreaterThan(0);
      expect(results[0].name).toBe('bash');
    });
  });

  describe('搜索结果结构', () => {
    it('返回正确的结果结构', () => {
      const results = searchTools('bash', testTools);

      expect(results[0]).toHaveProperty('name');
      expect(results[0]).toHaveProperty('description');
      expect(results[0]).toHaveProperty('category');
      expect(results[0]).toHaveProperty('score');
    });

    it('结果按分数降序排列', () => {
      const results = searchTools('file', testTools);

      for (let i = 1; i < results.length; i++) {
        expect(results[i - 1].score).toBeGreaterThanOrEqual(results[i].score);
      }
    });
  });
});
