import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { VerificationModel } from '../models/verification.model';
import { BookingVerification } from '../../domain/entities/booking-verification.entity';
import { UnprocessableEntityException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { WhatsappService } from 'src/services/whatsapp/whatsapp.service';
export class VerificationService {
  constructor(
    @InjectRepository(VerificationModel)
    private readonly verificationRepository: Repository<VerificationModel>,
    private readonly jwtService: JwtService,
  ) {}

  maxAttempts = 3;
  expiredTime = 5 * 60 * 1000;
  expiredTimeRegister = 1 * 60 * 1000;

  async generateToken(payload: BookingVerification) {
    return this.jwtService.sign({
      phone_number: payload.phone_number,
      name: payload.name,
      created_at: payload.created_at,
    });
  }

  async register(data: BookingVerification) {
    const isProduction = process.env.NODE_ENV === 'true';
    const currentTime = Math.floor(Date.now()); // current time in seconds

    // Generate a 4 digit OTP code
    const otpCode = Math.floor(1000 + Math.random() * 9000).toString();

    let verification = await this.verificationRepository.findOne({
      where: { phone_number: data.phone_number },
    });

    if (
      isProduction &&
      verification.updated_at &&
      currentTime - verification.updated_at < this.expiredTimeRegister
    ) {
      throw new UnprocessableEntityException('Please try again in 1 minute');
    }

    data.code = otpCode;
    data.tried = 0;
    data.updated_at = currentTime;

    if (verification) {
      // Update existing record
      verification = this.verificationRepository.merge(verification, data);
    } else {
      // Create new record
      verification = this.verificationRepository.create(data);
    }
    const payload = await this.verificationRepository.save(verification);

    const notificationService = new WhatsappService();
    notificationService.sendOtpNotification({
      phone: data.phone_number,
      code: otpCode,
    });

    return payload;
  }

  async findByPhoneNumber(phoneNumber: string) {
    return this.verificationRepository.findOne({
      where: { phone_number: phoneNumber },
    });
  }

  async verify(data: BookingVerification): Promise<BookingVerification> {
    const verification = await this.findByPhoneNumber(data.phone_number);
    if (!verification) {
      throw new UnprocessableEntityException('Phone number not found');
    }

    if (verification.tried >= this.maxAttempts) {
      throw new UnprocessableEntityException(
        'Too many attempts, please resend OTP Code',
      );
    }

    if (verification.code != data.code) {
      verification.tried++;
      await this.verificationRepository.save(verification);
      throw new UnprocessableEntityException('Invalid verification code');
    }

    const currentTime = Math.floor(Date.now());
    if (
      verification.updated_at &&
      currentTime - verification.updated_at > this.expiredTime
    ) {
      throw new UnprocessableEntityException('Verification code expired');
    }

    return verification;
  }

  async update(id: string, data: BookingVerification) {
    return this.verificationRepository.update(id, data);
  }

  async delete(id: string) {
    return this.verificationRepository.delete(id);
  }
}
