import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, type ICommandHandler } from '@nestjs/cqrs';
import { DomainException, LoggerService, ValidationException } from '@modules/shared';
import { USER_REPOSITORY, type IUserRepository } from '../../../domain/repositories/user.repository';
import { MfaService, type MfaSetupResult } from '../../../infrastructure/services/mfa.service';
import { SetupMfaCommand } from './setup-mfa.command';

export interface SetupMfaResultDto {
  secret: string;
  qrCodeDataUrl: string;
  otpauthUrl: string;
}

@CommandHandler(SetupMfaCommand)
export class SetupMfaHandler implements ICommandHandler<SetupMfaCommand> {
  constructor(
    @Inject(USER_REPOSITORY) private readonly userRepo: IUserRepository,
    private readonly mfaService: MfaService,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: SetupMfaCommand): Promise<SetupMfaResultDto> {
    try {
      const user = await this.userRepo.findById(command.userId);
      if (!user) {
        throw new ValidationException('Người dùng không tồn tại');
      }

      if (user.totpEnabled) {
        throw new ValidationException('MFA đã được bật. Vui lòng tắt trước khi thiết lập lại');
      }

      // Generate TOTP setup (secret + QR code)
      const identifier = user.email?.value ?? user.phone.value;
      const setup: MfaSetupResult = await this.mfaService.generateSetup(identifier);

      // Store secret temporarily (not enabled yet — user must verify first)
      await this.userRepo.updateMfaSecret(command.userId, setup.secret);

      return {
        secret: setup.secret,
        qrCodeDataUrl: setup.qrCodeDataUrl,
        otpauthUrl: setup.otpauthUrl,
      };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to setup MFA: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể thiết lập MFA');
    }
  }
}
