/**
 * Zulip客户端核心服务测试
 * 
 * 功能描述：
 * - 测试ZulipClientService的核心功能
 * - 包含属性测试验证客户端生命周期管理
 * - 验证消息发送和错误处理逻辑
 * 
 * 最近修改：
 * - 2026-01-12: 代码规范优化 - 修正注释规范和修改记录格式 (修改者: moyin)
 * - 2026-01-10: 测试完善 - 添加特殊字符消息和错误处理测试用例 (修改者: moyin)
 * 
 * @author angjustinl
 * @version 1.0.2
 * @since 2025-12-25
 * @lastModified 2026-01-12
 */

import { Test, TestingModule } from '@nestjs/testing';
import * as fc from 'fast-check';
import { ZulipClientService, ZulipClientConfig, ZulipClientInstance } from './zulip_client.service';
import { AppLoggerService } from '../../../core/utils/logger/logger.service';

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

  // Mock zulip-js模块
  const mockZulipClient = {
    users: {
      me: {
        getProfile: jest.fn(),
      },
    },
    messages: {
      send: jest.fn(),
    },
    queues: {
      register: jest.fn(),
      deregister: jest.fn(),
    },
    events: {
      retrieve: jest.fn(),
    },
  };

  const mockZulipInit = jest.fn().mockResolvedValue(mockZulipClient);

  beforeEach(async () => {
    // 重置所有mock
    jest.clearAllMocks();

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

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

    service = module.get<ZulipClientService>(ZulipClientService);

    // Mock动态导入
    jest.spyOn(service as any, 'loadZulipModule').mockResolvedValue(mockZulipInit);
  });

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

  describe('配置验证', () => {
    it('应该拒绝空的username', async () => {
      const config: ZulipClientConfig = {
        username: '',
        apiKey: 'valid-api-key',
        realm: 'https://zulip.example.com',
      };

      await expect(service.createClient('user1', config)).rejects.toThrow('无效的username配置');
    });

    it('应该拒绝空的apiKey', async () => {
      const config: ZulipClientConfig = {
        username: 'user@example.com',
        apiKey: '',
        realm: 'https://zulip.example.com',
      };

      await expect(service.createClient('user1', config)).rejects.toThrow('无效的apiKey配置');
    });

    it('应该拒绝无效的realm URL', async () => {
      const config: ZulipClientConfig = {
        username: 'user@example.com',
        apiKey: 'valid-api-key',
        realm: 'not-a-valid-url',
      };

      await expect(service.createClient('user1', config)).rejects.toThrow('realm必须是有效的URL');
    });
  });

  describe('客户端创建', () => {
    it('应该成功创建客户端', async () => {
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'success',
        email: 'user@example.com',
      });

      const config: ZulipClientConfig = {
        username: 'user@example.com',
        apiKey: 'valid-api-key',
        realm: 'https://zulip.example.com',
      };

      const client = await service.createClient('user1', config);

      expect(client).toBeDefined();
      expect(client.userId).toBe('user1');
      expect(client.isValid).toBe(true);
      expect(client.config).toEqual(config);
    });

    it('应该在API Key验证失败时抛出错误', async () => {
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'error',
        msg: 'Invalid API key',
      });

      const config: ZulipClientConfig = {
        username: 'user@example.com',
        apiKey: 'invalid-api-key',
        realm: 'https://zulip.example.com',
      };

      await expect(service.createClient('user1', config)).rejects.toThrow('API Key验证失败');
    });
  });

  describe('消息发送', () => {
    let clientInstance: ZulipClientInstance;

    beforeEach(() => {
      clientInstance = {
        userId: 'user1',
        config: {
          username: 'user@example.com',
          apiKey: 'valid-api-key',
          realm: 'https://zulip.example.com',
        },
        client: mockZulipClient,
        lastEventId: -1,
        createdAt: new Date(),
        lastActivity: new Date(),
        isValid: true,
      };
    });

    it('应该成功发送消息', async () => {
      mockZulipClient.messages.send.mockResolvedValue({
        result: 'success',
        id: 12345,
      });

      const result = await service.sendMessage(clientInstance, 'test-stream', 'test-topic', 'Hello World');

      expect(result.success).toBe(true);
      expect(result.messageId).toBe(12345);
      
      // 验证调用参数
      expect(mockZulipClient.messages.send).toHaveBeenCalledWith({
        type: 'stream',
        to: 'test-stream',
        subject: 'test-topic',
        content: 'Hello World',
      });
    });

    it('应该发送包含特殊字符的消息', async () => {
      const specialMessage = '测试消息 🎮 with special chars: @#$%^&*()';
      
      mockZulipClient.messages.send.mockResolvedValue({
        result: 'success',
        id: 67890,
      });

      const result = await service.sendMessage(clientInstance, 'test-stream', 'test-topic', specialMessage);

      expect(result.success).toBe(true);
      expect(result.messageId).toBe(67890);
      expect(mockZulipClient.messages.send).toHaveBeenCalledWith({
        type: 'stream',
        to: 'test-stream',
        subject: 'test-topic',
        content: specialMessage,
      });
    });

    it('应该处理Zulip API错误', async () => {
      mockZulipClient.messages.send.mockResolvedValue({
        result: 'error',
        msg: 'Stream does not exist',
      });

      const result = await service.sendMessage(clientInstance, 'nonexistent-stream', 'test-topic', 'Hello World');

      expect(result.success).toBe(false);
      expect(result.error).toBe('Stream does not exist');
    });

    it('应该在客户端无效时返回错误', async () => {
      clientInstance.isValid = false;

      const result = await service.sendMessage(clientInstance, 'test-stream', 'test-topic', 'Hello World');

      expect(result.success).toBe(false);
      expect(result.error).toContain('无效');
    });
  });

  describe('事件队列管理', () => {
    let clientInstance: ZulipClientInstance;

    beforeEach(() => {
      clientInstance = {
        userId: 'user1',
        config: {
          username: 'user@example.com',
          apiKey: 'valid-api-key',
          realm: 'https://zulip.example.com',
        },
        client: mockZulipClient,
        lastEventId: -1,
        createdAt: new Date(),
        lastActivity: new Date(),
        isValid: true,
      };
    });

    it('应该成功注册事件队列', async () => {
      mockZulipClient.queues.register.mockResolvedValue({
        result: 'success',
        queue_id: 'queue-123',
        last_event_id: 0,
      });

      const result = await service.registerQueue(clientInstance);

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

    it('应该成功注销事件队列', async () => {
      clientInstance.queueId = 'queue-123';
      mockZulipClient.queues.deregister.mockResolvedValue({
        result: 'success',
      });

      const result = await service.deregisterQueue(clientInstance);

      expect(result).toBe(true);
      expect(clientInstance.queueId).toBeUndefined();
    });
  });

  /**
   * 属性测试: Zulip客户端生命周期管理
   * 
   * **Feature: zulip-integration, Property 2: Zulip客户端生命周期管理**
   * **Validates: Requirements 2.1, 2.2, 2.5**
   * 
   * 对于任何用户的Zulip API Key，系统应该创建专用的Zulip客户端实例，
   * 注册事件队列，并在用户登出时完全清理客户端和队列资源
   */
  describe('Property 2: Zulip客户端生命周期管理', () => {
    /**
     * 属性: 对于任何有效的配置，创建客户端后应该处于有效状态
     */
    it('对于任何有效配置，创建的客户端应该处于有效状态', async () => {
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'success',
        email: 'user@example.com',
      });

      await fc.assert(
        fc.asyncProperty(
          // 生成有效的用户ID
          fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0),
          // 生成有效的邮箱格式
          fc.emailAddress(),
          // 生成有效的API Key
          fc.string({ minLength: 10, maxLength: 100 }).filter(s => s.trim().length >= 10),
          async (userId, email, apiKey) => {
            const config: ZulipClientConfig = {
              username: email,
              apiKey: apiKey,
              realm: 'https://zulip.example.com',
            };

            const client = await service.createClient(userId, config);

            // 验证客户端状态
            expect(client.userId).toBe(userId);
            expect(client.isValid).toBe(true);
            expect(client.config.username).toBe(email);
            expect(client.config.apiKey).toBe(apiKey);
            expect(client.createdAt).toBeInstanceOf(Date);
            expect(client.lastActivity).toBeInstanceOf(Date);
          }
        ),
        { numRuns: 100 }
      );
    }, 30000);

    /**
     * 属性: 对于任何客户端，注册队列后应该有有效的队列ID
     */
    it('对于任何客户端，注册队列后应该有有效的队列ID', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0),
          fc.string({ minLength: 5, maxLength: 50 }).filter(s => s.trim().length >= 5),
          fc.integer({ min: 0, max: 1000 }),
          async (userId, queueId, lastEventId) => {
            mockZulipClient.queues.register.mockResolvedValue({
              result: 'success',
              queue_id: queueId,
              last_event_id: lastEventId,
            });

            const clientInstance: ZulipClientInstance = {
              userId,
              config: {
                username: 'user@example.com',
                apiKey: 'valid-api-key',
                realm: 'https://zulip.example.com',
              },
              client: mockZulipClient,
              lastEventId: -1,
              createdAt: new Date(),
              lastActivity: new Date(),
              isValid: true,
            };

            const result = await service.registerQueue(clientInstance);

            // 验证队列注册结果
            expect(result.success).toBe(true);
            expect(result.queueId).toBe(queueId);
            expect(clientInstance.queueId).toBe(queueId);
            expect(clientInstance.lastEventId).toBe(lastEventId);
          }
        ),
        { numRuns: 100 }
      );
    }, 30000);

    /**
     * 属性: 对于任何客户端，销毁后应该处于无效状态且队列被清理
     */
    it('对于任何客户端，销毁后应该处于无效状态且队列被清理', async () => {
      mockZulipClient.queues.deregister.mockResolvedValue({
        result: 'success',
      });

      await fc.assert(
        fc.asyncProperty(
          fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0),
          fc.string({ minLength: 5, maxLength: 50 }).filter(s => s.trim().length >= 5),
          async (userId, queueId) => {
            const clientInstance: ZulipClientInstance = {
              userId,
              config: {
                username: 'user@example.com',
                apiKey: 'valid-api-key',
                realm: 'https://zulip.example.com',
              },
              client: mockZulipClient,
              queueId: queueId,
              lastEventId: 10,
              createdAt: new Date(),
              lastActivity: new Date(),
              isValid: true,
            };

            await service.destroyClient(clientInstance);

            // 验证客户端被正确销毁
            expect(clientInstance.isValid).toBe(false);
            expect(clientInstance.queueId).toBeUndefined();
            expect(clientInstance.client).toBeNull();
          }
        ),
        { numRuns: 100 }
      );
    }, 30000);

    /**
     * 属性: 创建-注册-销毁的完整生命周期应该正确管理资源
     */
    it('创建-注册-销毁的完整生命周期应该正确管理资源', async () => {
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'success',
        email: 'user@example.com',
      });
      mockZulipClient.queues.register.mockResolvedValue({
        result: 'success',
        queue_id: 'queue-123',
        last_event_id: 0,
      });
      mockZulipClient.queues.deregister.mockResolvedValue({
        result: 'success',
      });

      await fc.assert(
        fc.asyncProperty(
          fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0),
          fc.emailAddress(),
          fc.string({ minLength: 10, maxLength: 100 }).filter(s => s.trim().length >= 10),
          async (userId, email, apiKey) => {
            const config: ZulipClientConfig = {
              username: email,
              apiKey: apiKey,
              realm: 'https://zulip.example.com',
            };

            // 1. 创建客户端
            const client = await service.createClient(userId, config);
            expect(client.isValid).toBe(true);

            // 2. 注册事件队列
            const registerResult = await service.registerQueue(client);
            expect(registerResult.success).toBe(true);
            expect(client.queueId).toBeDefined();

            // 3. 销毁客户端
            await service.destroyClient(client);
            expect(client.isValid).toBe(false);
            expect(client.queueId).toBeUndefined();
          }
        ),
        { numRuns: 100 }
      );
    }, 30000);
  });
});
