import { logger } from '@goodgo/logger';
import { PrismaClient, VerificationType, VerificationStatus } from '@prisma/client';
import { Request } from 'express';
import { v4 as uuidv4 } from 'uuid';

import { getPrismaClient } from '../../../config/database.config';
import { auditService } from '../../../core/events/audit.service';
import { NotFoundError, BadRequestError } from '../../../errors/http-error';
import { IdentityVerificationRepository } from '../../../repositories/identity-verification.repository';
import { UserProfileRepository } from '../../../repositories/user-profile.repository';
import { UserRepository } from '../../../repositories/user.repository';


// EN: DTOs imported for future use / VI: DTOs được import để sử dụng sau
// import { VerificationRequestDto, VerifyEmailDto, VerifyPhoneDto } from '../identity.dto';

/**
 * EN: Identity Verification Service
 * VI: Service xác thực danh tính
 */
export class VerificationService {
  private prisma: PrismaClient;
  private verificationRepo: IdentityVerificationRepository;
  private userRepo: UserRepository;
  private profileRepo: UserProfileRepository;

  constructor() {
    this.prisma = getPrismaClient();
    this.verificationRepo = new IdentityVerificationRepository(this.prisma);
    this.userRepo = new UserRepository(this.prisma);
    this.profileRepo = new UserProfileRepository(this.prisma);
  }

  /**
   * EN: Request email verification
   * VI: Yêu cầu xác thực email
   */
  async requestEmailVerification(userId: string, req?: Request): Promise<{ token: string; expiresAt: Date }> {
    const user = await this.userRepo.findById(userId);
    if (!user) {
      throw new NotFoundError('User');
    }

    // Check if already verified
    if (user.emailVerified) {
      throw new BadRequestError('Email already verified / Email đã được xác thực');
    }

    // Generate verification token
    const token = uuidv4();
    const expiresAt = new Date();
    expiresAt.setHours(expiresAt.getHours() + 24); // 24 hours expiry

    // Create verification record
    await this.verificationRepo.createVerification({
      userId,
      type: 'EMAIL',
      status: VerificationStatus.PENDING,
      method: 'EMAIL_LINK',
      token,
      expiresAt,
    });

    // TODO: Send verification email (requires email service integration)
    // await emailService.sendVerificationEmail(user.email, token);

    if (req) {
      await auditService.logFromRequest(req, 'EMAIL_VERIFICATION_REQUESTED', {
        userId,
        success: true,
      });
    }

    logger.info('Email verification requested', { userId });

    return { token, expiresAt };
  }

  /**
   * EN: Verify email with token
   * VI: Xác thực email với token
   */
  async verifyEmail(token: string, req?: Request): Promise<{ verified: boolean }> {
    const verification = await this.verificationRepo.findByToken(token);
    if (!verification) {
      throw new BadRequestError('Invalid verification token / Token xác thực không hợp lệ');
    }

    if (verification.status !== VerificationStatus.PENDING) {
      throw new BadRequestError('Verification already processed / Xác thực đã được xử lý');
    }

    if (verification.expiresAt && verification.expiresAt < new Date()) {
      await this.verificationRepo.updateStatus(verification.id, VerificationStatus.EXPIRED);
      throw new BadRequestError('Verification token expired / Token xác thực đã hết hạn');
    }

    // Update verification status
    await this.verificationRepo.updateStatus(verification.id, VerificationStatus.VERIFIED, new Date());

    // Update user emailVerified status
    await this.prisma.user.update({
      where: { id: verification.userId },
      data: { emailVerified: true },
    });

    if (req) {
      await auditService.logFromRequest(req, 'EMAIL_VERIFIED', {
        userId: verification.userId,
        success: true,
      });
    }

    logger.info('Email verified', { userId: verification.userId });

    return { verified: true };
  }

