import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { UserRole } from '@prisma/client';
import { RequestUser } from '../common/request-user';
import { IS_PUBLIC_ROUTE } from '../auth/public.decorator';
import { ProfileService } from '../profile/profile.service';
import { FeatureAccessService } from './feature-access.service';
import { REQUIRE_FEATURE_KEY } from './require-feature.decorator';

@Injectable()
export class FeatureAccessGuard implements CanActivate {
  constructor(
    private readonly reflector: Reflector,
    private readonly features: FeatureAccessService,
    private readonly profile: ProfileService
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_ROUTE, [
      context.getHandler(),
      context.getClass()
    ]);
    if (isPublic) {
      return true;
    }

    const requiredFeature = this.reflector.getAllAndOverride<string>(REQUIRE_FEATURE_KEY, [
      context.getHandler(),
      context.getClass()
    ]);
    if (!requiredFeature) {
      return true;
    }

    const request = context.switchToHttp().getRequest<{ user?: RequestUser }>();
    const user = request.user;
    if (!user || user.role === UserRole.SUPER_ADMIN) {
      return true;
    }

    await this.profile.assertUsableProfile(user, requiredFeature);

    if (!(await this.features.isFeatureEnabled(user, requiredFeature))) {
      throw new ForbiddenException(`Feature ${requiredFeature} is not enabled for ${user.role}`);
    }

    return true;
  }
}
