/**
 * Zulip账号管理核心服务测试
 * 
 * 功能描述：
 * - 测试ZulipAccountService的核心功能
 * - 验证账号创建和管理流程
 * - 测试API Key生成和验证
 * - 测试账号关联功能
 * 
 * 职责分离：
 * - 单元测试层：测试各个方法的独立功能
 * - Mock层：模拟外部依赖和Zulip API
 * - 数据层：测试数据处理和验证逻辑
 * 
 * 最近修改：
 * - 2026-01-12: 代码规范优化 - 修正注释规范和修改记录格式 (修改者: moyin)
 * - 2026-01-07: 代码规范优化 - 创建缺失的测试文件 (修改者: moyin)
 * 
 * @author moyin
 * @version 1.0.2
 * @since 2026-01-07
 * @lastModified 2026-01-12
 */

import { Test, TestingModule } from '@nestjs/testing';
import { 
  ZulipAccountService, 
  CreateZulipAccountRequest
} from './zulip_account.service';
import { ZulipClientConfig } from '../zulip_core.interfaces';

describe('ZulipAccountService', () => {
  let service: ZulipAccountService;

  // Mock zulip-js模块
  const mockZulipClient = {
    users: {
      me: {
        getProfile: jest.fn(),
      },
      create: jest.fn(),
      retrieve: jest.fn(),
    },
    config: {
      apiKey: 'test-api-key',
      realm: 'https://zulip.example.com',
    },
  };

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

  beforeEach(async () => {
    jest.clearAllMocks();

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

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

    // Mock动态导入
    jest.spyOn(service as any, 'loadZulipModule').mockResolvedValue(mockZulipInit);
    
    // 重置 mock 函数的返回值
    mockZulipInit.mockResolvedValue(mockZulipClient);
  });

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

  describe('initializeAdminClient', () => {
    const adminConfig: ZulipClientConfig = {
      username: 'admin@example.com',
      apiKey: 'admin-api-key',
      realm: 'https://zulip.example.com',
    };

    it('应该成功初始化管理员客户端', async () => {
      // Arrange
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'success',
        email: 'admin@example.com',
        is_admin: true,
      });

      // Act
      const result = await service.initializeAdminClient(adminConfig);

      // Assert
      expect(result).toBe(true);
      expect(mockZulipInit).toHaveBeenCalledWith({
        username: adminConfig.username,
        apiKey: adminConfig.apiKey,
        realm: adminConfig.realm,
      });
    });

    it('应该在管理员验证失败时返回false', async () => {
      // Arrange
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'error',
        msg: 'Invalid API key',
      });

      // Act
      const result = await service.initializeAdminClient(adminConfig);

      // Assert
      expect(result).toBe(false);
    });

    it('应该处理网络异常', async () => {
      // Arrange
      mockZulipClient.users.me.getProfile.mockRejectedValue(new Error('Network error'));

      // Act
      const result = await service.initializeAdminClient(adminConfig);

      // Assert
      expect(result).toBe(false);
    });
  });

  describe('createZulipAccount', () => {
    const createRequest: CreateZulipAccountRequest = {
      email: 'user@example.com',
      fullName: 'Test User',
      password: 'password123',
    };

    beforeEach(async () => {
      // 初始化管理员客户端
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'success',
        email: 'admin@example.com',
        is_admin: true,
      });
      await service.initializeAdminClient({
        username: 'admin@example.com',
        apiKey: 'admin-api-key',
        realm: 'https://zulip.example.com',
      });
    });

    it('应该成功创建Zulip账号', async () => {
      // Arrange
      mockZulipClient.users.retrieve.mockResolvedValue({
        result: 'success',
        members: [], // 用户不存在
      });

      mockZulipClient.users.create.mockResolvedValue({
        result: 'success',
        user_id: 123,
      });

      // Mock API Key生成
      const mockUserClient = {
        users: {
          me: {
            getProfile: jest.fn().mockResolvedValue({
              result: 'success',
              user_id: 123,
            }),
          },
        },
        config: {
          apiKey: 'generated-api-key',
        },
      };
      mockZulipInit.mockResolvedValueOnce(mockUserClient);

      // Act
      const result = await service.createZulipAccount(createRequest);

      // Assert
      expect(result.success).toBe(true);
      expect(result.userId).toBe(123);
      expect(result.email).toBe(createRequest.email);
      expect(result.apiKey).toBe('generated-api-key');
    });

    it('应该在用户已存在时绑定已有账号', async () => {
      // Arrange
      mockZulipClient.users.retrieve.mockResolvedValue({
        result: 'success',
        members: [{ email: 'user@example.com', user_id: 123, full_name: 'Test User' }], // 用户已存在
      });

      // Act
      const result = await service.createZulipAccount(createRequest);

      // Assert
      expect(result.success).toBe(true);
      expect(result.isExistingUser).toBe(true);
      expect(result.userId).toBe(123);
      expect(result.email).toBe('user@example.com');
    });

    it('应该在邮箱为空时返回错误', async () => {
      // Arrange
      const invalidRequest = { ...createRequest, email: '' };

      // Act
      const result = await service.createZulipAccount(invalidRequest);

      // Assert
      expect(result.success).toBe(false);
      expect(result.error).toBe('邮箱地址不能为空');
    });

    it('应该在用户全名为空时返回错误', async () => {
      // Arrange
      const invalidRequest = { ...createRequest, fullName: '' };

      // Act
      const result = await service.createZulipAccount(invalidRequest);

      // Assert
      expect(result.success).toBe(false);
      expect(result.error).toBe('用户全名不能为空');
    });

    it('应该在邮箱格式无效时返回错误', async () => {
      // Arrange
      const invalidRequest = { ...createRequest, email: 'invalid-email' };

      // Act
      const result = await service.createZulipAccount(invalidRequest);

      // Assert
      expect(result.success).toBe(false);
      expect(result.error).toBe('邮箱格式无效');
    });

    it('应该在Zulip用户创建失败时返回错误', async () => {
      // Arrange
      mockZulipClient.users.retrieve.mockResolvedValue({
        result: 'success',
        members: [], // 用户不存在
      });

      mockZulipClient.users.create.mockResolvedValue({
        result: 'error',
        msg: 'User creation failed',
      });

      // Act
      const result = await service.createZulipAccount(createRequest);

      // Assert
      expect(result.success).toBe(false);
      expect(result.error).toBe('User creation failed');
      expect(result.errorCode).toBe('ZULIP_CREATE_FAILED');
    });

    it('应该在管理员客户端未初始化时返回错误', async () => {
      // Arrange - 创建新的服务实例，不初始化管理员客户端
      const newService = new ZulipAccountService();

      // Act
      const result = await newService.createZulipAccount(createRequest);

      // Assert
      expect(result.success).toBe(false);
      expect(result.error).toBe('管理员客户端未初始化');
    });
  });

  describe('generateApiKeyForUser', () => {
    beforeEach(async () => {
      // 先初始化管理员客户端，确保 getRealmFromAdminClient 能正常工作
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'success',
        email: 'admin@example.com',
        is_admin: true,
      });
      await service.initializeAdminClient({
        username: 'admin@example.com',
        apiKey: 'admin-api-key',
        realm: 'https://zulip.example.com',
      });
    });

    it('应该成功生成API Key', async () => {
      // Arrange
      const mockUserClient = {
        users: {
          me: {
            getProfile: jest.fn().mockResolvedValue({
              result: 'success',
              user_id: 123,
            }),
          },
        },
        config: {
          apiKey: 'generated-api-key',
        },
      };
      mockZulipInit.mockResolvedValueOnce(mockUserClient);

      // Act
      const result = await service.generateApiKeyForUser('user@example.com', 'password123');

      // Assert
      expect(result.success).toBe(true);
      expect(result.apiKey).toBe('generated-api-key');
    });

    it('应该在用户验证失败时返回错误', async () => {
      // Arrange
      const mockUserClient = {
        users: {
          me: {
            getProfile: jest.fn().mockResolvedValue({
              result: 'error',
              msg: 'Invalid credentials',
            }),
          },
        },
      };
      mockZulipInit.mockResolvedValueOnce(mockUserClient);

      // Act
      const result = await service.generateApiKeyForUser('user@example.com', 'wrong-password');

      // Assert
      expect(result.success).toBe(false);
      expect(result.error).toContain('API Key获取失败');
    });

    it('应该在API Key缺失时返回错误', async () => {
      // Arrange
      const mockUserClient = {
        users: {
          me: {
            getProfile: jest.fn().mockResolvedValue({
              result: 'success',
              user_id: 123,
            }),
          },
        },
        config: {}, // 没有apiKey
      };
      mockZulipInit.mockResolvedValueOnce(mockUserClient);

      // Act
      const result = await service.generateApiKeyForUser('user@example.com', 'password123');

      // Assert
      expect(result.success).toBe(false);
      expect(result.error).toBe('无法从客户端配置中获取API Key');
    });
  });

  describe('validateZulipAccount', () => {
    beforeEach(async () => {
      // 为 validateZulipAccount 测试初始化管理员客户端
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'success',
        email: 'admin@example.com',
        is_admin: true,
      });
      await service.initializeAdminClient({
        username: 'admin@example.com',
        apiKey: 'admin-api-key',
        realm: 'https://zulip.example.com',
      });
    });

    it('应该使用API Key成功验证账号', async () => {
      // Arrange
      const mockUserClient = {
        users: {
          me: {
            getProfile: jest.fn().mockResolvedValue({
              result: 'success',
              user_id: 123,
              email: 'user@example.com',
            }),
          },
        },
      };
      mockZulipInit.mockResolvedValueOnce(mockUserClient);

      // Act
      const result = await service.validateZulipAccount('user@example.com', 'api-key');

      // Assert
      expect(result.success).toBe(true);
      expect(result.isValid).toBe(true);
      expect(result.userInfo).toBeDefined();
    });

    it('应该在API Key无效时返回验证失败', async () => {
      // Arrange
      const mockUserClient = {
        users: {
          me: {
            getProfile: jest.fn().mockResolvedValue({
              result: 'error',
              msg: 'Invalid API key',
            }),
          },
        },
      };
      mockZulipInit.mockResolvedValueOnce(mockUserClient);

      // Act
      const result = await service.validateZulipAccount('user@example.com', 'invalid-api-key');

      // Assert
      expect(result.success).toBe(true);
      expect(result.isValid).toBe(false);
      expect(result.error).toBe('Invalid API key');
    });

    it('应该在没有API Key时检查用户存在性', async () => {
      // Arrange
      mockZulipClient.users.retrieve.mockResolvedValue({
        result: 'success',
        members: [{ email: 'user@example.com' }],
      });

      // Act
      const result = await service.validateZulipAccount('user@example.com');

      // Assert
      expect(result.success).toBe(true);
      expect(result.isValid).toBe(true);
    });

    it('应该处理验证异常', async () => {
      // Arrange
      mockZulipInit.mockRejectedValueOnce(new Error('Network error'));

      // Act
      const result = await service.validateZulipAccount('user@example.com', 'api-key');

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

  describe('linkGameAccount', () => {
    it('应该成功关联游戏账号', async () => {
      // Act
      const result = await service.linkGameAccount(
        'game-user-123',
        456,
        'user@example.com',
        'api-key'
      );

      // Assert
      expect(result).toBe(true);
      
      // 验证关联信息
      const linkInfo = service.getAccountLink('game-user-123');
      expect(linkInfo).toBeDefined();
      expect(linkInfo?.gameUserId).toBe('game-user-123');
      expect(linkInfo?.zulipUserId).toBe(456);
      expect(linkInfo?.zulipEmail).toBe('user@example.com');
      expect(linkInfo?.isActive).toBe(true);
    });

    it('应该在参数不完整时返回失败', async () => {
      // Act
      const result = await service.linkGameAccount('', 456, 'user@example.com', 'api-key');

      // Assert
      expect(result).toBe(false);
    });
  });

  describe('unlinkGameAccount', () => {
    it('应该成功解除账号关联', async () => {
      // Arrange - 先创建关联
      await service.linkGameAccount('game-user-123', 456, 'user@example.com', 'api-key');

      // Act
      const result = await service.unlinkGameAccount('game-user-123');

      // Assert
      expect(result).toBe(true);
      
      // 验证关联已解除
      const linkInfo = service.getAccountLink('game-user-123');
      expect(linkInfo).toBeNull();
    });

    it('应该在账号不存在时仍返回成功', async () => {
      // Act
      const result = await service.unlinkGameAccount('nonexistent-user');

      // Assert
      expect(result).toBe(true);
    });
  });

  describe('getAccountLink', () => {
    it('应该返回存在的账号关联信息', async () => {
      // Arrange
      await service.linkGameAccount('game-user-123', 456, 'user@example.com', 'api-key');

      // Act
      const linkInfo = service.getAccountLink('game-user-123');

      // Assert
      expect(linkInfo).toBeDefined();
      expect(linkInfo?.gameUserId).toBe('game-user-123');
      expect(linkInfo?.zulipUserId).toBe(456);
    });

    it('应该在账号不存在时返回null', () => {
      // Act
      const linkInfo = service.getAccountLink('nonexistent-user');

      // Assert
      expect(linkInfo).toBeNull();
    });
  });

  describe('getAllAccountLinks', () => {
    it('应该返回所有活跃的账号关联', async () => {
      // Arrange
      await service.linkGameAccount('user1', 123, 'user1@example.com', 'api-key1');
      await service.linkGameAccount('user2', 456, 'user2@example.com', 'api-key2');

      // Act
      const allLinks = service.getAllAccountLinks();

      // Assert
      expect(allLinks).toHaveLength(2);
      expect(allLinks.map(link => link.gameUserId)).toContain('user1');
      expect(allLinks.map(link => link.gameUserId)).toContain('user2');
    });

    it('应该在没有关联时返回空数组', () => {
      // Act
      const allLinks = service.getAllAccountLinks();

      // Assert
      expect(allLinks).toHaveLength(0);
    });
  });

  describe('边界情况测试', () => {
    it('应该处理特殊字符的邮箱', async () => {
      // Arrange
      const specialEmailRequest: CreateZulipAccountRequest = {
        email: 'user+test@example.com',
        fullName: 'Test User',
      };

      // 为这个测试初始化管理员客户端
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'success',
        email: 'admin@example.com',
        is_admin: true,
      });
      await service.initializeAdminClient({
        username: 'admin@example.com',
        apiKey: 'admin-api-key',
        realm: 'https://zulip.example.com',
      });

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

      mockZulipClient.users.create.mockResolvedValue({
        result: 'success',
        user_id: 123,
      });

      const mockUserClient = {
        users: { me: { getProfile: jest.fn().mockResolvedValue({ result: 'success' }) } },
        config: { apiKey: 'test-key' },
      };
      mockZulipInit.mockResolvedValueOnce(mockUserClient);

      // Act
      const result = await service.createZulipAccount(specialEmailRequest);

      // Assert
      expect(result.success).toBe(true);
    });

    it('应该处理很长的用户名', async () => {
      // Arrange
      const longNameRequest: CreateZulipAccountRequest = {
        email: 'user@example.com',
        fullName: 'A'.repeat(100), // 很长的名字
      };

      // 为这个测试重新初始化管理员客户端
      mockZulipClient.users.me.getProfile.mockResolvedValue({
        result: 'success',
        email: 'admin@example.com',
        is_admin: true,
      });
      await service.initializeAdminClient({
        username: 'admin@example.com',
        apiKey: 'admin-api-key',
        realm: 'https://zulip.example.com',
      });

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

      mockZulipClient.users.create.mockResolvedValue({
        result: 'success',
        user_id: 123,
      });

      const mockUserClient = {
        users: { me: { getProfile: jest.fn().mockResolvedValue({ result: 'success' }) } },
        config: { apiKey: 'test-key' },
      };
      mockZulipInit.mockResolvedValueOnce(mockUserClient);

      // Act
      const result = await service.createZulipAccount(longNameRequest);

      // Assert
      expect(result.success).toBe(true);
    });
  });
});