import {
  Body,
  Controller,
  HttpException,
  HttpStatus,
  Post,
  Req,
} from '@nestjs/common';
import {
  ApiResponse,
  ApiOperation,
  ApiBearerAuth,
  ApiTags,
} from '@nestjs/swagger';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { ErrorResponse } from '../../common/error/types/types';
import { AuthService } from './auth.service';
import {
  AccessTokenResponse,
  TokenRequest,
  TokenResponse,
} from './types/types';
import { retrieveAuthorizationToken } from '../../common/http/helper';
import { makeContext } from '../../common/log';
import { v4 as uuidv4 } from 'uuid';

@ApiTags('auth')
@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('token')
  @ApiResponse({
    status: HttpStatus.OK,
    type: TokenResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    description:
      'AzureADB2Cでのサインイン後に払いだされるIDトークンを元に認証用のアクセストークンとリフレッシュトークンを生成します',
    operationId: 'token',
  })
  async token(@Body() body: TokenRequest): Promise<TokenResponse> {
    console.log(body);
    const idToken = await this.authService.getVerifiedIdToken(body.idToken);

    const isVerified = await this.authService.isVerifiedUser(idToken);
    if (!isVerified) {
      throw new HttpException(
        makeErrorResponse('E010201'),
        HttpStatus.BAD_REQUEST,
      );
    }

    const context = makeContext(uuidv4());

    const refreshToken = await this.authService.generateRefreshToken(
      context,
      idToken,
      body.type,
    );

    const accessToken = await this.authService.generateAccessToken(
      context,
      refreshToken,
    );

    return {
      accessToken,
      refreshToken,
    };
  }

  @Post('accessToken')
  @ApiBearerAuth()
  @ApiResponse({
    status: HttpStatus.OK,
    type: AccessTokenResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'accessToken',
    description: 'リフレッシュトークンを元にアクセストークンを再生成します',
  })
  async accessToken(@Req() req): Promise<AccessTokenResponse> {
    const refreshToken = retrieveAuthorizationToken(req);

    if (!refreshToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const context = makeContext(uuidv4());

    const accessToken = await this.authService.generateAccessToken(
      context,
      refreshToken,
    );
    return { accessToken };
  }
}
