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

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

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

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

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

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

  describe('Role CRUD Operations', () => {
    it('should create and retrieve a role', async () => {
      // Create role
      const roleData = {
        name: 'admin',
        description: 'Administrator role',
        permissions: ['user:create', 'user:delete', 'role:manage']
      };

      const createdRole = await roleService.create(roleData);

      expect(createdRole.id).toBeDefined();
      expect(createdRole.name).toBe(roleData.name);
      expect(createdRole.description).toBe(roleData.description);
      expect(createdRole.permissions).toEqual(roleData.permissions);

      // Retrieve role
      const retrievedRole = await roleService.getById(createdRole.id);
      expect(retrievedRole).toBeDefined();
      expect(retrievedRole?.name).toBe(roleData.name);
    });

    it('should update role information', async () => {
      // Create role first
      const roleData = {
        name: 'updaterole',
        description: 'Role to be updated',
        permissions: ['user:read']
      };

      const createdRole = await roleService.create(roleData);

      // Update role
      const updateData = {
        description: 'Updated role description',
        permissions: ['user:read', 'user:update']
      };

      const updatedRole = await roleService.update(createdRole.id, updateData);

      expect(updatedRole).toBeDefined();
      expect(updatedRole?.description).toBe(updateData.description);
      expect(updatedRole?.permissions).toEqual(updateData.permissions);
    });

    it('should delete role', async () => {
      // Create role first
      const roleData = {
        name: 'deleterole',
        description: 'Role to be deleted',
        permissions: ['user:read']
      };

      const createdRole = await roleService.create(roleData);

      // Delete role
      const deleteResult = await roleService.delete(createdRole.id);
      expect(deleteResult).toBe(true);

      // Verify role is deleted
      const retrievedRole = await roleService.getById(createdRole.id);
      expect(retrievedRole).toBeNull();
    });

    it('should get role by name', async () => {
      const roleData = {
        name: 'specificrole',
        description: 'Specific role for testing',
        permissions: ['user:read']
      };

      await roleService.create(roleData);

      const foundRole = await roleService.getRoleByName('specificrole');
      expect(foundRole).toBeDefined();
      expect(foundRole?.name).toBe('specificrole');
    });
  });

  describe('Role List Operations', () => {
    it('should get paginated list of roles', async () => {
      // Create multiple roles
      const rolesData = [
        { name: 'role1', description: 'Role 1', permissions: ['user:read'] },
        { name: 'role2', description: 'Role 2', permissions: ['user:read'] },
        { name: 'role3', description: 'Role 3', permissions: ['user:read'] }
      ];

      for (const roleData of rolesData) {
        await roleService.create(roleData);
      }

      const [roles, total] = await roleService.getList(1, 10);

      expect(total).toBe(3);
      expect(roles).toHaveLength(3);
      expect(roles.map(r => r.name)).toEqual(
        expect.arrayContaining(['role1', 'role2', 'role3'])
      );
    });

    it('should search roles by name', async () => {
      // Create roles with different names
      await roleService.create({ name: 'admin', description: 'Admin role', permissions: ['user:create'] });
      await roleService.create({ name: 'user', description: 'User role', permissions: ['user:read'] });
      await roleService.create({ name: 'moderator', description: 'Moderator role', permissions: ['user:update'] });

      const [adminRoles] = await roleService.getList(1, 10, 'admin', ['name']);
      expect(adminRoles).toHaveLength(1);
      expect(adminRoles[0].name).toBe('admin');

      const [userRoles] = await roleService.getList(1, 10, 'user', ['name']);
      expect(userRoles).toHaveLength(1);
      expect(userRoles[0].name).toBe('user');
    });
  });

  describe('Permission Checking', () => {
    it('should check if role has permission', async () => {
      const roleData = {
        name: 'permissionrole',
        description: 'Role with specific permissions',
        permissions: ['user:create', 'user:read', 'user:update']
      };

      const role = await roleService.create(roleData);

      // Check existing permissions
      expect(await roleService.checkPermission(role.id, 'user:create')).toBe(true);
      expect(await roleService.checkPermission(role.id, 'user:read')).toBe(true);
      expect(await roleService.checkPermission(role.id, 'user:update')).toBe(true);

      // Check non-existing permission
      expect(await roleService.checkPermission(role.id, 'user:delete')).toBe(false);
    });

    it('should return false for non-existent role', async () => {
      const hasPermission = await roleService.checkPermission(999, 'user:create');
      expect(hasPermission).toBe(false);
    });
  });

  describe('Role Validation', () => {
    it('should require unique role names', async () => {
      const roleData = {
        name: 'unique',
        description: 'Unique role',
        permissions: ['user:read']
      };

      // Create first role
      await roleService.create(roleData);

      // Try to create role with same name
      await expect(roleService.create(roleData)).rejects.toThrow();
    });

    it('should require at least one permission', async () => {
      const roleData = {
        name: 'nopermission',
        description: 'Role without permissions',
        permissions: []
      };

      // This should work as TypeORM handles empty arrays
      const role = await roleService.create(roleData);
      expect(role.permissions).toEqual([]);
    });
  });
});