/**
 * 用户状态管理控制器测试
 * 
 * 功能描述：
 * - 测试用户状态管理API接口
 * - 测试HTTP请求处理和参数验证
 * - 测试权限控制和频率限制
 * - 测试响应格式和错误处理
 * 
 * 职责分离：
 * - 单元测试覆盖所有API端点
 * - Mock业务服务依赖
 * - 验证请求参数和响应格式
 * 
 * 最近修改：
 * - 2026-01-07: 代码规范优化 - 创建完整的控制器测试覆盖 (修改者: moyin)
 * 
 * @author moyin
 * @version 1.0.1
 * @since 2026-01-07
 * @lastModified 2026-01-07
 */

import { Test, TestingModule } from '@nestjs/testing';
import { Logger } from '@nestjs/common';
import { UserStatusController } from './user_status.controller';
import { UserManagementService } from './user_management.service';
import { AdminGuard } from '../admin/admin.guard';
import { UserStatusDto, BatchUserStatusDto } from './user_status.dto';
import { UserStatus } from './user_status.enum';
import { BATCH_OPERATION } from './user_mgmt.constants';

describe('UserStatusController', () => {
  let controller: UserStatusController;
  let mockUserManagementService: jest.Mocked<UserManagementService>;

  beforeEach(async () => {
    const mockUserManagementServiceProvider = {
      updateUserStatus: jest.fn(),
      batchUpdateUserStatus: jest.fn(),
      getUserStatusStats: jest.fn(),
    };

    const module: TestingModule = await Test.createTestingModule({
      controllers: [UserStatusController],
      providers: [
        {
          provide: UserManagementService,
          useValue: mockUserManagementServiceProvider,
        },
      ],
    })
    .overrideGuard(AdminGuard)
    .useValue({ canActivate: jest.fn(() => true) })
    .compile();

    controller = module.get<UserStatusController>(UserStatusController);
    mockUserManagementService = module.get(UserManagementService);

    // Mock Logger to avoid console output during tests
    jest.spyOn(Logger.prototype, 'log').mockImplementation();
  });

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

  describe('updateUserStatus', () => {
    it('should update user status successfully', async () => {
      // Arrange
      const userId = '123';
      const userStatusDto: UserStatusDto = {
        status: UserStatus.ACTIVE,
        reason: '用户申诉通过'
      };
      const expectedResult = {
        success: true,
        data: {
          user: {
            id: '123',
            username: 'testuser',
            nickname: '测试用户',
            status: UserStatus.ACTIVE,
            status_description: '正常',
            updated_at: new Date()
          },
          reason: '用户申诉通过'
        },
        message: '用户状态修改成功'
      };

      mockUserManagementService.updateUserStatus.mockResolvedValue(expectedResult);

      // Act
      const result = await controller.updateUserStatus(userId, userStatusDto);

      // Assert
      expect(result).toEqual(expectedResult);
      expect(mockUserManagementService.updateUserStatus).toHaveBeenCalledWith(BigInt(123), userStatusDto);
      expect(mockUserManagementService.updateUserStatus).toHaveBeenCalledTimes(1);
    });

    it('should handle user not found error', async () => {
      // Arrange
      const userId = '999';
      const userStatusDto: UserStatusDto = {
        status: UserStatus.LOCKED,
        reason: '违规操作'
      };
      const expectedResult = {
        success: false,
        message: '用户不存在',
        error_code: 'USER_NOT_FOUND'
      };

      mockUserManagementService.updateUserStatus.mockResolvedValue(expectedResult);

      // Act
      const result = await controller.updateUserStatus(userId, userStatusDto);

      // Assert
      expect(result).toEqual(expectedResult);
      expect(mockUserManagementService.updateUserStatus).toHaveBeenCalledWith(BigInt(999), userStatusDto);
    });

    it('should log operation details', async () => {
      // Arrange
      const userId = '456';
      const userStatusDto: UserStatusDto = {
        status: UserStatus.BANNED,
        reason: '严重违规'
      };
      const mockResult = {
        success: true,
        data: {
          user: {
            id: '456',
            username: 'testuser',
            nickname: '测试用户',
            status: UserStatus.BANNED,
            status_description: '已封禁',
            updated_at: new Date()
          },
          reason: '严重违规'
        },
        message: '成功'
      };
      mockUserManagementService.updateUserStatus.mockResolvedValue(mockResult);
      const logSpy = jest.spyOn(Logger.prototype, 'log');

      // Act
      await controller.updateUserStatus(userId, userStatusDto);

      // Assert
      expect(logSpy).toHaveBeenCalledWith(
        '管理员修改用户状态',
        expect.objectContaining({
          operation: 'update_user_status',
          userId: '456',
          newStatus: UserStatus.BANNED,
          reason: '严重违规'
        })
      );
    });

    it('should convert string id to BigInt correctly', async () => {
      // Arrange
      const userId = '9007199254740991'; // Large number as string
      const userStatusDto: UserStatusDto = {
        status: UserStatus.INACTIVE,
        reason: '长期未活跃'
      };
      const mockResult = {
        success: true,
        data: {
          user: {
            id: '9007199254740991',
            username: 'large_id_user',
            nickname: '大ID用户',
            status: UserStatus.INACTIVE,
            status_description: '非活跃',
            updated_at: new Date()
          },
          reason: '长期未活跃'
        },
        message: '成功'
      };

      mockUserManagementService.updateUserStatus.mockResolvedValue(mockResult);

      // Act
      await controller.updateUserStatus(userId, userStatusDto);

      // Assert
      expect(mockUserManagementService.updateUserStatus).toHaveBeenCalledWith(
        BigInt('9007199254740991'),
        userStatusDto
      );
    });
  });

  describe('batchUpdateUserStatus', () => {
    it('should batch update user status successfully', async () => {
      // Arrange
      const batchUserStatusDto: BatchUserStatusDto = {
        userIds: ['1', '2', '3'],
        status: UserStatus.LOCKED,
        reason: '批量锁定违规用户'
      };
      const expectedResult = {
        success: true,
        data: {
          result: {
            success_users: [
              { id: '1', username: 'user1', nickname: '用户1', status: UserStatus.LOCKED, status_description: '已锁定', updated_at: new Date() },
              { id: '2', username: 'user2', nickname: '用户2', status: UserStatus.LOCKED, status_description: '已锁定', updated_at: new Date() },
              { id: '3', username: 'user3', nickname: '用户3', status: UserStatus.LOCKED, status_description: '已锁定', updated_at: new Date() }
            ],
            failed_users: [],
            success_count: 3,
            failed_count: 0,
            total_count: 3
          },
          reason: '批量锁定违规用户'
        },
        message: '批量用户状态修改完成'
      };

      mockUserManagementService.batchUpdateUserStatus.mockResolvedValue(expectedResult);

      // Act
      const result = await controller.batchUpdateUserStatus(batchUserStatusDto);

      // Assert
      expect(result).toEqual(expectedResult);
      expect(mockUserManagementService.batchUpdateUserStatus).toHaveBeenCalledWith(batchUserStatusDto);
      expect(mockUserManagementService.batchUpdateUserStatus).toHaveBeenCalledTimes(1);
    });

    it('should handle partial success in batch operation', async () => {
      // Arrange
      const batchUserStatusDto: BatchUserStatusDto = {
        userIds: ['1', '2', '999'],
        status: UserStatus.ACTIVE,
        reason: '批量激活用户'
      };
      const expectedResult = {
        success: true,
        data: {
          result: {
            success_users: [
              { id: '1', username: 'user1', nickname: '用户1', status: UserStatus.ACTIVE, status_description: '正常', updated_at: new Date() },
              { id: '2', username: 'user2', nickname: '用户2', status: UserStatus.ACTIVE, status_description: '正常', updated_at: new Date() }
            ],
            failed_users: [
              { user_id: '999', error: '用户不存在' }
            ],
            success_count: 2,
            failed_count: 1,
            total_count: 3
          },
          reason: '批量激活用户'
        },
        message: '批量用户状态修改完成'
      };

      mockUserManagementService.batchUpdateUserStatus.mockResolvedValue(expectedResult);

      // Act
      const result = await controller.batchUpdateUserStatus(batchUserStatusDto);

      // Assert
      expect(result).toEqual(expectedResult);
      expect(result.data.result.success_count).toBe(2);
      expect(result.data.result.failed_count).toBe(1);
    });

    it('should handle empty user list', async () => {
      // Arrange
      const batchUserStatusDto: BatchUserStatusDto = {
        userIds: [],
        status: UserStatus.ACTIVE,
        reason: '空列表测试'
      };
      const expectedResult = {
        success: true,
        data: {
          result: {
            success_users: [],
            failed_users: [],
            success_count: 0,
            failed_count: 0,
            total_count: 0
          },
          reason: '空列表测试'
        },
        message: '批量操作完成'
      };

      mockUserManagementService.batchUpdateUserStatus.mockResolvedValue(expectedResult);

      // Act
      const result = await controller.batchUpdateUserStatus(batchUserStatusDto);

      // Assert
      expect(result).toEqual(expectedResult);
      expect(result.data.result.total_count).toBe(0);
    });

    it('should log batch operation details', async () => {
      // Arrange
      const batchUserStatusDto: BatchUserStatusDto = {
        userIds: ['1', '2', '3', '4', '5'],
        status: UserStatus.BANNED,
        reason: '批量封禁违规用户'
      };
      const mockResult = {
        success: true,
        data: {
          result: {
            success_users: [],
            failed_users: [],
            success_count: 0,
            failed_count: 0,
            total_count: 0
          }
        },
        message: '成功'
      };

      mockUserManagementService.batchUpdateUserStatus.mockResolvedValue(mockResult);
      const logSpy = jest.spyOn(Logger.prototype, 'log');

      // Act
      await controller.batchUpdateUserStatus(batchUserStatusDto);

      // Assert
      expect(logSpy).toHaveBeenCalledWith(
        '管理员批量修改用户状态',
        expect.objectContaining({
          operation: 'batch_update_user_status',
          userCount: 5,
          newStatus: UserStatus.BANNED,
          reason: '批量封禁违规用户'
        })
      );
    });

    it('should handle large user list within limits', async () => {
      // Arrange
      const userIds = Array.from({ length: BATCH_OPERATION.MAX_USER_COUNT }, (_, i) => i.toString());
      const batchUserStatusDto: BatchUserStatusDto = {
        userIds,
        status: UserStatus.INACTIVE,
        reason: '批量设置非活跃'
      };
      const mockResult = {
        success: true,
        data: {
          result: {
            success_users: userIds.map(id => ({ 
              id, 
              username: `user_${id}`,
              nickname: `用户_${id}`,
              status: UserStatus.INACTIVE,
              status_description: '非活跃',
              updated_at: new Date()
            })),
            failed_users: [],
            success_count: userIds.length,
            failed_count: 0,
            total_count: userIds.length
          }
        },
        message: '批量操作完成'
      };

      mockUserManagementService.batchUpdateUserStatus.mockResolvedValue(mockResult);

      // Act
      const result = await controller.batchUpdateUserStatus(batchUserStatusDto);

      // Assert
      expect(result.success).toBe(true);
      expect(result.data.result.total_count).toBe(BATCH_OPERATION.MAX_USER_COUNT);
      expect(mockUserManagementService.batchUpdateUserStatus).toHaveBeenCalledWith(batchUserStatusDto);
    });
  });

  describe('getUserStatusStats', () => {
    it('should get user status statistics successfully', async () => {
      // Arrange
      const expectedResult = {
        success: true,
        data: {
          stats: {
            active: 1250,
            inactive: 45,
            locked: 12,
            banned: 8,
            deleted: 3,
            pending: 15,
            total: 1333
          },
          timestamp: '2026-01-07T10:00:00.000Z'
        },
        message: '用户状态统计获取成功'
      };

      mockUserManagementService.getUserStatusStats.mockResolvedValue(expectedResult);

      // Act
      const result = await controller.getUserStatusStats();

      // Assert
      expect(result).toEqual(expectedResult);
      expect(mockUserManagementService.getUserStatusStats).toHaveBeenCalledTimes(1);
    });

    it('should handle statistics retrieval failure', async () => {
      // Arrange
      const expectedResult = {
        success: false,
        message: '统计数据获取失败',
        error_code: 'STATS_RETRIEVAL_FAILED'
      };

      mockUserManagementService.getUserStatusStats.mockResolvedValue(expectedResult);

      // Act
      const result = await controller.getUserStatusStats();

      // Assert
      expect(result).toEqual(expectedResult);
      expect(result.success).toBe(false);
    });

    it('should log statistics query operation', async () => {
      // Arrange
      const mockResult = {
        success: true,
        data: {
          stats: {
            active: 800,
            inactive: 150,
            locked: 30,
            banned: 15,
            deleted: 5,
            pending: 20,
            total: 1020
          },
          timestamp: '2026-01-07T15:30:00.000Z'
        },
        message: '成功'
      };

      mockUserManagementService.getUserStatusStats.mockResolvedValue(mockResult);
      const logSpy = jest.spyOn(Logger.prototype, 'log');

      // Act
      await controller.getUserStatusStats();

      // Assert
      expect(logSpy).toHaveBeenCalledWith(
        '管理员获取用户状态统计',
        expect.objectContaining({
          operation: 'get_user_status_stats'
        })
      );
    });

    it('should return detailed statistics breakdown', async () => {
      // Arrange
      const expectedResult = {
        success: true,
        data: {
          stats: {
            active: 800,
            inactive: 150,
            locked: 30,
            banned: 15,
            deleted: 5,
            pending: 20,
            total: 1020
          },
          timestamp: '2026-01-07T15:30:00.000Z',
          metadata: {
            last_updated: '2026-01-07T15:30:00.000Z',
            cache_duration: 300
          }
        },
        message: '用户状态统计获取成功'
      };

      mockUserManagementService.getUserStatusStats.mockResolvedValue(expectedResult);

      // Act
      const result = await controller.getUserStatusStats();

      // Assert
      expect(result.data.stats.total).toBe(1020);
      expect(result.data.stats.active).toBe(800);
      expect(result.data.stats.locked).toBe(30);
      expect(result.data.stats.banned).toBe(15);
    });

    it('should handle zero statistics gracefully', async () => {
      // Arrange
      const expectedResult = {
        success: true,
        data: {
          stats: {
            active: 0,
            inactive: 0,
            locked: 0,
            banned: 0,
            deleted: 0,
            pending: 0,
            total: 0
          },
          timestamp: '2026-01-07T10:00:00.000Z'
        },
        message: '用户状态统计获取成功'
      };

      mockUserManagementService.getUserStatusStats.mockResolvedValue(expectedResult);

      // Act
      const result = await controller.getUserStatusStats();

      // Assert
      expect(result.data.stats.total).toBe(0);
      expect(result.success).toBe(true);
    });
  });

  describe('AdminGuard Integration', () => {
    it('should be protected by AdminGuard', () => {
      // Verify that AdminGuard is applied to the controller methods
      const updateUserStatusMethod = Reflect.getMetadata('__guards__', UserStatusController.prototype.updateUserStatus);
      const batchUpdateMethod = Reflect.getMetadata('__guards__', UserStatusController.prototype.batchUpdateUserStatus);
      const getStatsMethod = Reflect.getMetadata('__guards__', UserStatusController.prototype.getUserStatusStats);
      
      // At least one method should have guards (they are applied via @UseGuards decorator)
      expect(updateUserStatusMethod || batchUpdateMethod || getStatsMethod).toBeTruthy();
    });
  });

  describe('Error Handling', () => {
    it('should handle service errors gracefully in updateUserStatus', async () => {
      // Arrange
      const userId = '123';
      const userStatusDto: UserStatusDto = {
        status: UserStatus.ACTIVE,
        reason: '测试错误处理'
      };

      mockUserManagementService.updateUserStatus.mockRejectedValue(new Error('Service error'));

      // Act & Assert
      await expect(controller.updateUserStatus(userId, userStatusDto)).rejects.toThrow('Service error');
    });

    it('should handle service errors gracefully in batchUpdateUserStatus', async () => {
      // Arrange
      const batchUserStatusDto: BatchUserStatusDto = {
        userIds: ['1', '2'],
        status: UserStatus.ACTIVE,
        reason: '测试错误处理'
      };

      mockUserManagementService.batchUpdateUserStatus.mockRejectedValue(new Error('Batch service error'));

      // Act & Assert
      await expect(controller.batchUpdateUserStatus(batchUserStatusDto)).rejects.toThrow('Batch service error');
    });

    it('should handle service errors gracefully in getUserStatusStats', async () => {
      // Arrange
      mockUserManagementService.getUserStatusStats.mockRejectedValue(new Error('Stats service error'));

      // Act & Assert
      await expect(controller.getUserStatusStats()).rejects.toThrow('Stats service error');
    });
  });
});