/**
 * DatabaseManagementService 单元测试
 * 
 * 测试目标：
 * - 验证服务类各个方法的具体实现
 * - 测试边界条件和异常情况
 * - 确保代码覆盖率达标
 * 
 * 最近修改：
 * - 2026-01-08: 注释规范优化 - 修正@author字段，更新版本号和修改记录 (修改者: moyin)
 * - 2026-01-08: 功能新增 - 创建DatabaseManagementService单元测试 (修改者: assistant)
 * 
 * @author moyin
 * @version 1.0.1
 * @since 2026-01-08
 * @lastModified 2026-01-08
 */

import { Test, TestingModule } from '@nestjs/testing';
import { ConfigModule } from '@nestjs/config';
import { DatabaseManagementService } from './database_management.service';
import { AdminOperationLogService } from './admin_operation_log.service';
import { UserStatus } from '../user_mgmt/user_status.enum';

describe('DatabaseManagementService Unit Tests', () => {
  let service: DatabaseManagementService;
  let mockUsersService: any;
  let mockUserProfilesService: any;
  let mockZulipAccountsService: any;
  let mockLogService: any;

  beforeEach(async () => {
    mockUsersService = {
      findAll: jest.fn(),
      findOne: jest.fn(),
      create: jest.fn(),
      update: jest.fn(),
      remove: jest.fn(),
      search: jest.fn(),
      count: jest.fn()
    };

    mockUserProfilesService = {
      findAll: jest.fn(),
      findOne: jest.fn(),
      create: jest.fn(),
      update: jest.fn(),
      remove: jest.fn(),
      findByMap: jest.fn(),
      count: jest.fn()
    };

    mockZulipAccountsService = {
      findMany: jest.fn(),
      findById: jest.fn(),
      create: jest.fn(),
      update: jest.fn(),
      delete: jest.fn(),
      batchUpdateStatus: jest.fn().mockResolvedValue({ success: true, updatedCount: 0 }),
      getStatusStatistics: jest.fn()
    };

    mockLogService = {
      createLog: jest.fn().mockResolvedValue({}),
      queryLogs: jest.fn().mockResolvedValue({ logs: [], total: 0 }),
      getLogById: jest.fn().mockResolvedValue(null),
      getStatistics: jest.fn().mockResolvedValue({}),
      cleanupExpiredLogs: jest.fn().mockResolvedValue(0),
      getAdminOperationHistory: jest.fn().mockResolvedValue([]),
      getSensitiveOperations: jest.fn().mockResolvedValue({ logs: [], total: 0 })
    };

    const module: TestingModule = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          envFilePath: ['.env.test', '.env']
        })
      ],
      providers: [
        DatabaseManagementService,
        {
          provide: AdminOperationLogService,
          useValue: mockLogService
        },
        {
          provide: 'UsersService',
          useValue: mockUsersService
        },
        {
          provide: 'IUserProfilesService',
          useValue: mockUserProfilesService
        },
        {
          provide: 'ZulipAccountsService',
          useValue: mockZulipAccountsService
        }
      ]
    }).compile();

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

  describe('User Management', () => {
    describe('getUserList', () => {
      it('should return paginated user list with correct format', async () => {
        const mockUsers = [
          { id: BigInt(1), username: 'user1', email: 'user1@test.com' },
          { id: BigInt(2), username: 'user2', email: 'user2@test.com' }
        ];
        const totalCount = 10;

        mockUsersService.findAll.mockResolvedValue(mockUsers);
        mockUsersService.count.mockResolvedValue(totalCount);

        const result = await service.getUserList(5, 0);

        expect(result.success).toBe(true);
        expect(result.data.items).toEqual(mockUsers.map(u => ({ ...u, id: u.id.toString() })));
        expect(result.data.total).toBe(totalCount);
        expect(result.data.limit).toBe(5);
        expect(result.data.offset).toBe(0);
        expect(result.data.has_more).toBe(true);
      });

      it('should handle empty result set', async () => {
        mockUsersService.findAll.mockResolvedValue([]);
        mockUsersService.count.mockResolvedValue(0);

        const result = await service.getUserList(10, 0);

        expect(result.success).toBe(true);
        expect(result.data.items).toEqual([]);
        expect(result.data.total).toBe(0);
        expect(result.data.has_more).toBe(false);
      });

      it('should apply limit and offset correctly', async () => {
        const mockUsers = [{ id: BigInt(1), username: 'user1' }];
        mockUsersService.findAll.mockResolvedValue(mockUsers);
        mockUsersService.count.mockResolvedValue(1);

        await service.getUserList(20, 10);

        expect(mockUsersService.findAll).toHaveBeenCalledWith(undefined, 20, 10);
      });

      it('should enforce maximum limit', async () => {
        mockUsersService.findAll.mockResolvedValue([]);
        mockUsersService.count.mockResolvedValue(0);

        await service.getUserList(200, 0); // 超过最大限制

        expect(mockUsersService.findAll).toHaveBeenCalledWith(undefined, 100, 0);
      });

      it('should handle negative offset', async () => {
        mockUsersService.findAll.mockResolvedValue([]);
        mockUsersService.count.mockResolvedValue(0);

        await service.getUserList(10, -5);

        expect(mockUsersService.findAll).toHaveBeenCalledWith(undefined, 10, 0);
      });
    });

    describe('getUserById', () => {
      it('should return user when found', async () => {
        const mockUser = { id: BigInt(1), username: 'testuser', email: 'test@example.com' };
        mockUsersService.findOne.mockResolvedValue(mockUser);

        const result = await service.getUserById(BigInt(1));

        expect(result.success).toBe(true);
        expect(result.data).toEqual({ ...mockUser, id: '1' });
        expect(mockUsersService.findOne).toHaveBeenCalledWith(BigInt(1));
      });

      it('should return error when user not found', async () => {
        mockUsersService.findOne.mockResolvedValue(null);

        const result = await service.getUserById(BigInt(999));

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('USER_NOT_FOUND');
        expect(result.message).toContain('User with ID 999 not found');
      });

      it('should handle invalid ID format', async () => {
        const result = await service.getUserById(BigInt(0)); // 使用有效的 bigint

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('INVALID_USER_ID');
      });

      it('should handle service errors', async () => {
        mockUsersService.findOne.mockRejectedValue(new Error('Database error'));

        const result = await service.getUserById(BigInt(1));

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('DATABASE_ERROR');
      });
    });

    describe('createUser', () => {
      it('should create user successfully', async () => {
        const userData = {
          username: 'newuser',
          email: 'new@example.com',
          nickname: 'New User',
          status: UserStatus.ACTIVE
        };
        const createdUser = { ...userData, id: BigInt(1) };
        
        mockUsersService.create.mockResolvedValue(createdUser);

        const result = await service.createUser(userData);

        expect(result.success).toBe(true);
        expect(result.data).toEqual({ ...createdUser, id: '1' });
        expect(mockUsersService.create).toHaveBeenCalledWith(userData);
      });

      it('should handle duplicate username error', async () => {
        const userData = { username: 'existing', email: 'test@example.com', nickname: 'Existing User', status: UserStatus.ACTIVE };
        mockUsersService.create.mockRejectedValue(new Error('Duplicate key violation'));

        const result = await service.createUser(userData);

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('DUPLICATE_USERNAME');
      });

      it('should validate required fields', async () => {
        const invalidData = { username: '', email: 'test@example.com', nickname: 'Test User', status: UserStatus.ACTIVE };

        const result = await service.createUser(invalidData);

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('VALIDATION_ERROR');
      });

      it('should validate email format', async () => {
        const invalidData = { username: 'test', email: 'invalid-email', nickname: 'Test User', status: UserStatus.ACTIVE };

        const result = await service.createUser(invalidData);

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('VALIDATION_ERROR');
      });
    });

    describe('updateUser', () => {
      it('should update user successfully', async () => {
        const updateData = { nickname: 'Updated Name' };
        const existingUser = { id: BigInt(1), username: 'test', email: 'test@example.com' };
        const updatedUser = { ...existingUser, ...updateData };

        mockUsersService.findOne.mockResolvedValue(existingUser);
        mockUsersService.update.mockResolvedValue(updatedUser);

        const result = await service.updateUser(BigInt(1), updateData);

        expect(result.success).toBe(true);
        expect(result.data).toEqual({ ...updatedUser, id: '1' });
        expect(mockUsersService.update).toHaveBeenCalledWith(BigInt(1), updateData);
      });

      it('should return error when user not found', async () => {
        mockUsersService.findOne.mockResolvedValue(null);

        const result = await service.updateUser(BigInt(999), { nickname: 'New Name' });

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('USER_NOT_FOUND');
      });

      it('should handle empty update data', async () => {
        const result = await service.updateUser(BigInt(1), {});

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('VALIDATION_ERROR');
        expect(result.message).toContain('No valid fields to update');
      });
    });

    describe('deleteUser', () => {
      it('should delete user successfully', async () => {
        const existingUser = { id: BigInt(1), username: 'test' };
        mockUsersService.findOne.mockResolvedValue(existingUser);
        mockUsersService.remove.mockResolvedValue(undefined);

        const result = await service.deleteUser(BigInt(1));

        expect(result.success).toBe(true);
        expect(result.data.deleted).toBe(true);
        expect(result.data.id).toBe('1');
        expect(mockUsersService.remove).toHaveBeenCalledWith(BigInt(1));
      });

      it('should return error when user not found', async () => {
        mockUsersService.findOne.mockResolvedValue(null);

        const result = await service.deleteUser(BigInt(999));

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('USER_NOT_FOUND');
      });
    });

    describe('searchUsers', () => {
      it('should search users successfully', async () => {
        const mockUsers = [
          { id: BigInt(1), username: 'testuser', email: 'test@example.com' }
        ];
        mockUsersService.search.mockResolvedValue(mockUsers);

        const result = await service.searchUsers('test', 10);

        expect(result.success).toBe(true);
        expect(result.data.items).toEqual(mockUsers.map(u => ({ ...u, id: u.id.toString() })));
        expect(mockUsersService.search).toHaveBeenCalledWith('test', 10);
      });

      it('should handle empty search term', async () => {
        const result = await service.searchUsers('', 10);

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('VALIDATION_ERROR');
        expect(result.message).toContain('Search term cannot be empty');
      });

      it('should apply search limit', async () => {
        mockUsersService.search.mockResolvedValue([]);

        await service.searchUsers('test', 200); // 超过限制

        expect(mockUsersService.search).toHaveBeenCalledWith('test', 100);
      });
    });
  });

  describe('User Profile Management', () => {
    describe('getUserProfileList', () => {
      it('should return paginated profile list', async () => {
        const mockProfiles = [
          { id: BigInt(1), user_id: '1', bio: 'Test bio' }
        ];
        mockUserProfilesService.findAll.mockResolvedValue(mockProfiles);
        mockUserProfilesService.count.mockResolvedValue(1);

        const result = await service.getUserProfileList(10, 0);

        expect(result.success).toBe(true);
        expect(result.data.items).toEqual(mockProfiles.map(p => ({ ...p, id: p.id.toString() })));
      });
    });

    describe('createUserProfile', () => {
      it('should create profile successfully', async () => {
        const profileData = {
          user_id: '1',
          bio: 'Test bio',
          current_map: 'plaza',
          pos_x: 100,
          pos_y: 200
        };
        const createdProfile = { ...profileData, id: BigInt(1) };
        
        mockUserProfilesService.create.mockResolvedValue(createdProfile);

        const result = await service.createUserProfile(profileData);

        expect(result.success).toBe(true);
        expect(result.data).toEqual({ ...createdProfile, id: '1' });
      });

      it('should validate position coordinates', async () => {
        const invalidData = {
          user_id: '1',
          bio: 'Test',
          pos_x: 'invalid' as any,
          pos_y: 100
        };

        const result = await service.createUserProfile(invalidData);

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('VALIDATION_ERROR');
      });
    });

    describe('getUserProfilesByMap', () => {
      it('should return profiles by map', async () => {
        const mockProfiles = [
          { id: BigInt(1), user_id: '1', current_map: 'plaza' }
        ];
        mockUserProfilesService.findByMap.mockResolvedValue(mockProfiles);
        mockUserProfilesService.count.mockResolvedValue(1);

        const result = await service.getUserProfilesByMap('plaza', 10, 0);

        expect(result.success).toBe(true);
        expect(result.data.items).toEqual(mockProfiles.map(p => ({ ...p, id: p.id.toString() })));
        expect(mockUserProfilesService.findByMap).toHaveBeenCalledWith('plaza', undefined, 10, 0);
      });

      it('should validate map name', async () => {
        const result = await service.getUserProfilesByMap('', 10, 0);

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('VALIDATION_ERROR');
        expect(result.message).toContain('Map name cannot be empty');
      });
    });
  });

  describe('Zulip Account Management', () => {
    describe('getZulipAccountList', () => {
      it('should return paginated account list', async () => {
        const mockAccounts = [
          { id: '1', gameUserId: '1', zulipEmail: 'test@zulip.com' }
        ];
        mockZulipAccountsService.findMany.mockResolvedValue({
          accounts: mockAccounts,
          total: 1
        });

        const result = await service.getZulipAccountList(10, 0);

        expect(result.success).toBe(true);
        expect(result.data.items).toEqual(mockAccounts);
        expect(result.data.total).toBe(1);
      });
    });

    describe('createZulipAccount', () => {
      it('should create account successfully', async () => {
        const accountData = {
          gameUserId: '1',
          zulipUserId: 123,
          zulipEmail: 'test@zulip.com',
          zulipFullName: 'Test User',
          zulipApiKeyEncrypted: 'encrypted_key',
          status: 'active' as const
        };
        const createdAccount = { ...accountData, id: '1' };
        
        mockZulipAccountsService.create.mockResolvedValue(createdAccount);

        const result = await service.createZulipAccount(accountData);

        expect(result.success).toBe(true);
        expect(result.data).toEqual(createdAccount);
      });

      it('should validate required fields', async () => {
        const invalidData = {
          gameUserId: '',
          zulipUserId: 123,
          zulipEmail: 'test@zulip.com',
          zulipFullName: 'Test',
          zulipApiKeyEncrypted: 'key',
          status: 'active' as const
        };

        const result = await service.createZulipAccount(invalidData);

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('VALIDATION_ERROR');
      });
    });

    describe('batchUpdateZulipAccountStatus', () => {
      it('should update multiple accounts successfully', async () => {
        const ids = ['1', '2'];
        const status = 'active';
        const reason = 'Test update';

        mockZulipAccountsService.update
          .mockResolvedValueOnce({ id: '1', status: 'active' })
          .mockResolvedValueOnce({ id: '2', status: 'active' });

        const result = await service.batchUpdateZulipAccountStatus(ids, status, reason);

        expect(result.success).toBe(true);
        expect(result.data.total).toBe(2);
        expect(result.data.success).toBe(2);
        expect(result.data.failed).toBe(0);
        expect(result.data.results).toHaveLength(2);
      });

      it('should handle partial failures', async () => {
        const ids = ['1', '2'];
        const status = 'active';
        const reason = 'Test update';

        mockZulipAccountsService.update
          .mockResolvedValueOnce({ id: '1', status: 'active' })
          .mockRejectedValueOnce(new Error('Update failed'));

        const result = await service.batchUpdateZulipAccountStatus(ids, status, reason);

        expect(result.success).toBe(true);
        expect(result.data.total).toBe(2);
        expect(result.data.success).toBe(1);
        expect(result.data.failed).toBe(1);
        expect(result.data.errors).toHaveLength(1);
      });

      it('should validate batch data', async () => {
        const ids: string[] = [];
        const status = 'active';
        const reason = 'Test';

        const result = await service.batchUpdateZulipAccountStatus(ids, status, reason);

        expect(result.success).toBe(false);
        expect(result.error_code).toBe('VALIDATION_ERROR');
        expect(result.message).toContain('No account IDs provided');
      });
    });

    describe('getZulipAccountStatistics', () => {
      it('should return statistics successfully', async () => {
        const mockStats = {
          active: 10,
          inactive: 5,
          suspended: 2,
          error: 1,
          total: 18
        };
        mockZulipAccountsService.getStatusStatistics.mockResolvedValue(mockStats);

        const result = await service.getZulipAccountStatistics();

        expect(result.success).toBe(true);
        expect(result.data).toEqual(mockStats);
      });
    });
  });

  // describe('Health Check', () => {
  //   describe('healthCheck', () => {
  //     it('should return healthy status', async () => {
  //       const result = await service.healthCheck();

  //       expect(result.success).toBe(true);
  //       expect(result.data.status).toBe('healthy');
  //       expect(result.data.timestamp).toBeDefined();
  //       expect(result.data.services).toBeDefined();
  //     });
  //   });
  // });

  describe('Error Handling', () => {
    it('should handle service injection errors', () => {
      expect(service).toBeDefined();
      expect(service['usersService']).toBeDefined();
      expect(service['userProfilesService']).toBeDefined();
      expect(service['zulipAccountsService']).toBeDefined();
    });

    it('should format BigInt IDs correctly', async () => {
      const mockUser = { id: BigInt(123456789012345), username: 'test' };
      mockUsersService.findOne.mockResolvedValue(mockUser);

      const result = await service.getUserById(BigInt('123456789012345'));

      expect(result.success).toBe(true);
      expect(result.data.id).toBe('123456789012345');
    });

    it('should handle concurrent operations', async () => {
      const mockUser = { id: BigInt(1), username: 'test' };
      mockUsersService.findOne.mockResolvedValue(mockUser);

      const promises = [
        service.getUserById(BigInt(1)),
        service.getUserById(BigInt(1)),
        service.getUserById(BigInt(1))
      ];

      const results = await Promise.all(promises);

      results.forEach(result => {
        expect(result.success).toBe(true);
        expect(result.data.id).toBe('1');
      });
    });
  });
});