import { ForbiddenException, Injectable } from '@nestjs/common';
import { PrismaService } from '../infra/prisma.service';

export interface UserAccessContext {
  roles: string[];
  permissions: string[];
  canAccessAdmin: boolean;
  canManageRoles: boolean;
  canManageOAuth: boolean;
  canManageUsers: boolean;
  canViewUsers: boolean;
  canManageSettings: boolean;
  canViewUserDocuments: boolean;
}

@Injectable()
export class AccessService {
  constructor(private readonly prisma: PrismaService) {}

  async getUserAccess(userId: string, isSuperAdmin: boolean): Promise<UserAccessContext> {
    if (isSuperAdmin) {
      return {
        roles: ['super-admin'],
        permissions: ['admin.access', 'oauth.manage', 'users.manage', 'users.read', 'settings.manage', 'rbac.manage', 'documents.view_others'],
        canAccessAdmin: true,
        canManageRoles: true,
        canManageOAuth: true,
        canManageUsers: true,
        canViewUsers: true,
        canManageSettings: true,
        canViewUserDocuments: true
      };
    }

    const links = await this.prisma.userRole.findMany({
      where: { userId },
      include: {
        role: {
          include: {
            permissions: {
              include: { permission: true }
            }
          }
        }
      }
    });

    const roles = links.map((link) => link.role.slug);
    const permissions = [...new Set(links.flatMap((link) => link.role.permissions.map((item) => item.permission.slug)))];

    return {
      roles,
      permissions,
      canAccessAdmin: permissions.includes('admin.access'),
      canManageRoles: false,
      canManageOAuth: permissions.includes('oauth.manage'),
      canManageUsers: permissions.includes('users.manage'),
      canViewUsers: permissions.includes('users.manage') || permissions.includes('users.read'),
      canManageSettings: permissions.includes('settings.manage'),
      canViewUserDocuments: permissions.includes('documents.view_others')
    };
  }

  async assertSuperAdmin(actorUserId: string) {
    const actor = await this.prisma.user.findUnique({ where: { id: actorUserId } });
    if (!actor?.isSuperAdmin) {
      throw new ForbiddenException('Только супер-администратор может выполнять это действие');
    }
  }

  async assertPermission(userId: string, isSuperAdmin: boolean, permission: string) {
    const access = await this.getUserAccess(userId, isSuperAdmin);
    if (!access.permissions.includes(permission) && !isSuperAdmin) {
      throw new Error('FORBIDDEN_PERMISSION');
    }
    return access;
  }

  async assertCanViewUserDocuments(requesterId: string, targetUserId: string) {
    if (requesterId === targetUserId) return;
    const requester = await this.prisma.user.findUnique({ where: { id: requesterId } });
    if (!requester) {
      throw new ForbiddenException('Пользователь не найден');
    }
    const access = await this.getUserAccess(requesterId, requester.isSuperAdmin);
    if (!access.canViewUserDocuments) {
      throw new ForbiddenException('Нет доступа к документам пользователя');
    }
  }
}
