/**
 * Zulip消息发送集成测试
 * 
 * 功能描述：
 * - 测试消息发送到真实Zulip服务器的完整流程
 * - 验证HTTP请求、响应处理和错误场景
 * - 包含网络异常和API错误的测试
 * 
 * 注意：这些测试需要真实的Zulip服务器配置
 * 
 * 最近修改：
 * - 2026-01-12: 架构优化 - 从src/core/zulip_core/services/移动到test/integration/，符合测试分离规范 (修改者: moyin)
 * - 2026-01-12: 代码规范优化 - 修正注释规范和修改记录格式 (修改者: moyin)
 * - 2026-01-10: 测试新增 - 创建Zulip消息发送集成测试 (修改者: moyin)
 * 
 * @author moyin
 * @version 1.1.0
 * @since 2026-01-10
 * @lastModified 2026-01-12
 */

import { Test, TestingModule } from '@nestjs/testing';
import { ZulipClientService, ZulipClientConfig, ZulipClientInstance } from '../../src/core/zulip_core/services/zulip_client.service';
import * as nock from 'nock';

describe('ZulipMessageIntegration', () => {
  let service: ZulipClientService;
  let mockZulipClient: any;
  let clientInstance: ZulipClientInstance;

  const testConfig: ZulipClientConfig = {
    username: 'test-bot@example.com',
    apiKey: 'test-api-key-12345',
    realm: 'https://test-zulip.example.com',
  };

  beforeEach(async () => {
    // 清理所有HTTP拦截
    nock.cleanAll();

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

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

    // 创建模拟的zulip-js客户端
    mockZulipClient = {
      config: testConfig,
      users: {
        me: {
          getProfile: jest.fn(),
        },
      },
      messages: {
        send: jest.fn(),
      },
      queues: {
        register: jest.fn(),
        deregister: jest.fn(),
      },
      events: {
        retrieve: jest.fn(),
      },
    };

    // 模拟客户端实例
    clientInstance = {
      userId: 'test-user-123',
      config: testConfig,
      client: mockZulipClient,
      lastEventId: -1,
      createdAt: new Date(),
      lastActivity: new Date(),
      isValid: true,
    };

    // Mock zulip-js模块加载
    jest.spyOn(service as any, 'loadZulipModule').mockResolvedValue(() => mockZulipClient);
  });

  afterEach(() => {
    nock.cleanAll();
    jest.clearAllMocks();
  });

  describe('消息发送到Zulip服务器', () => {
    it('应该成功发送消息到Zulip API', async () => {
      // 模拟成功的API响应
      mockZulipClient.messages.send.mockResolvedValue({
        result: 'success',
        id: 12345,
        msg: '',
      });

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

      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 from integration test!',
      });
    });

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

      const result = await service.sendMessage(
        clientInstance,
        'nonexistent-stream',
        'test-topic',
        'This should fail'
      );

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

    it('应该处理网络连接异常', async () => {
      // 模拟网络异常
      mockZulipClient.messages.send.mockRejectedValue(new Error('Network timeout'));

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

      expect(result.success).toBe(false);
      expect(result.error).toBe('Network timeout');
    });

    it('应该处理认证失败', async () => {
      // 模拟认证失败
      mockZulipClient.messages.send.mockResolvedValue({
        result: 'error',
        msg: 'Invalid API key',
        code: 'BAD_REQUEST',
      });

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

      expect(result.success).toBe(false);
      expect(result.error).toBe('Invalid API key');
    });

    it('应该正确处理特殊字符和长消息', async () => {
      const longMessage = 'A'.repeat(1000) + '特殊字符测试: 🎮🎯🚀 @#$%^&*()';
      
      mockZulipClient.messages.send.mockResolvedValue({
        result: 'success',
        id: 67890,
      });

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

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

    it('应该更新客户端最后活动时间', async () => {
      const initialTime = new Date('2026-01-01T00:00:00Z');
      clientInstance.lastActivity = initialTime;

      mockZulipClient.messages.send.mockResolvedValue({
        result: 'success',
        id: 11111,
      });

      await service.sendMessage(
        clientInstance,
        'test-stream',
        'test-topic',
        'Activity test'
      );

      expect(clientInstance.lastActivity.getTime()).toBeGreaterThan(initialTime.getTime());
    });
  });

  describe('事件队列与Zulip服务器交互', () => {
    it('应该成功注册事件队列', async () => {
      mockZulipClient.queues.register.mockResolvedValue({
        result: 'success',
        queue_id: 'test-queue-123',
        last_event_id: 42,
      });

      const result = await service.registerQueue(clientInstance, ['message', 'typing']);

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

    it('应该处理队列注册失败', async () => {
      mockZulipClient.queues.register.mockResolvedValue({
        result: 'error',
        msg: 'Rate limit exceeded',
      });

      const result = await service.registerQueue(clientInstance);

      expect(result.success).toBe(false);
      expect(result.error).toBe('Rate limit exceeded');
    });

    it('应该成功获取事件', async () => {
      clientInstance.queueId = 'test-queue-123';
      clientInstance.lastEventId = 10;

      const mockEvents = [
        {
          id: 11,
          type: 'message',
          message: {
            id: 98765,
            sender_email: 'user@example.com',
            content: 'Test message from Zulip',
            stream_id: 1,
            subject: 'Test Topic',
          },
        },
        {
          id: 12,
          type: 'typing',
          sender: { user_id: 123 },
        },
      ];

      mockZulipClient.events.retrieve.mockResolvedValue({
        result: 'success',
        events: mockEvents,
      });

      const result = await service.getEvents(clientInstance, true);

      expect(result.success).toBe(true);
      expect(result.events).toEqual(mockEvents);
      expect(clientInstance.lastEventId).toBe(12); // 更新为最后一个事件的ID
    });

    it('应该处理空事件队列', async () => {
      clientInstance.queueId = 'test-queue-123';

      mockZulipClient.events.retrieve.mockResolvedValue({
        result: 'success',
        events: [],
      });

      const result = await service.getEvents(clientInstance, true);

      expect(result.success).toBe(true);
      expect(result.events).toEqual([]);
    });

    it('应该成功注销事件队列', async () => {
      clientInstance.queueId = 'test-queue-123';

      mockZulipClient.queues.deregister.mockResolvedValue({
        result: 'success',
      });

      const result = await service.deregisterQueue(clientInstance);

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

    it('应该处理队列过期情况', async () => {
      clientInstance.queueId = 'expired-queue';

      // 模拟队列过期的JSON解析错误
      mockZulipClient.queues.deregister.mockRejectedValue(
        new Error('invalid json response body at https://zulip.example.com/api/v1/events reason: Unexpected token')
      );

      const result = await service.deregisterQueue(clientInstance);

      expect(result).toBe(true); // 应该返回true，因为队列已过期
      expect(clientInstance.queueId).toBeUndefined();
      expect(clientInstance.lastEventId).toBe(-1);
    });
  });

  describe('API Key验证', () => {
    it('应该成功验证有效的API Key', async () => {
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'success',
        email: 'test-bot@example.com',
        full_name: 'Test Bot',
        user_id: 123,
      });

      const isValid = await service.validateApiKey(clientInstance);

      expect(isValid).toBe(true);
      expect(clientInstance.isValid).toBe(true);
    });

    it('应该拒绝无效的API Key', async () => {
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'error',
        msg: 'Invalid API key',
      });

      const isValid = await service.validateApiKey(clientInstance);

      expect(isValid).toBe(false);
      expect(clientInstance.isValid).toBe(false);
    });

    it('应该处理API Key验证网络异常', async () => {
      mockZulipClient.users.me.getProfile.mockRejectedValue(new Error('Connection refused'));

      const isValid = await service.validateApiKey(clientInstance);

      expect(isValid).toBe(false);
      expect(clientInstance.isValid).toBe(false);
    });
  });

  describe('错误恢复和重试机制', () => {
    it('应该在临时网络错误后恢复', async () => {
      // 第一次调用失败，第二次成功
      mockZulipClient.messages.send
        .mockRejectedValueOnce(new Error('Temporary network error'))
        .mockResolvedValueOnce({
          result: 'success',
          id: 99999,
        });

      // 第一次调用应该失败
      const firstResult = await service.sendMessage(
        clientInstance,
        'test-stream',
        'test-topic',
        'First attempt'
      );
      expect(firstResult.success).toBe(false);

      // 第二次调用应该成功
      const secondResult = await service.sendMessage(
        clientInstance,
        'test-stream',
        'test-topic',
        'Second attempt'
      );
      expect(secondResult.success).toBe(true);
      expect(secondResult.messageId).toBe(99999);
    });

    it('应该处理服务器5xx错误', async () => {
      mockZulipClient.messages.send.mockRejectedValue(new Error('Internal Server Error (500)'));

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

      expect(result.success).toBe(false);
      expect(result.error).toBe('Internal Server Error (500)');
    });
  });

  describe('性能和并发测试', () => {
    it('应该处理并发消息发送', async () => {
      // 模拟多个并发消息 - 设置一次mock，让它返回不同的ID
      mockZulipClient.messages.send.mockImplementation(() => {
        const id = Math.floor(Math.random() * 10000) + 1000;
        return Promise.resolve({
          result: 'success',
          id: id,
        });
      });

      // 创建并发消息发送的Promise数组
      const messagePromises: Promise<any>[] = [];
      
      for (let i = 0; i < 10; i++) {
        messagePromises.push(
          service.sendMessage(
            clientInstance,
            'test-stream',
            'concurrent-topic',
            `Concurrent message ${i}`
          )
        );
      }

      const results = await Promise.all(messagePromises);

      results.forEach((result) => {
        expect(result.success).toBe(true);
        expect(result.messageId).toBeGreaterThan(999);
      });
    });

    it('应该在大量消息发送时保持性能', async () => {
      const startTime = Date.now();
      const messageCount = 100;

      mockZulipClient.messages.send.mockImplementation(() => 
        Promise.resolve({
          result: 'success',
          id: Math.floor(Math.random() * 100000),
        })
      );

      const promises = Array.from({ length: messageCount }, (_, i) =>
        service.sendMessage(
          clientInstance,
          'performance-stream',
          'performance-topic',
          `Performance test message ${i}`
        )
      );

      const results = await Promise.all(promises);
      const endTime = Date.now();
      const duration = endTime - startTime;

      // 验证所有消息都成功发送
      results.forEach(result => {
        expect(result.success).toBe(true);
      });

      // 性能检查：100条消息应该在合理时间内完成（这里设为5秒）
      expect(duration).toBeLessThan(5000);
      
      console.log(`发送${messageCount}条消息耗时: ${duration}ms`);
    }, 10000);
  });
});