import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Role } from '../entities/role.entity';
import { Permission } from '../entities/permission.entity';
import { User } from '../entities/user.entity';

@Injectable()
export class RbacService {
  constructor(
    @InjectRepository(Role)
    private readonly roleRepository: Repository<Role>,
    @InjectRepository(Permission)
    private readonly permissionRepository: Repository<Permission>,
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

  async getUserPermissions(userId: string): Promise<string[]> {
    const user = await this.userRepository.findOne({
      where: { id: userId },
      relations: ['role', 'role.permissions'],
    });

    if (!user) {
      throw new Error('User not found');
    }

    const permissions = new Set<string>();
    if (user.role && user.role.permissions) {
      user.role.permissions.forEach(permission => {
        permissions.add(permission.name);
      });
    }

    return Array.from(permissions);
  }

  async checkPermission(userId: string, requiredPermission: string): Promise<boolean> {
    const permissions = await this.getUserPermissions(userId);
    return permissions.includes(requiredPermission);
  }

  async hasRole(userId: string, roleName: string): Promise<boolean> {
    const user = await this.userRepository.findOne({
      where: { id: userId },
      relations: ['role'],
    });

    if (!user) {
      throw new Error('User not found');
    }

    return user.role?.name === roleName;
  }

  async assignRole(userId: string, roleName: string): Promise<void> {
    const user = await this.userRepository.findOne({
      where: { id: userId },
    });

    const role = await this.roleRepository.findOne({
      where: { name: roleName },
    });

    if (!user || !role) {
      throw new Error('User or role not found');
    }

    user.roleId = role.id;
    await this.userRepository.save(user);
  }

  async removeRole(userId: string, roleName: string): Promise<void> {
    const user = await this.userRepository.findOne({
      where: { id: userId },
    });

    const role = await this.roleRepository.findOne({
      where: { name: roleName },
    });

    if (!user || !role) {
      throw new Error('User or role not found');
    }

    user.roleId = null;
    await this.userRepository.save(user);
  }
}
