import {
  Body,
  Controller,
  Header,
  Post,
  Req,
  UseGuards,
} from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { Request } from 'express';
import { auditContext } from '../../audit/audit-actor';
import { AdminRequest } from './admin-identity';
import { AllowOrgWrite } from './allow-org-write.decorator';
import {
  ChangeOwnPasswordDto,
  MfaEnrollDto,
  RevokeOtherSessionsDto,
  VerifySigninCodeDto,
} from './auth.dto';
import { CorpReadonlyGuard } from './corp-readonly.guard';
import { AdminJwtAuthGuard } from './jwt.guard';
import { MfaService } from './mfa.service';
import { OriginCheckGuard } from './origin-check.guard';
import { Roles } from './roles.decorator';
import { RolesGuard } from './roles.guard';

/**
 * 본인 2차 인증(계획 3.16 · AZ-9) — 최고관리자 초기화와 다른 컨트롤러다. 상태 조회는 `/admin/me` 의 `mfa` 칸이 맡는다.
 * 권한 코드가 없는 본인 동작이라 맵 행 대신 예외 원장에 있다. 조직 관리자도 자기 것을 켠다(@AllowOrgWrite).
 */
@ApiTags('[관리자] 2차 인증')
@UseGuards(AdminJwtAuthGuard, RolesGuard, CorpReadonlyGuard, OriginCheckGuard)
@Roles('admin', 'sales', 'corp')
@Controller('admin/2fa')
export class MfaSelfController {
  constructor(private readonly mfa: MfaService) {}

  @ApiOperation({ summary: '본인 2차 인증 켜기 — 현재 비밀번호 확인 뒤 후보 시드' })
  @Post('enroll')
  @AllowOrgWrite()
  //* 응답에 시드(설정 키 · otpauth URI)가 있다
  @Header('Cache-Control', 'no-store')
  enroll(@Body() dto: MfaEnrollDto, @Req() req: AdminRequest) {
    return this.mfa.enroll(req.admin!, dto.password);
  }

  @ApiOperation({ summary: '본인 2차 인증 켜기 확인 — 후보 시드의 코드' })
  @Post('confirm')
  @AllowOrgWrite()
  confirm(@Body() dto: VerifySigninCodeDto, @Req() req: AdminRequest & Request) {
    return this.mfa.confirm(req.admin!, dto.code, auditContext(req));
  }

  @ApiOperation({ summary: '본인 2차 인증 끄기 — 사용 중 시드의 코드' })
  @Post('disable')
  @AllowOrgWrite()
  disable(@Body() dto: VerifySigninCodeDto, @Req() req: AdminRequest & Request) {
    return this.mfa.disable(req.admin!, dto.code, auditContext(req));
  }
}

/**
 * 마이페이지 본인 비밀번호 변경(75 5절) — 내부 관리자 · 영업만. 최고관리자 신청(노트 84)도 이 묶음에 있다(내부 관리자만). 기업 · 조직은 기업 마이페이지(`/corp/my-info`)가 맡는다.
 * 권한 코드가 없는 본인 동작이라 예외 원장에 있다. 실패 수 · 대기는 2차 인증과 같은 칸이다.
 */
@ApiTags('[관리자] 내 정보')
@UseGuards(AdminJwtAuthGuard, RolesGuard, OriginCheckGuard)
@Roles('admin', 'sales')
@Controller('admin/me')
export class SelfPasswordController {
  constructor(private readonly mfa: MfaService) {}

  @ApiOperation({ summary: '본인 비밀번호 변경 — 현재 비밀번호 확인 뒤, 지금 세션만 남기고 끊는다' })
  @Post('password')
  changePassword(@Body() dto: ChangeOwnPasswordDto, @Req() req: AdminRequest & Request) {
    return this.mfa.changePassword(req.admin!, dto.currentPassword, dto.newPassword, auditContext(req));
  }

  //* 내부 관리자만(메서드 @Roles 가 클래스 값을 덮는다). 본문 없음 — 자유 입력 칸을 두지 않는다(노트 84 T11)
  @ApiOperation({ summary: '최고관리자 신청 — 내부 관리자 본인, 2차 인증이 켜져 있어야 한다' })
  @Post('super-request')
  @Roles('admin')
  requestSuper(@Req() req: AdminRequest & Request) {
    return this.mfa.requestSuper(req.admin!, auditContext(req));
  }
}

/**
 * 마이페이지 「다른 곳 모두 로그아웃」(리뷰 N-4) — 네 신원이라 2차 인증 컨트롤러와 같은 가드 묶음 · @AllowOrgWrite.
 * 권한 코드가 없는 본인 동작이라 예외 원장에 있다. 실패 수 · 대기는 2차 인증과 같은 칸이다.
 */
@ApiTags('[관리자] 내 정보')
@UseGuards(AdminJwtAuthGuard, RolesGuard, CorpReadonlyGuard, OriginCheckGuard)
@Roles('admin', 'sales', 'corp')
@Controller('admin/me/sessions')
export class SelfSessionsController {
  constructor(private readonly mfa: MfaService) {}

  @ApiOperation({ summary: '다른 곳 모두 로그아웃 — 현재 비밀번호 확인 뒤, 지금 세션만 남기고 끊는다' })
  @Post('revoke-others')
  @AllowOrgWrite()
  revokeOthers(@Body() dto: RevokeOtherSessionsDto, @Req() req: AdminRequest & Request) {
    return this.mfa.revokeOthers(req.admin!, dto.currentPassword, auditContext(req));
  }
}
