const PersonalUserRepository = require('../../../repositories/user/personal/PersonalUserRepository');
const UserStatusService = require('../../status/UserStatusService');
const UnitOfWork = require('../../../database/UnitOfWork');
const MailService = require('../../email/MailService');
const AbonemmentService = require('../../abonemments/AbonemmentService');
const User = require('../../../models/User');
const { logger } = require('../../../middleware/logger');

const abonemmentService = new AbonemmentService();

class GuestUserService {
  /**
   * Create a guest user account with role='guest'.
   * Guest users only have access to subscriptions, nothing else.
   */
  static async createGuestUser({ email, password, firstName, lastName, referralEmail, lang }) {
    logger.info('GuestUserService.createGuestUser:start', { email, firstName, lastName });

    const unitOfWork = new UnitOfWork();
    await unitOfWork.start();
    unitOfWork.registerRepository('personalUser', new PersonalUserRepository(unitOfWork));

    try {
      const personalRepo = unitOfWork.getRepository('personalUser');

      // Check if user already exists
      const existing = await personalRepo.findByEmail(email);
      if (existing) {
        await unitOfWork.rollback();
        throw new Error('User already exists');
      }

      // Create user in DB with role='guest'
      const conn = unitOfWork.connection;
      const hashedPassword = await User.hashPassword(password);

      const [userResult] = await conn.query(
        `INSERT INTO users (email, password, user_type, role) VALUES (?, ?, 'personal', 'guest')`,
        [email, hashedPassword]
      );
      const userId = userResult.insertId;

      await conn.query(
        `INSERT INTO personal_profiles (user_id, first_name, last_name) VALUES (?, ?, ?)`,
        [userId, firstName, lastName]
      );

      // Initialize user status as active (skip full registration flow for guests)
      await UserStatusService.initializeUserStatus(userId, 'personal', unitOfWork, 'active');

      // Mark non-email status flags as completed for guests — they skip ID upload, profile, and contract
      // email_verified stays FALSE so guests must verify their email on first login
      await conn.query(
        `UPDATE user_status SET email_verified = FALSE, profile_completed = TRUE, documents_uploaded = TRUE, contract_signed = TRUE, registration_completed = TRUE, is_admin_verified = TRUE WHERE user_id = ?`,
        [userId]
      );

      // Handle referral if provided
      if (referralEmail) {
        try {
          const ReferralService = require('../../referral/ReferralService');
          await ReferralService.processReferral(userId, referralEmail, unitOfWork);
        } catch (refErr) {
          logger.warn('GuestUserService.createGuestUser:referral_failed', { userId, error: refErr?.message });
        }
      }

      // Link any pending gift subscriptions to this user
      await abonemmentService.linkGiftFlagsToUser(email, userId);

      // Send a welcome email
      const chosenLang = lang || 'en';
      await MailService.sendRegistrationEmail({
        email,
        firstName,
        lastName,
        userType: 'personal',
        lang: chosenLang,
      });

      await unitOfWork.commit();

      logger.info('GuestUserService.createGuestUser:success', { userId, email });
      return { id: userId, email, firstName, lastName, role: 'guest' };
    } catch (error) {
      logger.error('GuestUserService.createGuestUser:error', { email, error: error.message });
      await unitOfWork.rollback(error);
      throw error;
    }
  }

  static async findGuestByEmail(email) {
    const unitOfWork = new UnitOfWork();
    await unitOfWork.start();
    try {
      const conn = unitOfWork.connection;
      const [rows] = await conn.query(
        `SELECT u.id, u.email, u.role, pp.first_name, pp.last_name
         FROM users u
         LEFT JOIN personal_profiles pp ON u.id = pp.user_id
         WHERE u.email = ? AND u.role = 'guest' LIMIT 1`,
        [email]
      );
      await unitOfWork.commit();
      return rows[0] || null;
    } catch (error) {
      await unitOfWork.rollback(error);
      throw error;
    }
  }
}

module.exports = GuestUserService;
