import {
  Body,
  Controller,
  HttpStatus,
  Post,
  Get,
  Req,
  UseGuards,
  Param,
  Query,
  HttpException,
  Logger,
} from '@nestjs/common';
import {
  ApiOperation,
  ApiResponse,
  ApiTags,
  ApiBearerAuth,
} from '@nestjs/swagger';
import { ErrorResponse } from '../../common/error/types/types';
import { Request } from 'express';
import { AccountsService } from './accounts.service';
import {
  CreateAccountRequest,
  CreateAccountResponse,
  GetLicenseSummaryRequest,
  GetLicenseSummaryResponse,
  GetMyAccountResponse,
  GetTypistGroupsResponse,
  GetTypistsResponse,
  CreatePartnerAccountRequest,
  CreatePartnerAccountResponse,
  GetPartnerLicensesRequest,
  GetPartnerLicensesResponse,
  GetOrderHistoriesRequest,
  GetOrderHistoriesResponse,
  IssueLicenseRequest,
  IssueLicenseResponse,
  GetDealersResponse,
  CreateTypistGroupResponse,
  CreateTypistGroupRequest,
  GetTypistGroupResponse,
  GetTypistGroupRequest,
  UpdateTypistGroupRequest,
  UpdateTypistGroupRequestParam,
  CancelIssueRequest,
  CancelIssueResponse,
  GetWorktypesResponse,
  CreateWorktypeResponse,
  CreateWorktypesRequest,
  GetPartnersRequest,
  GetPartnersResponse,
  UpdateWorktypeRequestParam,
  UpdateWorktypeResponse,
  UpdateWorktypesRequest,
  GetOptionItemsRequestParam,
  GetOptionItemsResponse,
  UpdateOptionItemsResponse,
  UpdateOptionItemsRequestParam,
  UpdateOptionItemsRequest,
  PostActiveWorktypeRequest,
  PostActiveWorktypeResponse,
  UpdateAccountInfoRequest,
  UpdateAccountInfoResponse,
  DeleteAccountRequest,
  DeleteAccountResponse,
  GetAuthorsResponse,
  GetAccountInfoMinimalAccessRequest,
  GetAccountInfoMinimalAccessResponse,
  DeleteWorktypeRequestParam,
  DeleteWorktypeResponse,
  GetCompanyNameRequest,
  GetCompanyNameResponse,
} from './types/types';
import { USER_ROLES, ADMIN_ROLES, TIERS } from '../../constants';
import { AuthGuard } from '../../common/guards/auth/authguards';
import { RoleGuard } from '../../common/guards/role/roleguards';
import { retrieveAuthorizationToken } from '../../common/http/helper';
import { AccessToken } from '../../common/token';
import jwt from 'jsonwebtoken';
import { makeContext, retrieveRequestId, retrieveIp } from '../../common/log';
import { AuthService } from '../auth/auth.service';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';

@ApiTags('accounts')
@Controller('accounts')
export class AccountsController {
  private readonly logger = new Logger(AccountsController.name);
  constructor(
    private readonly accountService: AccountsService, //private readonly cryptoService: CryptoService,
    private readonly authService: AuthService,
  ) {}

  @Post()
  @ApiResponse({
    status: HttpStatus.OK,
    type: CreateAccountResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '登録済みユーザーからの登録など',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'createAccount' })
  async createAccount(
    @Body() body: CreateAccountRequest,
    @Req() req: Request,
  ): Promise<CreateAccountResponse> {
    const {
      companyName,
      country,
      dealerAccountId,
      adminMail,
      adminPassword,
      adminName,
      acceptedEulaVersion,
      acceptedPrivacyNoticeVersion,
      acceptedDpaVersion,
    } = body;
    const role = USER_ROLES.NONE;

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }

    const context = makeContext('anonymous', requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    await this.accountService.createAccount(
      context,
      companyName,
      country,
      dealerAccountId,
      adminMail,
      adminPassword,
      adminName,
      role,
      acceptedEulaVersion,
      acceptedPrivacyNoticeVersion,
      acceptedDpaVersion,
    );

    return {};
  }

