import { CanActivate, ExecutionContext, ForbiddenException, Injectable, UnauthorizedException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthContextService, type AuthenticatedRequest } from './auth-context.service';
import { PERMISSION_METADATA_KEY, type RequiredPermissionMetadata } from './permission.decorator';
import { PermissionService } from './permission.service';

@Injectable()
export class PermissionGuard implements CanActivate {
  constructor(
    private readonly reflector: Reflector,
    private readonly authContext: AuthContextService,
    private readonly permissions: PermissionService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const metadata = this.reflector.getAllAndOverride<RequiredPermissionMetadata>(PERMISSION_METADATA_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (!metadata) return true;

    const request = context.switchToHttp().getRequest<AuthenticatedRequest & { params?: Record<string, string> }>();
    const user = await this.authContext.resolveCurrentUser(request);
    if (!user) throw new UnauthorizedException('Authentication required');

    const allowed = await this.permissions.can(user, metadata.permission, {
      productId: metadata.productIdParam ? request.params?.[metadata.productIdParam] : undefined,
      projectId: metadata.projectIdParam ? request.params?.[metadata.projectIdParam] : undefined,
      versionId: metadata.versionIdParam ? request.params?.[metadata.versionIdParam] : undefined,
    });
    if (!allowed) throw new ForbiddenException(`Missing permission: ${metadata.permission}`);
    return true;
  }
}
