import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { AdminViewTokenService } from '../../admin-view-token/admin-view-token.service';

/**
 * 관리자 신원 비차단 복원 가드.
 *
 * 회원 화면과 관리자 admin-view(iframe)가 공유하는 공개 조회 경로에서 관리자 신원을
 * 복원한다. 없거나 무효여도 요청을 차단하지 않는다 — 차단 여부는 서비스의 소유자
 * 검증(assertOddOwner + isAdminViewerAllowed)이 결정한다.
 *
 * 두 가지 경로:
 * 1) admin JWT(_aaT 쿠키) — admin 패널과 API가 쿠키를 공유하는 환경.
 * 2) admin-view 단명 토큰(x-admin-view-token 헤더 또는 ?t) — iframe 요청에 쿠키가
 *    실리지 않는 환경(로컬 admin ↔ stg 사이트 등). scope 'analyze'+query.oddId로
 *    서명·TTL을 검증하며, 발급 시 이미 관리자 인증 + corp 기업 스코프가 검증된 토큰이다.
 *
 * 회원 토큰({ id, type, memId })에는 role 클레임이 없으므로 _aaT에 회원 토큰을 넣어도
 * 관리자로 오인되지 않는다(서비스 판정이 role 기반).
 */
@Injectable()
export class AdminOptionalGuard implements CanActivate {
  constructor(
    private jwtService: JwtService,
    private adminViewTokenService: AdminViewTokenService,
  ) {}

  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest<Request>();

    const token = request.cookies?.['_aaT'];
    if (token) {
      try {
        const payload = this.jwtService.verify(token);
        if (payload?.role) request['admin'] = payload;
      } catch {
        //* 관리자 토큰 아님/만료 — 회원 인증 경로로 계속 진행
      }
    }

    const viewToken =
      (request.headers['x-admin-view-token'] as string | undefined) ??
      (request.query?.t as string | undefined);
    const oddId = Number(request.query?.oddId);
    if (viewToken && Number.isInteger(oddId) && oddId > 0) {
      const claims = this.adminViewTokenService.verify(
        viewToken,
        'analyze',
        oddId,
      );
      if (claims) {
        request['admin'] = {
          ...(request['admin'] ?? {}),
          ...(claims.version === 2
            ? { role: claims.role, admId: claims.admId }
            : {}),
          viewTokenOddId: oddId,
        };
      }
    }

    return true;
  }
}
