import { describe, it, expect, beforeEach, afterEach, beforeAll } from 'vitest';
import { DataSource } from 'typeorm';
import { UserService } from '../../src/services/user.service';
import { RoleService } from '../../src/services/role.service';
import { UserEntity } from '../../src/entities/user.entity';
import { Role } from '../../src/entities/role.entity';
import { AppDataSource, initializeDataSource } from '@d8d/shared-utils';

// 确保测试环境变量被设置
process.env.NODE_ENV = 'test';

describe('User Integration Tests', () => {
  let dataSource: DataSource;
  let userService: UserService;
  let roleService: RoleService;

  beforeAll(() => {
    // 使用预先配置的数据源
    initializeDataSource([UserEntity, Role])
    dataSource = AppDataSource;
  })

  beforeEach(async () => {
    if (!dataSource.isInitialized) {
      await dataSource.initialize();
    }
    userService = new UserService(dataSource);
    roleService = new RoleService(dataSource);
  });

  afterEach(async () => {
    if (dataSource.isInitialized) {
      await dataSource.destroy();
    }
  });



  describe('User CRUD Operations', () => {
    it('should create and retrieve a user', async () => {
      // Create user
      const userData = {
        username: 'integrationuser',
        password: 'password123',
        email: 'integration@example.com',
        nickname: 'Integration User'
      };
      const originalUserData = {
        ...userData
      }

      const createdUser = await userService.createUser(userData);
      
      expect(createdUser.id).toBeDefined();
      expect(createdUser.username).toBe(userData.username);
      expect(createdUser.email).toBe(userData.email);
      expect(createdUser.nickname).toBe(userData.nickname);
      expect(createdUser.password).not.toBe(originalUserData.password); // Password should be hashed

      // Retrieve user
      const retrievedUser = await userService.getUserById(createdUser.id);
      expect(retrievedUser).toBeDefined();
      expect(retrievedUser?.username).toBe(userData.username);
    });

    it('should update user information', async () => {
      // Create user first
      const userData = {
        username: 'updateuser',
        password: 'password123',
        email: 'update@example.com'
      };

      const createdUser = await userService.createUser(userData);

      // Update user
      const updateData = {
        email: 'updated@example.com',
        nickname: 'Updated User'
      };

      const updatedUser = await userService.updateUser(createdUser.id, updateData);

      expect(updatedUser).toBeDefined();
      expect(updatedUser?.email).toBe(updateData.email);
      expect(updatedUser?.nickname).toBe(updateData.nickname);
    });

    it('should delete user', async () => {
      // Create user first
      const userData = {
        username: 'deleteuser',
        password: 'password123'
      };

      const createdUser = await userService.createUser(userData);

      // Delete user
      const deleteResult = await userService.deleteUser(createdUser.id);
      expect(deleteResult).toBe(true);

      // Verify user is deleted
      const retrievedUser = await userService.getUserById(createdUser.id);
      expect(retrievedUser).toBeNull();
    });

    it('should get user by username', async () => {
      const userData = {
        username: 'usernameuser',
        password: 'password123'
      };

      await userService.createUser(userData);

      const foundUser = await userService.getUserByUsername('usernameuser');
      expect(foundUser).toBeDefined();
      expect(foundUser?.username).toBe('usernameuser');
    });

    it('should get user by account (username or email)', async () => {
      const userData = {
        username: 'accountuser',
        password: 'password123',
        email: 'account@example.com'
      };

      await userService.createUser(userData);

      // Find by username
      const byUsername = await userService.getUserByAccount('accountuser');
      expect(byUsername).toBeDefined();
      expect(byUsername?.username).toBe('accountuser');

      // Find by email
      const byEmail = await userService.getUserByAccount('account@example.com');
      expect(byEmail).toBeDefined();
      expect(byEmail?.email).toBe('account@example.com');
    });
  });

  describe('User-Role Relationship', () => {
    it('should assign roles to user', async () => {
      // Create user
      const userData = {
        username: 'roleuser',
        password: 'password123'
      };
      const user = await userService.createUser(userData);

      // Create roles
      const adminRole = await roleService.create({
        name: 'admin',
        description: 'Administrator role',
        permissions: ['user:create', 'user:delete']
      });

      const userRole = await roleService.create({
        name: 'user',
        description: 'Regular user role',
        permissions: ['user:read']
      });

      // Assign roles to user
      const updatedUser = await userService.assignRoles(user.id, [adminRole.id, userRole.id]);

      expect(updatedUser).toBeDefined();
      expect(updatedUser?.roles).toHaveLength(2);
      expect(updatedUser?.roles.map(r => r.name)).toContain('admin');
      expect(updatedUser?.roles.map(r => r.name)).toContain('user');
    });
  });

  describe('User List Operations', () => {
    it('should get all users', async () => {
      // Create multiple users
      const usersData = [
        { username: 'user1', password: 'password123' },
        { username: 'user2', password: 'password123' },
        { username: 'user3', password: 'password123' }
      ];

      for (const userData of usersData) {
        await userService.createUser(userData);
      }

      const allUsers = await userService.getUsers();

      expect(allUsers).toHaveLength(3);
      expect(allUsers.map(u => u.username)).toEqual(
        expect.arrayContaining(['user1', 'user2', 'user3'])
      );
    });
  });

  describe('Password Verification', () => {
    it('should verify correct password', async () => {
      const userData = {
        username: 'verifyuser',
        password: 'correctpassword'
      };

      const user = await userService.createUser(userData);

      const isCorrect = await userService.verifyPassword(user, 'correctpassword');
      expect(isCorrect).toBe(true);
    });

    it('should reject incorrect password', async () => {
      const userData = {
        username: 'verifyuser2',
        password: 'correctpassword'
      };

      const user = await userService.createUser(userData);

      const isCorrect = await userService.verifyPassword(user, 'wrongpassword');
      expect(isCorrect).toBe(false);
    });
  });
});