  @ApiResponse({
    status: HttpStatus.OK,
    type: GetLicenseSummaryResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'getLicenseSummary',
    description: '指定したアカウントのライセンス集計情報を取得します',
  })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  @Post('licenses/summary')
  async getLicenseSummary(
    @Req() req: Request,
    @Body() body: GetLicenseSummaryRequest,
  ): Promise<GetLicenseSummaryResponse> {
    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);
    const response = await this.accountService.getLicenseSummary(
      context,
      body.accountId,
    );
    return response;
  }

  @ApiResponse({
    status: HttpStatus.OK,
    type: GetMyAccountResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '該当アカウントがDBに存在しない場合',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'getMyAccount',
    description: 'ログインしているユーザーのアカウント情報を取得します',
  })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  @Get('me')
  async getMyAccount(@Req() req: Request): Promise<GetMyAccountResponse> {
    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);
    //アカウントID取得処理
    const accountInfo = await this.accountService.getAccountInfo(
      context,
      userId,
    );
    return accountInfo;
  }

  @ApiResponse({
    status: HttpStatus.OK,
    type: GetAuthorsResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'getAuthors',
    description:
      'ログインしているユーザーのアカウント配下のAuthor一覧を取得します',
  })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  @Get('authors')
  async getAuthors(@Req() req: Request): Promise<GetAuthorsResponse> {
    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    const authors = await this.accountService.getAuthors(context, userId);

    return { authors };
  }

  @ApiResponse({
    status: HttpStatus.OK,
    type: GetTypistsResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'getTypists',
    description:
      'ログインしているユーザーのアカウント配下のタイピスト一覧を取得します',
  })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(RoleGuard.requireds({ delegation: true }))
  @Get('typists')
  async getTypists(@Req() req: Request): Promise<GetTypistsResponse> {
    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    const typists = await this.accountService.getTypists(context, userId);

    return { typists };
  }

  @ApiResponse({
    status: HttpStatus.OK,
    type: GetTypistGroupsResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'getTypistGroups',
    description:
      'ログインしているユーザーのアカウント配下のタイピストグループ一覧を取得します',
  })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(RoleGuard.requireds({ delegation: true }))
  @Get('typist-groups')
  async getTypistGroups(@Req() req: Request): Promise<GetTypistGroupsResponse> {
    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    const typistGroups = await this.accountService.getTypistGroups(
      context,
      userId,
    );

    return { typistGroups };
  }

  @ApiResponse({
    status: HttpStatus.OK,
    type: GetTypistGroupResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'グループが存在しない場合',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'getTypistGroup',
    description:
      'ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを取得します',
  })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  @Get('typist-groups/:typistGroupId')
  async getTypistGroup(
    @Req() req: Request,
    @Param() param: GetTypistGroupRequest,
  ): Promise<GetTypistGroupResponse> {
    const { typistGroupId } = param;

    // アクセストークン取得

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    const typistGroup = await this.accountService.getTypistGroup(
      context,
      userId,
      typistGroupId,
    );

    return typistGroup;
  }

  @ApiResponse({
    status: HttpStatus.OK,
    type: CreateTypistGroupResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'グループ名が空の場合/ユーザーが存在しない場合',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'createTypistGroup',
    description:
      'ログインしているユーザーのアカウント配下にタイピストグループを追加します',
  })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  @Post('typist-groups')
  async createTypistGroup(
    @Req() req: Request,
    @Body() body: CreateTypistGroupRequest,
  ): Promise<CreateTypistGroupResponse> {
    const { typistGroupName, typistIds } = body;
    // アクセストークン取得

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);
    await this.accountService.createTypistGroup(
      context,
      userId,
      typistGroupName,
      typistIds,
    );
    return {};
  }

  @ApiResponse({
    status: HttpStatus.OK,
    type: CreateTypistGroupResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'グループ名が空の場合/ユーザーが存在しない場合',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'updateTypistGroup',
    description:
      'ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを更新します',
  })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  @Post('typist-groups/:typistGroupId')
  async updateTypistGroup(
    @Req() req: Request,
    @Body() body: UpdateTypistGroupRequest,
    @Param() param: UpdateTypistGroupRequestParam,
  ): Promise<CreateTypistGroupResponse> {
    const { typistGroupName, typistIds } = body;
    const { typistGroupId } = param;

    // アクセストークン取得

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    await this.accountService.updateTypistGroup(
      context,
      userId,
      typistGroupId,
      typistGroupName,
      typistIds,
    );

    return {};
  }

  @Post('partner')
  @ApiResponse({
    status: HttpStatus.OK,
    type: CreatePartnerAccountResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '登録済みユーザーからの登録など',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'createPartnerAccount' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({
      roles: [ADMIN_ROLES.ADMIN],
      tiers: [TIERS.TIER1, TIERS.TIER2, TIERS.TIER3],
    }),
  )
  async createPartnerAccount(
    @Req() req: Request,
    @Body() body: CreatePartnerAccountRequest,
  ): Promise<CreatePartnerAccountResponse> {
    const { companyName, country, email, adminName } = body;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId, tier } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    await this.accountService.createPartnerAccount(
      context,
      companyName,
      country,
      email,
      adminName,
      userId,
      tier,
    );

    return {};
  }

  @Post('partner-licenses')
  @ApiResponse({
    status: HttpStatus.OK,
    type: GetPartnerLicensesResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'getPartnerLicenses' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({
      roles: [ADMIN_ROLES.ADMIN],
      tiers: [TIERS.TIER1, TIERS.TIER2, TIERS.TIER3, TIERS.TIER4],
    }),
  )
  async getPartnerLicenses(
    @Req() req: Request,
    @Body() body: GetPartnerLicensesRequest,
  ): Promise<GetPartnerLicensesResponse> {
    const { limit, offset, accountId } = body;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    const getPartnerLicensesResponse =
      await this.accountService.getPartnerLicenses(
        context,
        limit,
        offset,
        accountId,
      );

    return getPartnerLicensesResponse;
  }

  @Post('order-histories')
  @ApiResponse({
    status: HttpStatus.OK,
    type: GetOrderHistoriesResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'getOrderHistories' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({
      roles: [ADMIN_ROLES.ADMIN],
      delegation: true,
    }),
  )
  async getOrderHistories(
    @Req() req: Request,
    @Body() body: GetOrderHistoriesRequest,
  ): Promise<GetOrderHistoriesResponse> {
    const { limit, offset, accountId } = body;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    const getOrderHistoriesResponse =
      await this.accountService.getOrderHistories(
        context,
        limit,
        offset,
        accountId,
      );

    return getOrderHistoriesResponse;
  }

  @Post('/licenses/issue')
  @ApiResponse({
    status: HttpStatus.OK,
    type: IssueLicenseResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description:
      '自身のライセンス数が不足している場合/すでに対象注文が発行済の場合',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'issueLicense' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({
      roles: [ADMIN_ROLES.ADMIN],
      tiers: [TIERS.TIER1, TIERS.TIER2, TIERS.TIER3, TIERS.TIER4],
    }),
  )
  async issueLicense(
    @Req() req: Request,
    @Body() body: IssueLicenseRequest,
  ): Promise<IssueLicenseResponse> {
    const { orderedAccountId, poNumber } = body;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId, tier } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);
    await this.accountService.issueLicense(
      context,
      orderedAccountId,
      userId,
      tier,
      poNumber,
    );
    return {};
  }

  @Get('/dealers')
  @ApiResponse({
    status: HttpStatus.OK,
    type: GetDealersResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'getDealers' })
  async getDealers(@Req() req: Request): Promise<GetDealersResponse> {
    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }

    const context = makeContext('anonymous', requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    return await this.accountService.getDealers(context);
  }

  @Post('/issue/cancel')
  @ApiResponse({
    status: HttpStatus.OK,
    type: CancelIssueResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description:
      '対象注文のステータスが発行済以外/発行日から15日以降/ライセンスをユーザに割り当てている',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'cancelIssue',
    description: 'ライセンス発行をキャンセルします',
  })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({
      roles: [ADMIN_ROLES.ADMIN],
      tiers: [TIERS.TIER1, TIERS.TIER2],
    }),
  )
  async cancelIssue(
    @Req() req: Request,
    @Body() body: CancelIssueRequest,
  ): Promise<CancelIssueResponse> {
    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    await this.accountService.cancelIssue(
      context,
      userId,
      body.poNumber,
      body.orderedAccountId,
    );
    return {};
  }

  @Get('/worktypes')
  @ApiResponse({
    status: HttpStatus.OK,
    type: GetWorktypesResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'getWorktypes' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  async getWorktypes(@Req() req: Request): Promise<GetWorktypesResponse> {
    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);
    const worktypes = await this.accountService.getWorktypes(context, userId);

    return worktypes;
  }

  @Post('/worktypes')
  @ApiResponse({
    status: HttpStatus.OK,
    type: CreateWorktypeResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'WorktypeIDが重複 / WorktypeIDが空 / WorktypeIDが20件登録済み',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'createWorktype' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  async createWorktype(
    @Req() req: Request,
    @Body() body: CreateWorktypesRequest,
  ): Promise<CreateWorktypeResponse> {
    const { worktypeId, description } = body;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);
    await this.accountService.createWorktype(
      context,
      userId,
      worktypeId,
      description,
    );

    return {};
  }

  @Post('/worktypes/:id')
  @ApiResponse({
    status: HttpStatus.OK,
    type: UpdateWorktypeResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'WorktypeIDが重複 / WorktypeIDが空',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'updateWorktype' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  async updateWorktype(
    @Req() req: Request,
    @Param() param: UpdateWorktypeRequestParam,
    @Body() body: UpdateWorktypesRequest,
  ): Promise<UpdateWorktypeResponse> {
    const { worktypeId, description } = body;
    const { id } = param;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    await this.accountService.updateWorktype(
      context,
      userId,
      id,
      worktypeId,
      description,
    );

    return {};
  }

  @Post('/worktypes/:id/delete')
  @ApiResponse({
    status: HttpStatus.OK,
    type: DeleteWorktypeResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '指定WorktypeIDが削除済み / 指定WorktypeIDがWorkflowで使用中',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'deleteWorktype' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  async deleteWorktype(
    @Req() req: Request,
    @Param() param: DeleteWorktypeRequestParam,
  ): Promise<DeleteWorktypeResponse> {
    const { id } = param;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    await this.accountService.deleteWorktype(context, userId, id);
    return {};
  }

  @Get('/worktypes/:id/option-items')
  @ApiResponse({
    status: HttpStatus.OK,
    type: GetOptionItemsResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'WorktypeIDが不在',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'getOptionItems' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  async getOptionItems(
    @Req() req: Request,
    @Param() param: GetOptionItemsRequestParam,
  ): Promise<GetOptionItemsResponse> {
    const { id } = param;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    const optionItems = await this.accountService.getOptionItems(
      context,
      userId,
      id,
    );

    return optionItems;
  }

  @Post('/worktypes/:id/option-items')
  @ApiResponse({
    status: HttpStatus.OK,
    type: UpdateOptionItemsResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'WorktypeIDが不在',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'updateOptionItems' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  async updateOptionItems(
    @Req() req: Request,
    @Param() param: UpdateOptionItemsRequestParam,
    @Body() body: UpdateOptionItemsRequest,
  ): Promise<UpdateOptionItemsResponse> {
    const { optionItems } = body;
    const { id } = param;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    await this.accountService.updateOptionItems(
      context,
      userId,
      id,
      optionItems,
    );

    return {};
  }

  @Post('/active-worktype')
  @ApiResponse({
    status: HttpStatus.OK,
    type: PostActiveWorktypeResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'WorktypeIDが存在しない',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'activeWorktype' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  async activeWorktype(
    @Req() req: Request,
    @Body() body: PostActiveWorktypeRequest,
  ): Promise<PostActiveWorktypeResponse> {
    const { id } = body;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    await this.accountService.updateActiveWorktype(context, userId, id);
    return {};
  }

  @Get('/partners')
  @ApiResponse({
    status: HttpStatus.OK,
    type: GetPartnersResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'パラメータ不正',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'getPartners' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({
      roles: [ADMIN_ROLES.ADMIN],
      tiers: [TIERS.TIER1, TIERS.TIER2, TIERS.TIER3, TIERS.TIER4],
    }),
  )
  async getPartners(
    @Req() req: Request,
    @Query() query: GetPartnersRequest,
  ): Promise<GetPartnersResponse> {
    const { limit, offset } = query;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);
    const response = await this.accountService.getPartners(
      context,
      userId,
      limit,
      offset,
    );

    return response;
  }

  @Post('/me')
  @ApiResponse({
    status: HttpStatus.OK,
    type: UpdateAccountInfoResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'パラメータ不正/アカウント・ユーザー不在/管理者ユーザ不在',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'updateAccountInfo' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({
      roles: [ADMIN_ROLES.ADMIN],
    }),
  )
  async updateAccountInfo(
    @Req() req: Request,
    @Body() body: UpdateAccountInfoRequest,
  ): Promise<UpdateAccountInfoResponse> {
    const {
      parentAccountId,
      delegationPermission,
      primaryAdminUserId,
      secondryAdminUserId,
    } = body;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId, tier } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    await this.accountService.updateAccountInfo(
      context,
      userId,
      tier,
      delegationPermission,
      primaryAdminUserId,
      parentAccountId,
      secondryAdminUserId,
    );

    return {};
  }

  @Post('/delete')
  @ApiResponse({
    status: HttpStatus.OK,
    type: UpdateAccountInfoResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: 'DBアクセスに失敗しログインできる状態で処理が終了した場合',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'deleteAccountAndData' })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({
      roles: [ADMIN_ROLES.ADMIN],
    }),
  )
  async deleteAccountAndData(
    @Req() req: Request,
    @Body() body: DeleteAccountRequest,
  ): Promise<DeleteAccountResponse> {
    const { accountId } = body;

    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    await this.accountService.deleteAccountAndData(context, userId, accountId);
    return {};
  }

  @Post('/minimal-access')
  @ApiResponse({
    status: HttpStatus.OK,
    type: GetAccountInfoMinimalAccessResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '対象のユーザーIDが存在しない場合',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({ operationId: 'getAccountInfoMinimalAccess' })
  async getAccountInfoMinimalAccess(
    @Body() body: GetAccountInfoMinimalAccessRequest,
    @Req() req: Request,
  ): Promise<GetAccountInfoMinimalAccessResponse> {
    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const context = makeContext('anonymous', requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);

    // IDトークンの検証
    const idToken = await this.authService.getVerifiedIdToken(
      context,
      body.idToken,
    );
    const isVerified = await this.authService.isVerifiedUser(context, idToken);
    if (!isVerified) {
      throw new HttpException(
        makeErrorResponse('E010201'),
        HttpStatus.BAD_REQUEST,
      );
    }

    const tier = await this.accountService.getAccountInfoMinimalAccess(
      context,
      idToken.sub,
    );
    return { tier };
  }

  @ApiResponse({
    status: HttpStatus.OK,
    type: GetCompanyNameResponse,
    description: '成功時のレスポンス',
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '認証エラー',
    type: ErrorResponse,
  })
  @ApiResponse({
    status: HttpStatus.INTERNAL_SERVER_ERROR,
    description: '想定外のサーバーエラー',
    type: ErrorResponse,
  })
  @ApiOperation({
    operationId: 'getCompanyName',
    description: '指定したアカウントの会社名を取得します',
  })
  @ApiBearerAuth()
  @UseGuards(AuthGuard)
  @UseGuards(
    RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], delegation: true }),
  )
  @Post('company-name')
  async getCompanyName(
    @Req() req: Request,
    @Body() body: GetCompanyNameRequest,
  ): Promise<GetCompanyNameResponse> {
    const accessToken = retrieveAuthorizationToken(req);
    if (!accessToken) {
      throw new HttpException(
        makeErrorResponse('E000107'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const ip = retrieveIp(req);
    if (!ip) {
      throw new HttpException(
        makeErrorResponse('E000401'),
        HttpStatus.UNAUTHORIZED,
      );
    }

    const requestId = retrieveRequestId(req);
    if (!requestId) {
      throw new HttpException(
        makeErrorResponse('E000501'),
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const decodedAccessToken = jwt.decode(accessToken, { json: true });
    if (!decodedAccessToken) {
      throw new HttpException(
        makeErrorResponse('E000101'),
        HttpStatus.UNAUTHORIZED,
      );
    }
    const { userId } = decodedAccessToken as AccessToken;

    const context = makeContext(userId, requestId);
    this.logger.log(`[${context.getTrackingId()}] ip : ${ip}`);
    const companyName = await this.accountService.getCompanyName(
      context,
      body.accountId,
    );
    return companyName;
  }
}