  /**
   * EN: Request phone verification
   * VI: Yêu cầu xác thực điện thoại
   */
  async requestPhoneVerification(userId: string, phone: string, req?: Request): Promise<{ token: string; expiresAt: Date }> {
    const user = await this.userRepo.findById(userId);
    if (!user) {
      throw new NotFoundError('User');
    }

    // Generate verification code (6 digits)
    const code = Math.floor(100000 + Math.random() * 900000).toString();
    const token = uuidv4();
    const expiresAt = new Date();
    expiresAt.setMinutes(expiresAt.getMinutes() + 10); // 10 minutes expiry

    // Update profile with phone
    await this.profileRepo.upsert(userId, { phone, phoneVerified: false });

    // Create verification record
    await this.verificationRepo.createVerification({
      userId,
      type: 'PHONE',
      status: VerificationStatus.PENDING,
      method: 'SMS',
      token,
      expiresAt,
      metadata: { code, phone },
    });

    // TODO: Send SMS (requires SMS service integration)
    // await smsService.sendVerificationCode(phone, code);

    if (req) {
      await auditService.logFromRequest(req, 'PHONE_VERIFICATION_REQUESTED', {
        userId,
        phone,
        success: true,
      });
    }

    logger.info('Phone verification requested', { userId, phone });

    return { token, expiresAt };
  }

  /**
   * EN: Verify phone with code
   * VI: Xác thực điện thoại với mã
   */
  async verifyPhone(token: string, code: string, req?: Request): Promise<{ verified: boolean }> {
    const verification = await this.verificationRepo.findByToken(token);
    if (!verification) {
      throw new BadRequestError('Invalid verification token / Token xác thực không hợp lệ');
    }

    if (verification.status !== VerificationStatus.PENDING) {
      throw new BadRequestError('Verification already processed / Xác thực đã được xử lý');
    }

    if (verification.expiresAt && verification.expiresAt < new Date()) {
      await this.verificationRepo.updateStatus(verification.id, VerificationStatus.EXPIRED);
      throw new BadRequestError('Verification token expired / Token xác thực đã hết hạn');
    }

    // Verify code (from metadata)
    const storedCode = (verification.metadata as any)?.code;
    if (storedCode !== code) {
      throw new BadRequestError('Invalid verification code / Mã xác thực không hợp lệ');
    }

    // Update verification status
    await this.verificationRepo.updateStatus(verification.id, VerificationStatus.VERIFIED, new Date());

    // Update profile phoneVerified status
    await this.profileRepo.verifyPhone(verification.userId);

    if (req) {
      await auditService.logFromRequest(req, 'PHONE_VERIFIED', {
        userId: verification.userId,
        success: true,
      });
    }

    logger.info('Phone verified', { userId: verification.userId });

    return { verified: true };
  }

  /**
   * EN: Request document verification (placeholder)
   * VI: Yêu cầu xác thực tài liệu (placeholder)
   */
  async requestDocumentVerification(userId: string, documentUrl: string, req?: Request): Promise<{ verificationId: string }> {
    const user = await this.userRepo.findById(userId);
    if (!user) {
      throw new NotFoundError('User');
    }

    const verification = await this.verificationRepo.createVerification({
      userId,
      type: 'DOCUMENT',
      status: VerificationStatus.PENDING,
      method: 'DOCUMENT_SCAN',
      metadata: { documentUrl },
    });

    // TODO: Process document verification (requires document verification service)

    if (req) {
      await auditService.logFromRequest(req, 'DOCUMENT_VERIFICATION_REQUESTED', {
        userId,
        success: true,
      });
    }

    logger.info('Document verification requested', { userId, verificationId: verification.id });

    return { verificationId: verification.id };
  }

  /**
   * EN: Get verification status
   * VI: Lấy trạng thái xác thực
   */
  async getVerificationStatus(userId: string, type: VerificationType): Promise<any> {
    const verification = await this.verificationRepo.findByUserAndType(userId, type);
    return verification;
  }
}

export const verificationService = new VerificationService();
