import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';

/**
 * AdminGuard
 * ----------
 * This guard protects admin-only routes by:
 * 1. Extracting a JWT from the Authorization header
 * 2. Verifying the token using the configured JWT secret
 * 3. Ensuring the authenticated user has an admin role
 * 4. Attaching the decoded JWT payload to the request object
 */
@Injectable()
export class AdminGuard implements CanActivate {
  constructor(
    private jwtService: JwtService,
    private configService: ConfigService,
  ) {}

  /**
   * canActivate
   * -----------
   * Core guard method executed before the request reaches the controller.
   *
   * @param context NestJS execution context
   * @returns boolean indicating whether the request is authorized
   * @throws UnauthorizedException when authentication or authorization fails
   */
  async canActivate(context: ExecutionContext): Promise<boolean> {
    // Extract the incoming HTTP request
    const request = context.switchToHttp().getRequest();

    // Extract JWT token from Authorization header
    const token = this.extractTokenFromHeader(request);

    // Reject request if token is missing
    if (!token) {
      throw new UnauthorizedException();
    }

    try {
      /**
       * Verify JWT token
       * - Ensures token is valid
       * - Ensures token is not expired
       * - Decodes payload if verification succeeds
       */
      const payload = await this.jwtService.verifyAsync(token, {
        secret: this.configService.get('JWT_SECRET'),
      });

      /**
       * Authorization check
       * Assumption:
       *   role === 1  => Admin
       * Any other role is denied access
       */
      if (payload.role !== 1) {
        throw new UnauthorizedException();
      }

      /**
       * Attach decoded payload to request object
       * This allows controllers and services to access:
       *   request.user.id
       *   request.user.role
       *   request.user.email
       * etc.
       */
      request.user = payload;
    } catch {
      /**
       * Any error during:
       * - Token verification
       * - Token expiration
       * - Role validation
       * results in unauthorized access
       */
      throw new UnauthorizedException();
    }

    // Allow request to proceed
    return true;
  }

  /**
   * extractTokenFromHeader
   * ----------------------
   * Extracts JWT token from Authorization header.
   *
   * Expected format:
   *   Authorization: Bearer <jwt_token>
   *
   * @param request Express request object
   * @returns JWT token string or undefined
   */
  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}
