/**
 * Zulip客户端池服务测试
 * 
 * 功能描述：
 * - 测试ZulipClientPoolService的核心功能
 * - 测试客户端创建和销毁流程
 * - 测试事件队列管理
 * - 验证连接池统计和监控功能
 * 
 * 测试策略：
 * - 模拟ZulipClientService，测试池管理逻辑
 * - 验证客户端生命周期管理的正确性
 * - 测试并发场景下的资源管理
 * 
 * 最近修改：
 * - 2026-01-12: 代码规范优化 - 完善测试文件注释规范 (修改者: moyin)
 * 
 * @author angjustinl
 * @version 1.0.1
 * @since 2025-12-25
 * @lastModified 2026-01-12
 */

import { Test, TestingModule } from '@nestjs/testing';
import { ZulipClientPoolService, PoolStats } from './zulip_client_pool.service';
import { ZulipClientService, ZulipClientConfig, ZulipClientInstance } from './zulip_client.service';
import { AppLoggerService } from '../../utils/logger/logger.service';

describe('ZulipClientPoolService', () => {
  let service: ZulipClientPoolService;
  let mockZulipClientService: jest.Mocked<ZulipClientService>;
  let mockLogger: jest.Mocked<AppLoggerService>;

  const createMockClientInstance = (userId: string, queueId?: string): ZulipClientInstance => ({
    userId,
    config: {
      username: `${userId}@example.com`,
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    },
    client: {},
    queueId,
    lastEventId: queueId ? 0 : -1,
    createdAt: new Date(),
    lastActivity: new Date(),
    isValid: true,
  });

  beforeEach(async () => {
    jest.clearAllMocks();

    mockLogger = {
      info: jest.fn(),
      warn: jest.fn(),
      error: jest.fn(),
      debug: jest.fn(),
    } as any;

    mockZulipClientService = {
      createClient: jest.fn(),
      validateApiKey: jest.fn(),
      sendMessage: jest.fn(),
      registerQueue: jest.fn(),
      deregisterQueue: jest.fn(),
      getEvents: jest.fn(),
      destroyClient: jest.fn(),
    } as any;

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        ZulipClientPoolService,
        {
          provide: ZulipClientService,
          useValue: mockZulipClientService,
        },
        {
          provide: AppLoggerService,
          useValue: mockLogger,
        },
      ],
    }).compile();

    service = module.get<ZulipClientPoolService>(ZulipClientPoolService);
  });

  afterEach(async () => {
    // 清理所有客户端
    await service.onModuleDestroy();
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  describe('createUserClient - 客户端创建', () => {
    const config: ZulipClientConfig = {
      username: 'user@example.com',
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该成功创建新的用户客户端', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });

      const result = await service.createUserClient('user1', config);

      expect(result).toBeDefined();
      expect(result.userId).toBe('user1');
      expect(result.isValid).toBe(true);
      expect(mockZulipClientService.createClient).toHaveBeenCalledWith('user1', config);
      expect(mockZulipClientService.registerQueue).toHaveBeenCalled();
    });

    it('应该返回已存在的有效客户端', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });

      // 第一次创建
      await service.createUserClient('user1', config);
      
      // 第二次应该返回已存在的客户端
      const result = await service.createUserClient('user1', config);

      expect(result).toBeDefined();
      expect(result.userId).toBe('user1');
      // createClient只应该被调用一次
      expect(mockZulipClientService.createClient).toHaveBeenCalledTimes(1);
    });

    it('应该在事件队列注册失败时抛出错误', async () => {
      const mockInstance = createMockClientInstance('user1');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: false,
        error: '队列注册失败',
      });

      await expect(service.createUserClient('user1', config))
        .rejects.toThrow('事件队列注册失败');
    });

    it('应该在客户端创建失败时抛出错误', async () => {
      mockZulipClientService.createClient.mockRejectedValue(new Error('API Key无效'));

      await expect(service.createUserClient('user1', config))
        .rejects.toThrow('API Key无效');
    });
  });

  describe('getUserClient - 获取客户端', () => {
    const config: ZulipClientConfig = {
      username: 'user@example.com',
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该返回已存在的客户端', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });

      await service.createUserClient('user1', config);
      const result = await service.getUserClient('user1');

      expect(result).toBeDefined();
      expect(result?.userId).toBe('user1');
    });

    it('应该在客户端不存在时返回null', async () => {
      const result = await service.getUserClient('nonexistent');

      expect(result).toBeNull();
    });
  });

  describe('hasUserClient - 检查客户端存在', () => {
    const config: ZulipClientConfig = {
      username: 'user@example.com',
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该在客户端存在时返回true', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });

      await service.createUserClient('user1', config);
      
      expect(service.hasUserClient('user1')).toBe(true);
    });

    it('应该在客户端不存在时返回false', () => {
      expect(service.hasUserClient('nonexistent')).toBe(false);
    });
  });

  describe('destroyUserClient - 销毁客户端', () => {
    const config: ZulipClientConfig = {
      username: 'user@example.com',
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该成功销毁客户端', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });
      mockZulipClientService.destroyClient.mockResolvedValue(undefined);

      await service.createUserClient('user1', config);
      expect(service.hasUserClient('user1')).toBe(true);

      await service.destroyUserClient('user1');
      
      expect(service.hasUserClient('user1')).toBe(false);
      expect(mockZulipClientService.destroyClient).toHaveBeenCalled();
    });

    it('应该在客户端不存在时静默处理', async () => {
      await expect(service.destroyUserClient('nonexistent')).resolves.not.toThrow();
    });

    it('应该在销毁失败时仍从池中移除客户端', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });
      mockZulipClientService.destroyClient.mockRejectedValue(new Error('销毁失败'));

      await service.createUserClient('user1', config);
      await service.destroyUserClient('user1');
      
      expect(service.hasUserClient('user1')).toBe(false);
    });
  });

  describe('sendMessage - 发送消息', () => {
    const config: ZulipClientConfig = {
      username: 'user@example.com',
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该成功发送消息', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });
      mockZulipClientService.sendMessage.mockResolvedValue({
        success: true,
        messageId: 12345,
      });

      await service.createUserClient('user1', config);
      const result = await service.sendMessage('user1', 'test-stream', 'test-topic', 'Hello');

      expect(result.success).toBe(true);
      expect(result.messageId).toBe(12345);
    });

    it('应该在客户端不存在时返回错误', async () => {
      const result = await service.sendMessage('nonexistent', 'test-stream', 'test-topic', 'Hello');

      expect(result.success).toBe(false);
      expect(result.error).toContain('不存在');
    });
  });

  describe('registerEventQueue - 事件队列注册', () => {
    const config: ZulipClientConfig = {
      username: 'user@example.com',
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该成功注册事件队列', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-new',
        lastEventId: 0,
      });

      await service.createUserClient('user1', config);
      
      // 重新注册队列
      const result = await service.registerEventQueue('user1');

      expect(result.success).toBe(true);
      expect(result.queueId).toBe('queue-new');
    });

    it('应该在客户端不存在时返回错误', async () => {
      const result = await service.registerEventQueue('nonexistent');

      expect(result.success).toBe(false);
      expect(result.error).toContain('不存在');
    });
  });

  describe('deregisterEventQueue - 事件队列注销', () => {
    const config: ZulipClientConfig = {
      username: 'user@example.com',
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该成功注销事件队列', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });
      mockZulipClientService.deregisterQueue.mockResolvedValue(true);

      await service.createUserClient('user1', config);
      const result = await service.deregisterEventQueue('user1');

      expect(result).toBe(true);
      expect(mockZulipClientService.deregisterQueue).toHaveBeenCalled();
    });

    it('应该在客户端不存在时返回true', async () => {
      const result = await service.deregisterEventQueue('nonexistent');

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

  describe('getPoolStats - 获取池统计信息', () => {
    const config: ZulipClientConfig = {
      username: 'user@example.com',
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该返回正确的统计信息', async () => {
      const mockInstance1 = createMockClientInstance('user1', 'queue-1');
      const mockInstance2 = createMockClientInstance('user2', 'queue-2');
      
      mockZulipClientService.createClient
        .mockResolvedValueOnce(mockInstance1)
        .mockResolvedValueOnce(mockInstance2);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });

      await service.createUserClient('user1', config);
      await service.createUserClient('user2', { ...config, username: 'user2@example.com' });

      const stats = service.getPoolStats();

      expect(stats.totalClients).toBe(2);
      expect(stats.clientIds).toContain('user1');
      expect(stats.clientIds).toContain('user2');
    });

    it('应该在池为空时返回零', () => {
      const stats = service.getPoolStats();

      expect(stats.totalClients).toBe(0);
      expect(stats.activeClients).toBe(0);
      expect(stats.clientIds).toHaveLength(0);
    });
  });

  describe('cleanupIdleClients - 清理过期客户端', () => {
    const config: ZulipClientConfig = {
      username: 'user@example.com',
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该清理过期的客户端', async () => {
      // 创建一个过期的客户端实例
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      // 设置最后活动时间为1小时前
      mockInstance.lastActivity = new Date(Date.now() - 60 * 60 * 1000);
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });
      mockZulipClientService.destroyClient.mockResolvedValue(undefined);

      await service.createUserClient('user1', config);
      
      // 清理30分钟未活动的客户端
      const cleanedCount = await service.cleanupIdleClients(30);

      expect(cleanedCount).toBe(1);
      expect(service.hasUserClient('user1')).toBe(false);
    });

    it('应该保留活跃的客户端', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      // 最后活动时间为现在
      mockInstance.lastActivity = new Date();
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });

      await service.createUserClient('user1', config);
      
      const cleanedCount = await service.cleanupIdleClients(30);

      expect(cleanedCount).toBe(0);
      expect(service.hasUserClient('user1')).toBe(true);
    });
  });

  describe('事件轮询', () => {
    const config: ZulipClientConfig = {
      username: 'user@example.com',
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该启动和停止事件轮询', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });
      mockZulipClientService.getEvents.mockResolvedValue({
        success: true,
        events: [],
      });

      await service.createUserClient('user1', config);
      
      const callback = jest.fn();
      service.startEventPolling('user1', callback, 100);
      
      // 等待一小段时间让轮询执行
      await new Promise(resolve => setTimeout(resolve, 50));
      
      service.stopEventPolling('user1');
      
      // 验证getEvents被调用
      expect(mockZulipClientService.getEvents).toHaveBeenCalled();
    });

    it('应该在收到事件时调用回调', async () => {
      const mockInstance = createMockClientInstance('user1', 'queue-123');
      const mockEvents: any[] = [
        { id: 1, type: 'message', queue_id: 'queue-123', message: { content: 'Hello' } },
      ];
      
      mockZulipClientService.createClient.mockResolvedValue(mockInstance);
      mockZulipClientService.registerQueue.mockResolvedValue({
        success: true,
        queueId: 'queue-123',
        lastEventId: 0,
      });
      mockZulipClientService.getEvents.mockResolvedValue({
        success: true,
        events: mockEvents,
      });

      await service.createUserClient('user1', config);
      
      const callback = jest.fn();
      service.startEventPolling('user1', callback, 100);
      
      // 等待轮询执行
      await new Promise(resolve => setTimeout(resolve, 150));
      
      service.stopEventPolling('user1');
      
      // 验证回调被调用
      expect(callback).toHaveBeenCalledWith(mockEvents);
    });
  });
});
