/**
 * Agent Adapter 测试
 *
 * 测试 initCore、getOrCreateAgent、配置错误处理等关键功能
 */

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import {
  createMockCoreModule,
  createMockProviderRegistry,
  createMockAgentRegistry,
  createConfigurationErrorMock,
} from '../../mocks/core.mock.js';

// 由于 adapter.ts 使用动态 import，需要特殊处理
// 我们需要在每个测试中重新导入模块以确保 mock 生效

describe('Agent Adapter', () => {
  // 存储原始模块状态
  let originalCwd: typeof process.cwd;

  beforeEach(() => {
    vi.clearAllMocks();
    vi.resetModules();
    originalCwd = process.cwd;
  });

  afterEach(() => {
    process.cwd = originalCwd;
    vi.restoreAllMocks();
  });

  describe('initCore - Core 模块初始化', () => {
    it('成功加载 Core 模块时返回 true', async () => {
      const mockCore = createMockCoreModule();

      vi.doMock('@ai-assistant/core', () => mockCore);

      const { initCore } = await import('../../../src/agent/adapter.js');
      const result = await initCore();

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

    it('Core 模块缺少必要导出时返回 false', async () => {
      const incompleteCore = {
        Agent: undefined,
        toolRegistry: undefined,
        loadConfig: undefined,
      };

      vi.doMock('@ai-assistant/core', () => incompleteCore);

      const { initCore } = await import('../../../src/agent/adapter.js');
      const result = await initCore();

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

    it('Core 模块加载失败时返回 false', async () => {
      vi.doMock('@ai-assistant/core', () => {
        throw new Error('Module not found');
      });

      const { initCore } = await import('../../../src/agent/adapter.js');
      const result = await initCore();

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

    it('调用 ProviderRegistry.init()', async () => {
      const mockProviderRegistry = createMockProviderRegistry({
        isInitialized: vi.fn().mockReturnValue(false),
      });
      const mockCore = createMockCoreModule({
        providerRegistry: mockProviderRegistry,
      });

      vi.doMock('@ai-assistant/core', () => mockCore);

      const { initCore } = await import('../../../src/agent/adapter.js');
      await initCore();

      expect(mockCore.getProviderRegistry().init).toHaveBeenCalled();
    });

    it('ProviderRegistry 已初始化时不重复调用 init()', async () => {
      const mockProviderRegistry = createMockProviderRegistry({
        isInitialized: vi.fn().mockReturnValue(true),
      });
      const mockCore = createMockCoreModule({
        providerRegistry: mockProviderRegistry,
      });

      vi.doMock('@ai-assistant/core', () => mockCore);

      const { initCore } = await import('../../../src/agent/adapter.js');
      await initCore();

      expect(mockCore.getProviderRegistry().init).not.toHaveBeenCalled();
    });

    it('调用 AgentRegistry.init() 并传入 process.cwd()', async () => {
      const testCwd = '/test/workdir';
      process.cwd = vi.fn().mockReturnValue(testCwd);

      const mockAgentRegistry = createMockAgentRegistry({
        isInitialized: vi.fn().mockReturnValue(false),
      });
      const mockCore = createMockCoreModule({
        agentRegistry: mockAgentRegistry,
      });

      vi.doMock('@ai-assistant/core', () => mockCore);

      const { initCore } = await import('../../../src/agent/adapter.js');
      await initCore();

      expect(mockCore.agentRegistry.init).toHaveBeenCalledWith(testCwd);
    });

    it('AgentRegistry 已初始化时不重复调用 init()', async () => {
      const mockAgentRegistry = createMockAgentRegistry({
        isInitialized: vi.fn().mockReturnValue(true),
      });
      const mockCore = createMockCoreModule({
        agentRegistry: mockAgentRegistry,
      });

      vi.doMock('@ai-assistant/core', () => mockCore);

      const { initCore } = await import('../../../src/agent/adapter.js');
      await initCore();

      expect(mockCore.agentRegistry.init).not.toHaveBeenCalled();
    });
  });

  describe('isCoreAvailable - Core 模块可用性检查', () => {
    it('Core 未初始化时返回 false', async () => {
      vi.resetModules();
      const { isCoreAvailable } = await import('../../../src/agent/adapter.js');
      expect(isCoreAvailable()).toBe(false);
    });

    it('Core 初始化后返回 true', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      const { initCore, isCoreAvailable } = await import('../../../src/agent/adapter.js');
      await initCore();

      expect(isCoreAvailable()).toBe(true);
    });
  });

  describe('getOrCreateAgent - Agent 创建与缓存', () => {
    it('Core 未初始化时返回 null', async () => {
      vi.resetModules();
      const { getOrCreateAgent } = await import('../../../src/agent/adapter.js');
      const agent = getOrCreateAgent('session-1');
      expect(agent).toBeNull();
    });

    it('成功创建 Agent 实例', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      // Mock session manager
      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue({
          exists: vi.fn().mockReturnValue(true),
          get: vi.fn().mockReturnValue({ id: 'session-1' }),
        }),
      }));

      // Mock permission handler
      vi.doMock('../../../src/permission/handler.js', () => ({
        createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
      }));

      const { initCore, getOrCreateAgent } = await import('../../../src/agent/adapter.js');
      await initCore();

      const agent = getOrCreateAgent('session-1');

      expect(agent).not.toBeNull();
      expect(mockCore.Agent).toHaveBeenCalled();
    });

    it('重复获取同一 session 返回缓存的 Agent', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue({
          exists: vi.fn().mockReturnValue(true),
        }),
      }));

      vi.doMock('../../../src/permission/handler.js', () => ({
        createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
      }));

      const { initCore, getOrCreateAgent } = await import('../../../src/agent/adapter.js');
      await initCore();

      const agent1 = getOrCreateAgent('session-1');
      const agent2 = getOrCreateAgent('session-1');

      expect(agent1).toBe(agent2);
      // Agent 构造函数只应被调用一次
      expect(mockCore.Agent).toHaveBeenCalledTimes(1);
    });

    it('ConfigurationError 时返回 null', async () => {
      const mockCore = createMockCoreModule({
        loadConfig: createConfigurationErrorMock('未配置 API Key', 'deepseek'),
      });
      vi.doMock('@ai-assistant/core', () => mockCore);

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue({
          exists: vi.fn().mockReturnValue(true),
        }),
      }));

      vi.doMock('../../../src/permission/handler.js', () => ({
        createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
      }));

      const { initCore, getOrCreateAgent } = await import('../../../src/agent/adapter.js');
      await initCore();

      const agent = getOrCreateAgent('session-1');

      expect(agent).toBeNull();
    });

    it('非 ConfigurationError 时重新抛出', async () => {
      const mockCore = createMockCoreModule({
        loadConfig: vi.fn().mockImplementation(() => {
          throw new Error('Other error');
        }),
      });
      vi.doMock('@ai-assistant/core', () => mockCore);

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue({
          exists: vi.fn().mockReturnValue(true),
        }),
      }));

      vi.doMock('../../../src/permission/handler.js', () => ({
        createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
      }));

      const { initCore, getOrCreateAgent } = await import('../../../src/agent/adapter.js');
      await initCore();

      expect(() => getOrCreateAgent('session-1')).toThrow('Other error');
    });
  });

  describe('destroyAgent - Agent 销毁', () => {
    it('从缓存中移除 Agent', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue({
          exists: vi.fn().mockReturnValue(true),
        }),
      }));

      vi.doMock('../../../src/permission/handler.js', () => ({
        createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
      }));

      const { initCore, getOrCreateAgent, destroyAgent } = await import('../../../src/agent/adapter.js');
      await initCore();

      // 创建 Agent
      getOrCreateAgent('session-1');
      expect(mockCore.Agent).toHaveBeenCalledTimes(1);

      // 销毁 Agent
      destroyAgent('session-1');

      // 再次获取应创建新 Agent
      getOrCreateAgent('session-1');
      expect(mockCore.Agent).toHaveBeenCalledTimes(2);
    });
  });

  describe('getAgentStats - Agent 统计信息', () => {
    it('Core 未初始化时返回 available: false', async () => {
      vi.resetModules();
      const { getAgentStats } = await import('../../../src/agent/adapter.js');
      const stats = getAgentStats('session-1');
      expect(stats).toEqual({ available: false });
    });

    it('Agent 不存在时返回 available: true 但无其他信息', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      const { initCore, getAgentStats } = await import('../../../src/agent/adapter.js');
      await initCore();

      const stats = getAgentStats('non-existent-session');
      expect(stats).toEqual({ available: true });
    });

    it('Agent 存在时返回完整统计信息', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue({
          exists: vi.fn().mockReturnValue(true),
        }),
      }));

      vi.doMock('../../../src/permission/handler.js', () => ({
        createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
      }));

      const { initCore, getOrCreateAgent, getAgentStats } = await import('../../../src/agent/adapter.js');
      await initCore();

      // 创建 Agent
      getOrCreateAgent('session-1');

      const stats = getAgentStats('session-1');
      expect(stats.available).toBe(true);
      expect(stats.toolCount).toEqual({ core: 5, discovered: 0, total: 5 });
      expect(stats.contextUsage).toBe('10k / 200k');
    });
  });

  describe('cancelProcessing - 取消处理', () => {
    it('更新会话状态为 idle', async () => {
      const mockSessionManager = {
        exists: vi.fn().mockReturnValue(true),
        updateStatus: vi.fn(),
      };

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue(mockSessionManager),
      }));

      vi.doMock('../../../src/sse.js', () => ({
        emitStatusEvent: vi.fn(),
        emitLogEvent: vi.fn(),
      }));

      const { cancelProcessing } = await import('../../../src/agent/adapter.js');
      cancelProcessing('session-1');

      expect(mockSessionManager.updateStatus).toHaveBeenCalledWith('session-1', 'idle');
    });
  });

  describe('getContextUsage - 获取上下文使用情况', () => {
    it('Core 未初始化时返回 null', async () => {
      vi.resetModules();
      const { getContextUsage } = await import('../../../src/agent/adapter.js');
      const usage = getContextUsage('session-1');
      expect(usage).toBeNull();
    });

    it('Agent 不存在时返回 null', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      const { initCore, getContextUsage } = await import('../../../src/agent/adapter.js');
      await initCore();

      const usage = getContextUsage('non-existent-session');
      expect(usage).toBeNull();
    });

    it('Agent 存在时返回使用情况', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue({
          exists: vi.fn().mockReturnValue(true),
        }),
      }));

      vi.doMock('../../../src/permission/handler.js', () => ({
        createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
      }));

      const { initCore, getOrCreateAgent, getContextUsage } = await import('../../../src/agent/adapter.js');
      await initCore();

      getOrCreateAgent('session-1');

      const usage = getContextUsage('session-1');
      expect(usage).not.toBeNull();
      expect(usage?.formatted).toBe('10k / 200k');
      expect(usage?.input).toBe(10000);
    });
  });

  describe('compressContext - 上下文压缩', () => {
    it('Core 未初始化时返回 null', async () => {
      vi.resetModules();
      const { compressContext } = await import('../../../src/agent/adapter.js');
      const result = await compressContext('session-1');
      expect(result).toBeNull();
    });

    it('Agent 不存在时返回 null', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      const { initCore, compressContext } = await import('../../../src/agent/adapter.js');
      await initCore();

      const result = await compressContext('non-existent-session');
      expect(result).toBeNull();
    });

    it('压缩成功时返回结果', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue({
          exists: vi.fn().mockReturnValue(true),
        }),
      }));

      vi.doMock('../../../src/permission/handler.js', () => ({
        createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
      }));

      const { initCore, getOrCreateAgent, compressContext } = await import('../../../src/agent/adapter.js');
      await initCore();

      getOrCreateAgent('session-1');

      const result = await compressContext('session-1');
      expect(result).not.toBeNull();
      expect(result?.type).toBe('prune');
      expect(result?.freedTokens).toBe(1000);
    });

    it('压缩失败时返回错误信息', async () => {
      const mockCore = createMockCoreModule({
        agent: {
          compactHistory: vi.fn().mockRejectedValue(new Error('Compression failed')),
        },
      });

      vi.doMock('@ai-assistant/core', () => mockCore);

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue({
          exists: vi.fn().mockReturnValue(true),
        }),
      }));

      vi.doMock('../../../src/permission/handler.js', () => ({
        createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
      }));

      const { initCore, getOrCreateAgent, compressContext } = await import('../../../src/agent/adapter.js');
      await initCore();

      getOrCreateAgent('session-1');

      const result = await compressContext('session-1');
      expect(result).not.toBeNull();
      expect(result?.status).toBe('failed_error');
      expect(result?.error).toBe('Compression failed');
    });
  });

  describe('processMessage - 消息处理', () => {
    it('Agent 不可用时发送占位消息', async () => {
      const mockSessionManager = {
        exists: vi.fn().mockReturnValue(true),
        updateStatus: vi.fn(),
      };

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue(mockSessionManager),
      }));

      const mockBroadcast = vi.fn();
      vi.doMock('../../../src/ws.js', () => ({
        broadcastToSession: mockBroadcast,
      }));

      vi.doMock('../../../src/sse.js', () => ({
        emitStatusEvent: vi.fn(),
        emitLogEvent: vi.fn(),
      }));

      // 不初始化 core，使 agent 为 null
      vi.resetModules();
      const { processMessage } = await import('../../../src/agent/adapter.js');
      await processMessage('session-1', 'Hello');

      // 应该发送占位消息
      expect(mockBroadcast).toHaveBeenCalledWith('session-1', expect.objectContaining({
        type: 'chunk',
      }));
    });

    it('成功处理消息并返回响应', async () => {
      const mockCore = createMockCoreModule();
      vi.doMock('@ai-assistant/core', () => mockCore);

      const mockSessionManager = {
        exists: vi.fn().mockReturnValue(true),
        get: vi.fn().mockReturnValue({ id: 'session-1', name: 'Test' }),
        updateStatus: vi.fn(),
        updateMessageCount: vi.fn(),
      };

      vi.doMock('../../../src/session/manager.js', () => ({
        getSessionManager: vi.fn().mockReturnValue(mockSessionManager),
      }));

      vi.doMock('../../../src/permission/handler.js', () => ({
        createServerPermissionCallback: vi.fn().mockReturnValue(async () => ({ allow: true })),
      }));

      const mockBroadcast = vi.fn();
      vi.doMock('../../../src/ws.js', () => ({
        broadcastToSession: mockBroadcast,
      }));

      vi.doMock('../../../src/sse.js', () => ({
        emitStatusEvent: vi.fn(),
        emitLogEvent: vi.fn(),
      }));

      const { initCore, processMessage } = await import('../../../src/agent/adapter.js');
      await initCore();
      await processMessage('session-1', 'Hello');

      // 应该发送 done 消息
      expect(mockBroadcast).toHaveBeenCalledWith('session-1', expect.objectContaining({
        type: 'done',
      }));
    });
  });
});
