import { describe, it, expect, vi, beforeEach } from 'vitest';

// Mock fs
vi.mock('fs', () => ({
  readFileSync: vi.fn(),
}));

import * as fs from 'fs';
import { loadDescription } from '../../../src/tools/load_description.js';

describe('loadDescription', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('带分类的工具', () => {
    it('加载 shell 类工具描述', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('  Bash 工具描述  ');

      const result = loadDescription('bash');

      expect(result).toBe('Bash 工具描述');
      expect(fs.readFileSync).toHaveBeenCalledWith(
        expect.stringContaining('descriptions/shell/bash.txt'),
        'utf-8'
      );
    });

    it('加载 filesystem 类工具描述', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('读取文件描述');

      const result = loadDescription('read_file');

      expect(result).toBe('读取文件描述');
      expect(fs.readFileSync).toHaveBeenCalledWith(
        expect.stringContaining('descriptions/filesystem/read_file.txt'),
        'utf-8'
      );
    });

    it('加载 write_file 描述', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('写入文件描述');

      loadDescription('write_file');

      expect(fs.readFileSync).toHaveBeenCalledWith(
        expect.stringContaining('descriptions/filesystem/write_file.txt'),
        'utf-8'
      );
    });

    it('加载 edit_file 描述', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('编辑文件描述');

      loadDescription('edit_file');

      expect(fs.readFileSync).toHaveBeenCalledWith(
        expect.stringContaining('descriptions/filesystem/edit_file.txt'),
        'utf-8'
      );
    });

    it('加载 git 类工具描述', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('Git status 描述');

      loadDescription('git_status');

      expect(fs.readFileSync).toHaveBeenCalledWith(
        expect.stringContaining('descriptions/git/git_status.txt'),
        'utf-8'
      );
    });

    it('加载 web 类工具描述', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('Web search 描述');

      loadDescription('web_search');

      expect(fs.readFileSync).toHaveBeenCalledWith(
        expect.stringContaining('descriptions/web/web_search.txt'),
        'utf-8'
      );
    });

    it('加载 todo 类工具描述', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('Todo read 描述');

      loadDescription('todo_read');

      expect(fs.readFileSync).toHaveBeenCalledWith(
        expect.stringContaining('descriptions/todo/todo_read.txt'),
        'utf-8'
      );
    });
  });

  describe('不带分类的工具', () => {
    it('未知工具使用根目录', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('未知工具描述');

      loadDescription('unknown_tool');

      expect(fs.readFileSync).toHaveBeenCalledWith(
        expect.stringContaining('descriptions/unknown_tool.txt'),
        'utf-8'
      );
      // 确保不包含子目录
      expect(fs.readFileSync).not.toHaveBeenCalledWith(
        expect.stringContaining('descriptions/filesystem/unknown_tool.txt'),
        'utf-8'
      );
    });
  });

  describe('错误处理', () => {
    it('文件不存在时抛出错误', () => {
      vi.mocked(fs.readFileSync).mockImplementation(() => {
        throw new Error('ENOENT');
      });

      expect(() => loadDescription('nonexistent')).toThrow('无法加载工具描述文件');
    });

    it('错误信息包含文件路径', () => {
      vi.mocked(fs.readFileSync).mockImplementation(() => {
        throw new Error('ENOENT');
      });

      expect(() => loadDescription('some_tool')).toThrow('some_tool.txt');
    });
  });

  describe('内容处理', () => {
    it('去除前后空白', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('\n\n  内容  \n\n');

      const result = loadDescription('bash');

      expect(result).toBe('内容');
    });

    it('保留中间空白', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('第一行\n第二行\n第三行');

      const result = loadDescription('bash');

      expect(result).toBe('第一行\n第二行\n第三行');
    });

    it('空文件返回空字符串', () => {
      vi.mocked(fs.readFileSync).mockReturnValue('   ');

      const result = loadDescription('bash');

      expect(result).toBe('');
    });
  });

  describe('所有映射的工具', () => {
    const toolCategories = [
      // shell
      { tool: 'bash', category: 'shell' },
      // filesystem
      { tool: 'read_file', category: 'filesystem' },
      { tool: 'write_file', category: 'filesystem' },
      { tool: 'edit_file', category: 'filesystem' },
      { tool: 'list_directory', category: 'filesystem' },
      { tool: 'create_directory', category: 'filesystem' },
      { tool: 'search_files', category: 'filesystem' },
      { tool: 'grep_content', category: 'filesystem' },
      { tool: 'get_file_info', category: 'filesystem' },
      { tool: 'move_file', category: 'filesystem' },
      { tool: 'copy_file', category: 'filesystem' },
      { tool: 'delete_file', category: 'filesystem' },
      // web
      { tool: 'web_search', category: 'web' },
      { tool: 'web_extract', category: 'web' },
      // git
      { tool: 'git_status', category: 'git' },
      { tool: 'git_diff', category: 'git' },
      { tool: 'git_log', category: 'git' },
      { tool: 'git_branch', category: 'git' },
      { tool: 'git_add', category: 'git' },
      { tool: 'git_commit', category: 'git' },
      { tool: 'git_push', category: 'git' },
      { tool: 'git_pull', category: 'git' },
      { tool: 'git_checkout', category: 'git' },
      { tool: 'git_stash', category: 'git' },
      // todo
      { tool: 'todo_read', category: 'todo' },
      { tool: 'todo_write', category: 'todo' },
    ];

    it.each(toolCategories)('$tool 映射到 $category 目录', ({ tool, category }) => {
      vi.mocked(fs.readFileSync).mockReturnValue('描述');

      loadDescription(tool);

      expect(fs.readFileSync).toHaveBeenCalledWith(
        expect.stringContaining(`descriptions/${category}/${tool}.txt`),
        'utf-8'
      );
    });
  });
});
