const Account = require('../models/account.model');
const Referral = require('../models/referral.model');
const Wallet = require('../models/wallet.model');
const Transaction = require('../models/transactions.model');
const NotificationService = require('../utils/notificationService');
const mongoose = require('mongoose');

class ReferralController {
  static async getReferralInfo(req, res) {
    try {
      const { id: userId } = req.user;

      if (!mongoose.Types.ObjectId.isValid(userId)) {
        return res.status(400).json({
          success: false,
          message: 'Invalid user ID format',
        });
      }

      const user = await Account.findById(userId)
        .select('id firstName lastName referralCode')
        .lean();

      if (!user) {
        return res.status(404).json({
          success: false,
          message: 'User not found',
        });
      }

      // Get referrals made by this user
      const referrals = await Referral.find({ referrerId: userId })
        .populate('referredId', 'id firstName lastName email createdAt')
        .sort({ createdAt: -1 })
        .lean();

      const totalReferrals = referrals.length;
      const completedReferrals = referrals.filter(
        (r) => r.status === 'completed',
      ).length;
      const totalEarnings = referrals
        .filter((r) => r.status === 'completed')
        .reduce((sum, r) => sum + parseFloat(r.bonusAmount || 0), 0);

      // Format referrals for response
      const formattedReferrals = referrals.map((ref) => ({
        id: ref._id,
        status: ref.status,
        bonusAmount: ref.bonusAmount,
        completedAt: ref.completedAt,
        createdAt: ref.createdAt,
        referred: ref.referredId
          ? {
              id: ref.referredId._id,
              firstName: ref.referredId.firstName,
              lastName: ref.referredId.lastName,
              email: ref.referredId.email,
              createdAt: ref.referredId.createdAt,
            }
          : null,
      }));

      return res.status(200).json({
        success: true,
        data: {
          referralCode: user.referralCode,
          referralLink: `${process.env.FRONTEND_URL}/register?ref=${user.referralCode}`,
          totalReferrals,
          completedReferrals,
          totalEarnings,
          referrals: formattedReferrals,
        },
      });
    } catch (error) {
      console.error('Error fetching referral info:', error);
      return res.status(500).json({
        success: false,
        message: 'Internal server error',
        error: error.message,
      });
    }
  }

  static async processReferralBonus(referredUserId) {
    const session = await mongoose.startSession();
    session.startTransaction();

    try {
      if (!mongoose.Types.ObjectId.isValid(referredUserId)) {
        await session.abortTransaction();
        session.endSession();
        throw new Error('Invalid referred user ID format');
      }

      const referredUser =
        await Account.findById(referredUserId).session(session);

      if (!referredUser || !referredUser.referredBy) {
        await session.abortTransaction();
        session.endSession();
        return;
      }

      const referrer = await Account.findOne({
        referralCode: referredUser.referredBy,
      }).session(session);

      if (!referrer) {
        await session.abortTransaction();
        session.endSession();
        return;
      }

      // Check if referral already exists
      const existingReferral = await Referral.findOne({
        referrerId: referrer._id,
        referredId: referredUserId,
      }).session(session);

      if (existingReferral) {
        await session.abortTransaction();
        session.endSession();
        return;
      }

      // Create referral record
      const [referral] = await Referral.create(
        [
          {
            referrerId: referrer._id,
            referredId: referredUserId,
            bonusAmount: 500.0,
            status: 'completed',
            completedAt: new Date(),
          },
        ],
        { session },
      );

      // Add bonus to referrer's referral balance
      const referrerWallet = await Wallet.findOne({
        user: referrer._id,
      }).session(session);

      if (referrerWallet) {
        referrerWallet.referralBalance =
          parseFloat(referrerWallet.referralBalance || 0) + 500.0;
        await referrerWallet.save({ session });

        // Create transaction record
        await Transaction.create(
          [
            {
              amount: 500.0,
              reference: `REF-${Date.now()}-${referrer._id}`,
              type: 'credit',
              method: 'wallet',
              purpose: 'referral',
              sender: referrer._id,
              receiver: referrer._id,
              status: 'success',
              description: `Referral bonus for referring ${referredUser.firstName} ${referredUser.lastName}`,
            },
          ],
          { session },
        );

        // Send notification to referrer
        await NotificationService.sendNotification(
          referrer._id,
          'Referral Bonus Earned!',
          `You've earned ₦500 referral bonus for referring ${referredUser.firstName} ${referredUser.lastName}`,
          'referral_bonus',
          { referralId: referral._id, amount: 500 },
        );
      }

      await session.commitTransaction();
      session.endSession();
      return referral;
    } catch (error) {
      await session.abortTransaction();
      session.endSession();
      console.error('Error processing referral bonus:', error);
      throw error;
    }
  }

  static async getReferralEarnings(req, res) {
    try {
      const { id: userId } = req.user;

      if (!mongoose.Types.ObjectId.isValid(userId)) {
        return res.status(400).json({
          success: false,
          message: 'Invalid user ID format',
        });
      }

      const [wallet, referrals] = await Promise.all([
        Wallet.findOne({ user: userId }).select('referralBalance').lean(),
        Referral.find({ referrerId: userId, status: 'completed' })
          .populate('referredId', 'firstName lastName email')
          .sort({ completedAt: -1 })
          .lean(),
      ]);

      const totalEarnings = referrals.reduce(
        (sum, r) => sum + parseFloat(r.bonusAmount || 0),
        0,
      );

      // Format referrals for response
      const formattedReferrals = referrals.map((ref) => ({
        id: ref._id,
        bonusAmount: ref.bonusAmount,
        completedAt: ref.completedAt,
        referred: ref.referredId
          ? {
              firstName: ref.referredId.firstName,
              lastName: ref.referredId.lastName,
              email: ref.referredId.email,
            }
          : null,
      }));

      return res.status(200).json({
        success: true,
        data: {
          referralBalance: wallet ? parseFloat(wallet.referralBalance || 0) : 0,
          totalEarnings,
          referrals: formattedReferrals,
        },
      });
    } catch (error) {
      console.error('Error fetching referral earnings:', error);
      return res.status(500).json({
        success: false,
        message: 'Internal server error',
        error: error.message,
      });
    }
  }

  /**
   * Get referral statistics for admin dashboard
   */
  static async getReferralStats(req, res) {
    try {
      const stats = await Referral.aggregate([
        {
          $group: {
            _id: '$status',
            count: { $sum: 1 },
            totalBonus: { $sum: '$bonusAmount' },
          },
        },
      ]);

      const totalReferrals = await Referral.countDocuments();
      const totalBonusPaid = await Referral.aggregate([
        { $match: { status: 'completed' } },
        { $group: { _id: null, total: { $sum: '$bonusAmount' } } },
      ]);

      // Get recent referrals
      const recentReferrals = await Referral.find()
        .populate('referrerId', 'firstName lastName email')
        .populate('referredId', 'firstName lastName email')
        .sort({ createdAt: -1 })
        .limit(10)
        .lean();

      return res.status(200).json({
        success: true,
        data: {
          stats: stats.reduce((acc, curr) => {
            acc[curr._id] = { count: curr.count, totalBonus: curr.totalBonus };
            return acc;
          }, {}),
          totalReferrals,
          totalBonusPaid: totalBonusPaid[0]?.total || 0,
          recentReferrals,
        },
      });
    } catch (error) {
      console.error('Error fetching referral stats:', error);
      return res.status(500).json({
        success: false,
        message: 'Internal server error',
        error: error.message,
      });
    }
  }
}

module.exports = ReferralController;
