import { describe, it, expect, beforeEach, vi } from 'vitest';
import { AgentRegistry } from '../../../src/agent/registry.js';
import type { AgentInfo, AgentConfigFile } from '../../../src/agent/types.js';

// Mock config-loader
vi.mock('../../../src/agent/config-loader.js', () => ({
  loadAgentConfig: vi.fn(),
}));

// Mock presets
vi.mock('../../../src/agent/presets/index.js', () => ({
  presetAgents: {
    explore: {
      description: '代码探索 Agent',
      mode: 'subagent' as const,
      prompt: '你是代码探索助手',
      maxSteps: 5,
    },
    'code-reviewer': {
      description: '代码审查 Agent',
      mode: 'subagent' as const,
      prompt: '你是代码审查助手',
    },
    build: {
      description: '构建 Agent',
      mode: 'all' as const,
      prompt: '你是构建助手',
    },
  },
}));

import { loadAgentConfig } from '../../../src/agent/config-loader.js';

describe('AgentRegistry - Agent 注册表', () => {
  let registry: AgentRegistry;

  beforeEach(() => {
    registry = new AgentRegistry();
    vi.clearAllMocks();
    vi.mocked(loadAgentConfig).mockResolvedValue(null);
  });

  describe('init - 初始化', () => {
    it('初始化后注册预设 Agent', async () => {
      await registry.init('/test/project');

      expect(registry.has('explore')).toBe(true);
      expect(registry.has('code-reviewer')).toBe(true);
      expect(registry.has('build')).toBe(true);
    });

    it('初始化加载用户配置', async () => {
      const userConfig: AgentConfigFile = {
        defaults: {
          maxSteps: 20,
        },
        agents: {
          'custom-agent': {
            description: '自定义 Agent',
            mode: 'subagent',
            prompt: '你是自定义助手',
          },
        },
      };

      vi.mocked(loadAgentConfig).mockResolvedValue(userConfig);

      await registry.init('/test/project');

      expect(registry.has('custom-agent')).toBe(true);
    });

    it('重复初始化只执行一次', async () => {
      await registry.init('/test/project');
      await registry.init('/test/project');

      expect(loadAgentConfig).toHaveBeenCalledTimes(1);
    });
  });

  describe('get - 获取 Agent', () => {
    beforeEach(async () => {
      await registry.init('/test/project');
    });

    it('获取存在的 Agent', () => {
      const agent = registry.get('explore');

      expect(agent).toBeDefined();
      expect(agent?.name).toBe('explore');
      expect(agent?.description).toBe('代码探索 Agent');
    });

    it('获取不存在的 Agent 返回 undefined', () => {
      const agent = registry.get('non-existent');

      expect(agent).toBeUndefined();
    });

    it('获取的 Agent 应用全局配置', async () => {
      vi.mocked(loadAgentConfig).mockResolvedValue({
        defaults: {
          maxSteps: 25,
        },
      });

      const newRegistry = new AgentRegistry();
      await newRegistry.init('/test/project');

      const agent = newRegistry.get('code-reviewer');

      // code-reviewer 没有设置 maxSteps，应该使用全局默认值
      expect(agent?.maxSteps).toBe(25);
    });

    it('Agent 自己的配置优先于全局配置', async () => {
      vi.mocked(loadAgentConfig).mockResolvedValue({
        defaults: {
          maxSteps: 25,
        },
      });

      const newRegistry = new AgentRegistry();
      await newRegistry.init('/test/project');

      const agent = newRegistry.get('explore');

      // explore 设置了 maxSteps: 5
      expect(agent?.maxSteps).toBe(5);
    });
  });

  describe('list - 列出 Agent', () => {
    beforeEach(async () => {
      await registry.init('/test/project');
    });

    it('列出所有 Agent', () => {
      const agents = registry.list();

      expect(agents.length).toBeGreaterThan(0);
      expect(agents.some(a => a.name === 'explore')).toBe(true);
      expect(agents.some(a => a.name === 'code-reviewer')).toBe(true);
    });

    it('按 mode 过滤 Agent', () => {
      const subagents = registry.list('subagent');

      expect(subagents.every(a => a.mode === 'subagent' || a.mode === 'all')).toBe(true);
    });
  });

  describe('listSubagents - 列出子 Agent', () => {
    beforeEach(async () => {
      await registry.init('/test/project');
    });

    it('排除 primary-only 的 Agent', () => {
      const subagents = registry.listSubagents();

      expect(subagents.every(a => a.mode !== 'primary')).toBe(true);
    });
  });

  describe('listPrimaryAgents - 列出主 Agent', () => {
    beforeEach(async () => {
      await registry.init('/test/project');
    });

    it('排除 subagent-only 的 Agent', () => {
      const primaryAgents = registry.listPrimaryAgents();

      expect(primaryAgents.every(a => a.mode !== 'subagent')).toBe(true);
    });
  });

  describe('register - 动态注册', () => {
    beforeEach(async () => {
      await registry.init('/test/project');
    });

    it('注册新 Agent', () => {
      const newAgent: AgentInfo = {
        name: 'dynamic-agent',
        description: '动态注册的 Agent',
        mode: 'subagent',
        prompt: '你是动态 Agent',
      };

      registry.register(newAgent);

      expect(registry.has('dynamic-agent')).toBe(true);
      expect(registry.get('dynamic-agent')?.description).toBe('动态注册的 Agent');
    });

    it('覆盖已有 Agent', () => {
      const updatedAgent: AgentInfo = {
        name: 'explore',
        description: '更新后的探索 Agent',
        mode: 'all',
        prompt: '更新后的提示',
      };

      registry.register(updatedAgent);

      const agent = registry.get('explore');
      expect(agent?.description).toBe('更新后的探索 Agent');
    });
  });

  describe('remove - 移除 Agent', () => {
    beforeEach(async () => {
      await registry.init('/test/project');
    });

    it('移除存在的 Agent', () => {
      const result = registry.remove('explore');

      expect(result).toBe(true);
      expect(registry.has('explore')).toBe(false);
    });

    it('移除不存在的 Agent 返回 false', () => {
      const result = registry.remove('non-existent');

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

  describe('has - 检查 Agent 是否存在', () => {
    beforeEach(async () => {
      await registry.init('/test/project');
    });

    it('存在的 Agent 返回 true', () => {
      expect(registry.has('explore')).toBe(true);
    });

    it('不存在的 Agent 返回 false', () => {
      expect(registry.has('non-existent')).toBe(false);
    });
  });

  describe('size - 获取 Agent 数量', () => {
    beforeEach(async () => {
      await registry.init('/test/project');
    });

    it('返回正确的数量', () => {
      expect(registry.size).toBeGreaterThan(0);
    });

    it('添加后数量增加', () => {
      const initialSize = registry.size;

      registry.register({
        name: 'new-agent',
        description: 'New',
        mode: 'subagent',
        prompt: 'New agent',
      });

      expect(registry.size).toBe(initialSize + 1);
    });

    it('移除后数量减少', () => {
      const initialSize = registry.size;

      registry.remove('explore');

      expect(registry.size).toBe(initialSize - 1);
    });
  });

  describe('getNames - 获取所有 Agent 名称', () => {
    beforeEach(async () => {
      await registry.init('/test/project');
    });

    it('返回所有 Agent 名称', () => {
      const names = registry.getNames();

      expect(names).toContain('explore');
      expect(names).toContain('code-reviewer');
      expect(names).toContain('build');
    });
  });

  describe('getGlobalConfig - 获取全局配置', () => {
    it('无用户配置时返回 null', async () => {
      vi.mocked(loadAgentConfig).mockResolvedValue(null);

      await registry.init('/test/project');

      expect(registry.getGlobalConfig()).toBeNull();
    });

    it('有用户配置时返回 defaults', async () => {
      vi.mocked(loadAgentConfig).mockResolvedValue({
        defaults: {
          maxSteps: 30,
          model: {
            temperature: 0.5,
          },
        },
      });

      const newRegistry = new AgentRegistry();
      await newRegistry.init('/test/project');

      const globalConfig = newRegistry.getGlobalConfig();

      expect(globalConfig?.maxSteps).toBe(30);
      expect(globalConfig?.model?.temperature).toBe(0.5);
    });
  });

  describe('generateSubagentDescription - 生成子 Agent 描述', () => {
    beforeEach(async () => {
      await registry.init('/test/project');
    });

    it('生成包含所有子 Agent 的描述', () => {
      const description = registry.generateSubagentDescription();

      expect(description).toContain('explore');
      expect(description).toContain('代码探索');
    });

    it('无子 Agent 时返回提示信息', async () => {
      // 移除所有 Agent
      for (const name of registry.getNames()) {
        registry.remove(name);
      }

      const description = registry.generateSubagentDescription();

      expect(description).toContain('没有可用');
    });
  });
});

describe('agentRegistry 单例', () => {
  it('导出单例实例', async () => {
    const { agentRegistry } = await import('../../../src/agent/registry.js');

    expect(agentRegistry).toBeDefined();
    expect(agentRegistry).toBeInstanceOf(AgentRegistry);
  });
});
