import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
import { DataSource } from 'typeorm';
import { MiniAuthService } from '../../src/services/index.mt';
import { UserEntityMt } from '@d8d/user-module-mt';

// Mock 依赖
vi.mock('@d8d/shared-utils', async (importOriginal) => {
  const actual = await importOriginal() as any;
  return {
    ...actual,
    JWTUtil: {
      generateToken: vi.fn().mockReturnValue('mock-jwt-token')
    },
    redisUtil: {
      setSessionKey: vi.fn().mockResolvedValue(undefined),
      getSessionKey: vi.fn().mockResolvedValue('mock-session-key')
    }
  };
});

vi.mock('@d8d/file-module', () => ({
  FileService: vi.fn().mockImplementation(() => ({
    downloadAndSaveFromUrl: vi.fn().mockResolvedValue({ file: { id: 1 } })
  }))
}));

describe('MiniAuthService', () => {
  let miniAuthService: MiniAuthService;
  let mockDataSource: DataSource;
  let mockUserRepository: any;

  beforeEach(() => {
    // Mock DataSource
    mockUserRepository = {
      findOne: vi.fn(),
      create: vi.fn(),
      save: vi.fn()
    };

    mockDataSource = {
      getRepository: vi.fn().mockReturnValue(mockUserRepository)
    } as any;

    miniAuthService = new MiniAuthService(mockDataSource);
  });

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

  describe('decryptPhoneNumber', () => {
    it('应该成功解密有效的手机号数据', async () => {
      // 由于实际的解密需要有效的AES加密数据，这里我们主要测试参数验证和错误处理
      // 对于成功的解密测试，我们跳过实际的解密过程
      const encryptedData = 'valid_encrypted_data';
      const iv = 'valid_iv';
      const sessionKey = 'valid_session_key';

      // 这里我们主要测试方法能够被调用
      // 在实际环境中，需要提供有效的加密数据才能测试成功解密
      await expect(miniAuthService.decryptPhoneNumber(encryptedData, iv, sessionKey))
        .rejects.toMatchObject({ code: 400 });
    });

    it('应该拒绝空的加密数据', async () => {
      const encryptedData = '';
      const iv = 'valid_iv';
      const sessionKey = 'valid_session_key';

      await expect(miniAuthService.decryptPhoneNumber(encryptedData, iv, sessionKey))
        .rejects.toMatchObject({ code: 400, message: '加密数据或初始向量不能为空' });
    });

    it('应该拒绝空的初始向量', async () => {
      const encryptedData = 'valid_encrypted_data';
      const iv = '';
      const sessionKey = 'valid_session_key';

      await expect(miniAuthService.decryptPhoneNumber(encryptedData, iv, sessionKey))
        .rejects.toMatchObject({ code: 400, message: '加密数据或初始向量不能为空' });
    });

    it('应该拒绝空的sessionKey', async () => {
      const encryptedData = 'valid_encrypted_data';
      const iv = 'valid_iv';
      const sessionKey = '';

      await expect(miniAuthService.decryptPhoneNumber(encryptedData, iv, sessionKey))
        .rejects.toMatchObject({ code: 400, message: '加密数据或初始向量不能为空' });
    });

    it('应该处理解密失败的情况', async () => {
      // 模拟无效的加密数据（非Base64编码）
      const encryptedData = 'invalid_encrypted_data';
      const iv = 'invalid_iv';
      const sessionKey = 'invalid_session_key';

      // 由于我们无法真正模拟 crypto 模块，这里主要测试错误处理
      await expect(miniAuthService.decryptPhoneNumber(encryptedData, iv, sessionKey))
        .rejects.toMatchObject({ code: 400 });
    });
  });

  describe('miniLogin', () => {
    it('应该成功处理小程序登录', async () => {
      // Mock 微信API响应
      const mockOpenidInfo = {
        openid: 'test_openid',
        session_key: 'test_session_key'
      };

      // Mock 用户数据
      const mockUser = {
        id: 1,
        username: 'wx_user',
        openid: 'test_openid'
      } as any;

      // Mock 方法
      vi.spyOn(miniAuthService as any, 'getOpenIdByCode').mockResolvedValue(mockOpenidInfo);
      mockUserRepository.findOne.mockResolvedValue(mockUser);

      const result = await miniAuthService.miniLogin('test_code');

      expect(result).toHaveProperty('token');
      expect(result).toHaveProperty('user');
      expect(result).toHaveProperty('isNewUser');
      expect(result.token).toBe('mock-jwt-token');
      expect(result.user).toEqual(mockUser);
      expect(result.isNewUser).toBe(false);
    });

    it('应该为新用户创建账户', async () => {
      // Mock 微信API响应
      const mockOpenidInfo = {
        openid: 'new_user_openid',
        session_key: 'test_session_key'
      };

      // Mock 新用户数据
      const mockNewUser = {
        id: 2,
        username: 'wx_new_user',
        openid: 'new_user_openid'
      } as any;

      // Mock 方法
      vi.spyOn(miniAuthService as any, 'getOpenIdByCode').mockResolvedValue(mockOpenidInfo);
      vi.spyOn(miniAuthService as any, 'createMiniUser').mockResolvedValue(mockNewUser);
      mockUserRepository.findOne.mockResolvedValue(null);

      const result = await miniAuthService.miniLogin('test_code');

      expect(result.isNewUser).toBe(true);
      expect(result.user).toEqual(mockNewUser);
    });
  });

  describe('updateUserProfile', () => {
    it('应该成功更新用户资料', async () => {
      const mockUser = {
        id: 1,
        nickname: 'old_nickname',
        avatarFileId: null
      } as any;

      mockUserRepository.findOne.mockResolvedValue(mockUser);
      mockUserRepository.save.mockResolvedValue({ ...mockUser, nickname: 'new_nickname' });

      const result = await miniAuthService.updateUserProfile(1, {
        nickname: 'new_nickname'
      });

      expect(result.nickname).toBe('new_nickname');
      expect(mockUserRepository.save).toHaveBeenCalled();
    });

    it('应该处理用户不存在的情况', async () => {
      mockUserRepository.findOne.mockResolvedValue(null);

      await expect(miniAuthService.updateUserProfile(999, { nickname: 'test' }))
        .rejects.toThrow('用户不存在');
    });
  });
});