const EmailVerificationRepository = require('../../repositories/email/EmailVerificationRepository');
const MailService = require('./MailService');
const { logger } = require('../../middleware/logger');

class EmailVerificationService {
  static async sendVerificationEmail(user, unitOfWork) {
    logger.info('EmailVerificationService.sendVerificationEmail:start', { userId: user.id, email: user.email });
    const emailVerificationRepo = new EmailVerificationRepository(unitOfWork);

    try {
      // Check if already verified
      const status = await unitOfWork.connection.query(
        'SELECT email_verified FROM user_status WHERE user_id = ?', [user.id]
      );
      if (status[0][0] && status[0][0].email_verified) {
        logger.warn('EmailVerificationService.sendVerificationEmail:already_verified', { userId: user.id });
        throw new Error('Email already verified');
      }

      // Generate 6-digit code and expiry
      const code = Math.floor(100000 + Math.random() * 900000).toString();
      const expiresAt = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes

      // Upsert code in DB
      await emailVerificationRepo.upsertCode(user.id, code, expiresAt);
      logger.info('EmailVerificationService.sendVerificationEmail:code_upserted', { userId: user.id });

      // Send email
      await MailService.sendVerificationCodeEmail({
        email: user.email,
        code,
        expiresAt
      });
      logger.info('EmailVerificationService.sendVerificationEmail:email_sent', { userId: user.id, email: user.email });

      logger.info('EmailVerificationService.sendVerificationEmail:success', { userId: user.id });
      return true;
    } catch (error) {
      logger.error('EmailVerificationService.sendVerificationEmail:error', { userId: user.id, error: error.message });
      throw error;
    }
  }

  static async verifyCode(userId, code, unitOfWork) {
    logger.info('EmailVerificationService.verifyCode:start', { userId, code });
    const emailVerificationRepo = new EmailVerificationRepository(unitOfWork);

    try {
      // Get latest, unexpired, unverified code
      const record = await emailVerificationRepo.getByUserId(userId);
      if (
        !record ||
        record.verified_at ||
        new Date(record.expires_at) < new Date() ||
        record.verification_code !== code
      ) {
        logger.warn('EmailVerificationService.verifyCode:invalid_or_expired', { userId, code });
        // Optionally increment attempts
        if (record) {
          await emailVerificationRepo.incrementAttempts(record.id);
        }
        return { success: false, error: 'Invalid or expired code' };
      }

      // Mark as verified
      await emailVerificationRepo.setVerified(record.id);
      logger.info('EmailVerificationService.verifyCode:code_verified', { userId });

      // Update user_status
      await unitOfWork.connection.query(
        `UPDATE user_status SET email_verified = 1, email_verified_at = NOW() WHERE user_id = ?`,
        [userId]
      );
      logger.info('EmailVerificationService.verifyCode:user_status_updated', { userId });

      // Check if all steps are complete and set status to 'pending' if so
      const UserStatusService = require('../status/UserStatusService');
      await UserStatusService.checkAndSetPendingIfComplete(userId, unitOfWork);
      logger.info('EmailVerificationService.verifyCode:pending_check_complete', { userId });

      // Auto-grant can_subscribe permission if user doesn't already have it
      try {
        const [permRows] = await unitOfWork.connection.query(
          `SELECT id FROM permissions WHERE name = 'can_subscribe' AND is_active = TRUE LIMIT 1`
        );
        if (permRows.length > 0) {
          const permId = permRows[0].id;
          const [existing] = await unitOfWork.connection.query(
            `SELECT 1 FROM user_permissions WHERE user_id = ? AND permission_id = ? LIMIT 1`,
            [userId, permId]
          );
          if (existing.length === 0) {
            await unitOfWork.connection.query(
              `INSERT INTO user_permissions (user_id, permission_id) VALUES (?, ?)`,
              [userId, permId]
            );
            logger.info('EmailVerificationService.verifyCode:can_subscribe_granted', { userId });
          }
        }
      } catch (permError) {
        logger.error('EmailVerificationService.verifyCode:permission_grant_error', { userId, error: permError.message });
      }

      logger.info('EmailVerificationService.verifyCode:success', { userId });
      return { success: true };
    } catch (error) {
      logger.error('EmailVerificationService.verifyCode:error', { userId, error: error.message });
      throw error;
    }
  }
}

module.exports = EmailVerificationService;
