import { isDevSwaggerRequest } from '@api/helpers/request.helper';
import { getAuthTokenCandidates } from '@api/helpers/cookie.helper';
import {
  CanActivate,
  ExecutionContext,
  Injectable,
  Logger,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { AuthGuardService } from './auth-guard.service';

/**
 * Optional JWT Guard
 * JWT 토큰이 있으면 검증하고, 없으면 통과시킴 (B2C 지원용)
 */
@Injectable()
export class JwtOptionalGuard implements CanActivate {
  private logger = new Logger(JwtOptionalGuard.name);
  private readonly DEV_USER = {
    id: 'rsteam',
    type: '일반',
    memId: 180,
  };

  constructor(
    private jwtService: JwtService,
    private reflector: Reflector,
    private authGuardService: AuthGuardService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<Request>();
    //* _aT 후보(옛 만료 + 새 유효 중복 가능) + 헤더 토큰 중 verify 성공하는 것을 쓴다.
    const candidates = getAuthTokenCandidates(request);

    // 화이트리스트 IP
    const isWhitelistedIP =
      request.headers['x-forwarded-for'] == '58.72.93.50' ||
      request.headers['x-forwarded-for'] == '121.153.166.236';

    if (this.reflector.get<boolean>('isPublic', context.getHandler())) {
      return true;
    }

    // 토큰이 없으면 그냥 통과 (B2C의 경우)
    if (candidates.length === 0) {
      request['user'] = null;
      return true;
    }

    let payload;

    for (const token of candidates) {
      try {
        payload = this.jwtService.verify(token);
        break; //* 유효한 토큰을 찾으면 사용
      } catch (e) {
        // 다음 후보 시도
      }
    }

    if (!payload) {
      if (isWhitelistedIP) {
        payload = this.DEV_USER;
      } else if (isDevSwaggerRequest(request)) {
        payload = this.DEV_USER;
      } else {
        // JWT 검증 실패해도 통과 (B2C 지원)
        this.logger.warn('JWT verification failed, but allowing access for B2C');
        request['user'] = null;
        return true;
      }
    }

    // 유저 차단 혹은 중단 여부 체크 로직
    if (payload && payload.type === '기업') {
      await this.validateAgencyMember(payload.memId);
    }

    request['user'] = payload;

    return true;
  }

  private async validateAgencyMember(memId: number) {
    const member = await this.authGuardService.getAgencyMember(memId);

    if (member.memAgency?.agcDeliquent === 1) {
      // 기업 회원이 연체 상태일 때만 차단
      this.logger.warn(`Agency member ${memId} is delinquent`);
      return false;
    }

    if (member.memIsResigned === 1) {
      this.logger.warn(`Agency member ${memId} has resigned`);
      return false;
    }
  }
}
