import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import type { FastifyRequest } from 'fastify';
import type { AuthenticatedUser } from '../auth/authenticated-user';
import { MODULE_REQUIREMENT_KEY, type ModuleRequirement } from './requires-module.decorator';
import { satisfies } from './modules';

type AuthenticatedRequest = FastifyRequest & { user?: AuthenticatedUser };

/**
 * Enforces @RequiresModule(...). Runs after SessionAuthGuard, so `request.user`
 * carries the entitlements resolved with the session.
 *
 * Routes without the decorator are unrestricted beyond needing a valid session,
 * which keeps this additive: nothing that worked before starts failing.
 */
@Injectable()
export class ModuleAccessGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requirement = this.reflector.getAllAndOverride<ModuleRequirement>(
      MODULE_REQUIREMENT_KEY,
      [context.getHandler(), context.getClass()],
    );
    if (!requirement) return true;

    const user = context.switchToHttp().getRequest<AuthenticatedRequest>().user;
    if (!user || !satisfies(user.modules[requirement.module], requirement.level)) {
      // Deliberately vague: which modules exist and which this account lacks is
      // not something an unauthorised caller needs to learn.
      throw new ForbiddenException('This module is not enabled for your account.');
    }

    return true;
  }
}
