import {
  Body,
  Controller,
  HttpException,
  HttpStatus,
  Logger,
  Post,
  Req,
  UseGuards,
} from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { ConfigService } from '@nestjs/config';
import { CooconAuthService } from '@lib/coocon/src/coocon-auth.service';
import { ClientBasicAuthGuard } from '../auth/client/auth.guard';
import { TreatReservationService } from './dispatch/treat-reservation.service';

/**
 * 진료수집(쿠콘) 바이패스 — 외부 서비스(보상닥터)용.
 *  - 인증: ClientBasicAuthGuard (tn_client CODE:PASS). req.user.username = cliCode.
 *  - 동작: 외부가 보낸 쿠콘 봉투를 우리 인증키만 주입(미노출)해 쿠콘 게이트웨이로 그대로 전달.
 *  - 슬롯: 본인인증(세션 시작) 시 client별 동시 슬롯 예약(TTL 자동만료). 초과 시 429.
 *    (MVP: TTL 자동만료로 동시건수 상한 보장. 즉시해제는 2단계)
 */
@ApiTags('진료수집 바이패스')
@UseGuards(ClientBasicAuthGuard)
@Controller('clients/coocon')
export class CooconBypassController {
  private logger = new Logger(CooconBypassController.name);

  constructor(
    private cooconAuth: CooconAuthService,
    private reservation: TreatReservationService,
    private config: ConfigService,
  ) {}

  @ApiOperation({
    summary: '쿠콘 진료수집 바이패스',
    description:
      '쿠콘 봉투(Common/InputList/Dsnc/SAS_SessionID)를 그대로 전달한다. Auth_key는 서버가 주입(외부 미노출). 본인인증 시 동시 슬롯 예약.',
  })
  @Post('scrap')
  async scrap(@Body() envelope: any, @Req() req: any) {
    const code = req?.user?.username ?? 'unknown';
    const job = envelope?.InputList?.[0]?.Job;

    //* 세션 시작(본인인증) 시 client별 슬롯 예약. TTL(10분)로 동시건수 상한 보장.
    if (job === '본인인증') {
      const slot = Number(this.config.get('b2cBypass.slot') ?? 2);
      const slotId = await this.reservation.reserve(
        `coocon-bypass:${code}`,
        slot,
        600000,
      );
      if (!slotId) {
        throw new HttpException(
          {
            code: 'B2C_BUSY',
            message: '동시 처리 한도 초과. 잠시 후 다시 시도해 주세요.',
          },
          HttpStatus.TOO_MANY_REQUESTS,
        );
      }
      this.logger.log(`[coocon-bypass] reserve code=${code} resvId=${slotId}`);
    }

    return this.cooconAuth.passthrough(envelope);
  }
}
