import {
  BadRequestException,
  Controller,
  ForbiddenException,
  Get,
  Query,
  Req,
  UseGuards,
} from '@nestjs/common';
import { AdminJwtAuthGuard } from '../auth/admin/jwt.guard';
import {
  CorpAnalysisView,
  CorpAnalysisViewGuard,
} from '../auth/admin/corp-analysis-view.guard';
import { AnalyzeRepository } from '../analyze/analyze.repository';
import { AdminViewTokenService } from './admin-view-token.service';
import { canViewCar } from '../auth/admin/car-view-admin.guard';

const VALID_SCOPES = ['analyze', 'b2c-analyze', 'client-analyze'];

/**
 * ★보안(C2): admin(AdminJwtAuthGuard 보호)이 특정 분석건(type+id)에 스코프된 단명 토큰을 발급받는 엔드포인트.
 *   admin 팝업이 이 토큰을 iframe URL ?t= 로 실어 site admin-view 를 띄우면, site→server admin-view 호출이
 *   토큰으로 인가된다. 관리자만(AdminJwtAuthGuard) 발급 가능하므로 순차 id 순회 IDOR가 막힌다.
 */
@Controller('admin-view-token')
@UseGuards(AdminJwtAuthGuard, CorpAnalysisViewGuard)
//* corp는 분석 상세팝업(레벨2) 허용 기업만 admin-view 토큰 발급 가능
@CorpAnalysisView(2)
export class AdminViewTokenController {
  constructor(
    private tokenService: AdminViewTokenService,
    private analyzeRepository: AnalyzeRepository,
  ) {}

  @Get()
  async issue(
    @Query('type') type: string,
    @Query('id') id: string,
    @Req() req: Request,
  ) {
    if (!VALID_SCOPES.includes(type)) {
      throw new BadRequestException('invalid type');
    }
    const numId = Number(id);
    if (!Number.isInteger(numId) || numId <= 0) {
      throw new BadRequestException('invalid id');
    }
    await this.assertCorpScope(type, numId, req['admin']);
    const admin = req['admin'];
    return {
      token: this.tokenService.issue(type, numId, admin, canViewCar(admin)),
    };
  }

  private async assertCorpScope(type: string, id: number, admin: any) {
    if (admin?.role !== 'corp') return;

    if (type !== 'analyze') {
      throw new ForbiddenException('접근 권한이 없습니다');
    }

    const inScope = await this.analyzeRepository.isOddInCorpScope(
      id,
      admin.agcId,
      admin.corpScope === 'ORG' ? admin.orgPath : undefined,
    );
    if (!inScope) {
      throw new ForbiddenException('접근 권한이 없습니다');
    }
  }
}
