import { Injectable, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Reflector } from '@nestjs/core';

/**
 * JWT 인증 가드
 *
 * @description
 * JWT 토큰 검증 가드입니다.
 * @Public() 데코레이터가 있는 엔드포인트는 인증을 건너뜁니다.
 *
 * @example
 * // 사용법 1: 특정 엔드포인트에 적용
 * @UseGuards(JwtAuthGuard)
 * @Get('profile')
 * getProfile(@Req() req) {
 *   return req.user;
 * }
 *
 * @example
 * // 사용법 2: 전역 적용 (main.ts)
 * app.useGlobalGuards(new JwtAuthGuard(new Reflector()));
 *
 * @example
 * // 사용법 3: 인증 제외
 * @Public()
 * @Get('public')
 * getPublicData() {
 *   return 'Anyone can access';
 * }
 *
 * @export
 * @class JwtAuthGuard
 * @extends {AuthGuard('jwt')}
 */
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  constructor(private reflector: Reflector) {
    super();
  }

  /**
   * 인증 확인
   *
   * @param {ExecutionContext} context - 실행 컨텍스트
   * @returns {boolean | Promise<boolean>}
   */
  canActivate(context: ExecutionContext) {
    // @Public() 데코레이터 확인
    const isPublic = this.reflector.getAllAndOverride<boolean>('isPublic', [
      context.getHandler(),
      context.getClass(),
    ]);

    // Public 엔드포인트는 인증 건너뜀
    if (isPublic) {
      return true;
    }

    // JWT 검증 수행
    return super.canActivate(context);
  }

  /**
   * 요청 처리
   *
   * @param {any} err - 에러
   * @param {any} user - 사용자 정보
   * @param {any} info - 추가 정보
   * @returns {any}
   */
  handleRequest(err: any, user: any, info: any) {
    if (err || !user) {
      throw err || new UnauthorizedException('인증이 필요합니다. 로그인 후 이용해주세요.');
    }
    return user;
  }
}
