/**
 * 聊天 HTTP 控制器单元测试
 * 
 * 功能描述：
 * - 测试 ChatController 的所有 HTTP 端点
 * - 验证请求处理和响应格式
 * - 测试错误处理机制
 * 
 * 测试范围：
 * - sendMessage() - 发送消息端点
 * - getChatHistory() - 获取历史记录端点
 * - getSystemStatus() - 获取系统状态端点
 * - getWebSocketInfo() - 获取 WebSocket 信息端点
 * 
 * @author moyin
 * @version 1.0.0
 * @since 2026-01-14
 */

import { Test, TestingModule } from '@nestjs/testing';
import { HttpException, HttpStatus } from '@nestjs/common';
import { ChatController } from './chat.controller';
import { ChatService } from '../../business/chat/chat.service';
import { ChatWebSocketGateway } from './chat.gateway';
import { SendChatMessageDto, GetChatHistoryDto } from './chat.dto';
import { JwtAuthGuard } from '../auth/jwt_auth.guard';

describe('ChatController', () => {
  let controller: ChatController;
  let mockChatService: jest.Mocked<Partial<ChatService>>;
  let mockWebSocketGateway: jest.Mocked<Partial<ChatWebSocketGateway>>;

  beforeEach(async () => {
    mockChatService = {
      getChatHistory: jest.fn(),
    };

    mockWebSocketGateway = {
      getConnectionCount: jest.fn(),
      getAuthenticatedConnectionCount: jest.fn(),
      getMapPlayerCounts: jest.fn(),
    };

    const module: TestingModule = await Test.createTestingModule({
      controllers: [ChatController],
      providers: [
        { provide: ChatService, useValue: mockChatService },
        { provide: ChatWebSocketGateway, useValue: mockWebSocketGateway },
      ],
    })
      .overrideGuard(JwtAuthGuard)
      .useValue({ canActivate: () => true })
      .compile();

    controller = module.get<ChatController>(ChatController);
  });

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

  describe('sendMessage', () => {
    it('should throw HttpException indicating WebSocket is required', async () => {
      const dto: SendChatMessageDto = {
        content: '测试消息',
        scope: 'local',
      };

      await expect(controller.sendMessage(dto)).rejects.toThrow(HttpException);
      await expect(controller.sendMessage(dto)).rejects.toThrow(
        '聊天消息发送需要通过 WebSocket 连接'
      );
    });

    it('should throw HttpException with BAD_REQUEST status', async () => {
      const dto: SendChatMessageDto = {
        content: '测试消息',
        scope: 'local',
      };

      try {
        await controller.sendMessage(dto);
        fail('Expected HttpException to be thrown');
      } catch (error) {
        expect(error).toBeInstanceOf(HttpException);
        expect((error as HttpException).getStatus()).toBe(HttpStatus.BAD_REQUEST);
      }
    });
  });

  describe('getChatHistory', () => {
    it('should return chat history successfully', async () => {
      const query: GetChatHistoryDto = {
        mapId: 'whale_port',
        limit: 50,
        offset: 0,
      };

      const mockResult = {
        success: true,
        messages: [
          {
            id: 1,
            sender: 'Player_1',
            content: '你好',
            scope: 'local',
            mapId: 'whale_port',
            timestamp: '2026-01-14T10:00:00.000Z',
            streamName: 'Whale Port',
            topicName: 'Game Chat',
          },
        ],
        total: 1,
        count: 1,
      };

      mockChatService.getChatHistory.mockResolvedValue(mockResult);

      const result = await controller.getChatHistory(query);

      expect(result).toEqual(mockResult);
      expect(mockChatService.getChatHistory).toHaveBeenCalledWith(query);
    });

    it('should throw HttpException when getChatHistory fails', async () => {
      const query: GetChatHistoryDto = {
        mapId: 'whale_port',
      };

      mockChatService.getChatHistory.mockRejectedValue(new Error('Database error'));

      await expect(controller.getChatHistory(query)).rejects.toThrow(HttpException);
    });

    it('should use default values for optional parameters', async () => {
      const query: GetChatHistoryDto = {};

      const mockResult = {
        success: true,
        messages: [],
        total: 0,
        count: 0,
      };

      mockChatService.getChatHistory.mockResolvedValue(mockResult);

      await controller.getChatHistory(query);

      expect(mockChatService.getChatHistory).toHaveBeenCalledWith(query);
    });
  });

  describe('getSystemStatus', () => {
    it('should return system status successfully', async () => {
      mockWebSocketGateway.getConnectionCount.mockReturnValue(10);
      mockWebSocketGateway.getAuthenticatedConnectionCount.mockReturnValue(8);
      mockWebSocketGateway.getMapPlayerCounts.mockReturnValue({
        whale_port: 5,
        pumpkin_valley: 3,
      });

      const result = await controller.getSystemStatus();

      expect(result.websocket.totalConnections).toBe(10);
      expect(result.websocket.authenticatedConnections).toBe(8);
      expect(result.websocket.activeSessions).toBe(8);
      expect(result.websocket.mapPlayerCounts).toEqual({
        whale_port: 5,
        pumpkin_valley: 3,
      });
      expect(result.zulip.serverConnected).toBe(true);
      expect(result.uptime).toBeGreaterThanOrEqual(0);
      expect(result.memory).toBeDefined();
    });

    it('should include memory usage information', async () => {
      mockWebSocketGateway.getConnectionCount.mockReturnValue(0);
      mockWebSocketGateway.getAuthenticatedConnectionCount.mockReturnValue(0);
      mockWebSocketGateway.getMapPlayerCounts.mockReturnValue({});

      const result = await controller.getSystemStatus();

      expect(result.memory.used).toMatch(/\d+(\.\d+)? MB/);
      expect(result.memory.total).toMatch(/\d+(\.\d+)? MB/);
      expect(typeof result.memory.percentage).toBe('number');
    });

    it('should throw HttpException when getSystemStatus fails', async () => {
      mockWebSocketGateway.getConnectionCount.mockImplementation(() => {
        throw new Error('Gateway error');
      });

      await expect(controller.getSystemStatus()).rejects.toThrow(HttpException);
    });
  });

  describe('getWebSocketInfo', () => {
    it('should return WebSocket connection information', async () => {
      const result = await controller.getWebSocketInfo();

      expect(result.websocketUrl).toBe('wss://whaletownend.xinghangee.icu/game');
      expect(result.protocol).toBe('native-websocket');
      expect(result.path).toBe('/game');
      expect(result.supportedEvents).toContain('login');
      expect(result.supportedEvents).toContain('chat');
      expect(result.supportedEvents).toContain('position');
      expect(result.supportedResponses).toContain('connected');
      expect(result.supportedResponses).toContain('login_success');
      expect(result.authRequired).toBe(true);
      expect(result.tokenType).toBe('JWT');
    });
  });
});
