import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, type ICommandHandler } from '@nestjs/cqrs';
import { createId } from '@paralleldrive/cuid2';
import { LoggerService, DomainException } from '@modules/shared';
import {
  MFA_CHALLENGE_REPOSITORY,
  type IMfaChallengeRepository,
} from '../../../domain/repositories/mfa-challenge.repository';
import { TokenService, type TokenPair } from '../../../infrastructure/services/token.service';
import { LoginUserCommand } from './login-user.command';

const MFA_CHALLENGE_TTL_MINUTES = 5;

export interface LoginResult {
  requiresMfa: boolean;
  challengeId?: string;
  tokens?: TokenPair;
}

@CommandHandler(LoginUserCommand)
export class LoginUserHandler implements ICommandHandler<LoginUserCommand> {
  constructor(
    private readonly tokenService: TokenService,
    @Inject(MFA_CHALLENGE_REPOSITORY)
    private readonly challengeRepo: IMfaChallengeRepository,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: LoginUserCommand): Promise<LoginResult> {
    try {
      // If MFA is required, create a challenge instead of tokens
      if (command.isMfaRequired) {
        const challengeId = createId();
        const expiresAt = new Date();
        expiresAt.setMinutes(expiresAt.getMinutes() + MFA_CHALLENGE_TTL_MINUTES);

        await this.challengeRepo.create({
          id: challengeId,
          userId: command.userId,
          type: 'totp',
          attemptCount: 0,
          maxAttempts: 5,
          isVerified: false,
          expiresAt,
        });

        return {
          requiresMfa: true,
          challengeId,
        };
      }

      // No MFA — issue tokens directly
      const tokens = await this.tokenService.generateTokenPair({
        sub: command.userId,
        phone: command.phone,
        role: command.role,
      });

      return {
        requiresMfa: false,
        tokens,
      };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to login user: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể tạo phiên đăng nhập, vui lòng thử lại');
    }
  }
}

