const User = require('../models/User');
const Commission = require('../models/Commission');
const PaymentOrder = require('../models/PaymentOrder');
const { sequelize } = require('../config/database');
const commissionConfigService = require('./commissionConfigService');

/**
 * Commission Service
 * Handles commission calculation and management
 */

/**
 * Calculate and record commissions for a payment order
 * Creates separate commission records for each currency present (RMB and/or PHP)
 * @param {string} paymentOrderId - Payment order ID
 * @returns {Array<Object>|null} Array of commission records or null if no commission generated
 */
const calculateCommission = async (paymentOrderId) => {
  // Get payment order with user info
  const paymentOrder = await PaymentOrder.findByPk(paymentOrderId, {
    include: [{ model: User, as: 'user' }],
  });

  if (!paymentOrder) {
    throw new Error('Payment order not found');
  }

  if (paymentOrder.status !== 'active') {
    return null; // Don't calculate commission for cancelled orders
  }

  // Check if user was invited
  const inviteeUser = paymentOrder.user;
  if (!inviteeUser || !inviteeUser.invitedBy) {
    return null; // User was not invited, no commission
  }

  // Get current commission rate
  const commissionRate = await commissionConfigService.getCommissionRate();

  // Collect all currency amounts to process
  const currencyAmounts = [];
  
  // Check RMB amount (including legacy 'amount' field)
  const rmbAmount = parseFloat(paymentOrder.amountRmb || 0) || parseFloat(paymentOrder.amount || 0);
  if (rmbAmount > 0) {
    currencyAmounts.push({ currency: 'RMB', paymentAmount: rmbAmount });
  }
  
  // Check Peso amount
  const pesoAmount = parseFloat(paymentOrder.amountPeso || 0);
  if (pesoAmount > 0) {
    currencyAmounts.push({ currency: 'PHP', paymentAmount: pesoAmount });
  }
  
  if (currencyAmounts.length === 0) {
    return null; // No valid payment amounts
  }

  // Start transaction
  const transaction = await sequelize.transaction();

  try {
    const commissions = [];
    
    // Get inviter for balance updates
    const inviter = await User.findByPk(inviteeUser.invitedBy, { transaction });
    
    // Create commission record for each currency
    for (const { currency, paymentAmount } of currencyAmounts) {
      const commissionAmount = paymentAmount * commissionRate;
      
      // Create commission record
      const commission = await Commission.create({
        inviterId: inviteeUser.invitedBy,
        inviteeId: inviteeUser.id,
        paymentOrderId: paymentOrder.id,
        paymentAmount: paymentAmount,
        commissionRate: commissionRate,
        commissionAmount: commissionAmount,
        currency: currency,
        status: 'credited',
      }, { transaction });
      
      commissions.push(commission);
      
      // Update inviter's balance based on currency
      if (inviter) {
        if (currency === 'PHP') {
          inviter.balancePeso = parseFloat(inviter.balancePeso || 0) + commissionAmount;
        } else {
          inviter.balance = parseFloat(inviter.balance || 0) + commissionAmount;
        }
      }
    }
    
    // Save inviter balance updates
    if (inviter) {
      await inviter.save({ transaction });
    }

    await transaction.commit();

    return commissions;
  } catch (error) {
    await transaction.rollback();
    throw error;
  }
};

/**
 * Get commission records for an inviter
 * @param {string} inviterId - Inviter user ID
 * @param {Object} options - Query options (page, limit)
 * @returns {Object} Commission records with pagination
 */
const getCommissionsByInviter = async (inviterId, options = {}) => {
  const { page = 1, limit = 20 } = options;
  const offset = (page - 1) * limit;

  const { count, rows } = await Commission.findAndCountAll({
    where: { inviterId, status: 'credited' },
    include: [
      {
        model: User,
        as: 'invitee',
        attributes: ['id', 'uid', 'nickname', 'avatar'],
      },
      {
        model: PaymentOrder,
        as: 'paymentOrder',
        attributes: ['id', 'orderNo', 'serviceContent', 'paymentTime'],
      },
    ],
    order: [['createdAt', 'DESC']],
    limit: parseInt(limit),
    offset: parseInt(offset),
  });

  const records = rows.map(commission => ({
    id: commission.id,
    invitee: commission.invitee ? {
      id: commission.invitee.id,
      uid: commission.invitee.uid,
      nickname: commission.invitee.nickname,
      avatar: commission.invitee.avatar,
    } : null,
    paymentOrder: commission.paymentOrder ? {
      id: commission.paymentOrder.id,
      orderNo: commission.paymentOrder.orderNo,
      serviceContent: commission.paymentOrder.serviceContent,
      paymentTime: commission.paymentOrder.paymentTime,
    } : null,
    paymentAmount: parseFloat(commission.paymentAmount).toFixed(2),
    currency: commission.currency || 'RMB',
    commissionRate: `${(parseFloat(commission.commissionRate) * 100).toFixed(2)}%`,
    commissionAmount: parseFloat(commission.commissionAmount).toFixed(2),
    createdAt: commission.createdAt,
  }));

  return {
    records,
    pagination: {
      page: parseInt(page),
      limit: parseInt(limit),
      total: count,
      totalPages: Math.ceil(count / limit),
    },
  };
};

/**
 * Get invited users with their commission details (grouped by user)
 * @param {string} inviterId - Inviter user ID
 * @param {Object} options - Query options (page, limit)
 * @returns {Object} Invited users with commission details
 */
const getInvitedUsersWithCommissions = async (inviterId, options = {}) => {
  const { page = 1, limit = 20 } = options;
  const offset = (page - 1) * limit;

  // Get all invited users
  const { count, rows: invitedUsers } = await User.findAndCountAll({
    where: { invitedBy: inviterId },
    attributes: ['id', 'uid', 'nickname', 'avatar', 'createdAt'],
    order: [['createdAt', 'DESC']],
    limit: parseInt(limit),
    offset: parseInt(offset),
  });

  // Get commission records for each invited user
  const usersWithCommissions = await Promise.all(
    invitedUsers.map(async (user) => {
      // Get all commissions for this invitee
      const commissions = await Commission.findAll({
        where: { 
          inviterId, 
          inviteeId: user.id,
          status: 'credited' 
        },
        include: [
          {
            model: PaymentOrder,
            as: 'paymentOrder',
            attributes: ['id', 'orderNo', 'serviceContent', 'paymentTime', 'amountRmb', 'amountPeso'],
          },
        ],
        order: [['createdAt', 'DESC']],
      });

      // Calculate totals by currency
      let totalCommissionRmb = 0;
      let totalCommissionPeso = 0;
      let totalPaymentRmb = 0;
      let totalPaymentPeso = 0;

      const orders = commissions.map(c => {
        const amount = parseFloat(c.commissionAmount);
        const paymentAmount = parseFloat(c.paymentAmount);
        
        if (c.currency === 'PHP') {
          totalCommissionPeso += amount;
          totalPaymentPeso += paymentAmount;
        } else {
          totalCommissionRmb += amount;
          totalPaymentRmb += paymentAmount;
        }

        return {
          id: c.id,
          orderNo: c.paymentOrder?.orderNo || '-',
          serviceContent: c.paymentOrder?.serviceContent || '-',
          paymentTime: c.paymentOrder?.paymentTime || c.createdAt,
          paymentAmount: paymentAmount.toFixed(2),
          commissionAmount: amount.toFixed(2),
          currency: c.currency || 'RMB',
          createdAt: c.createdAt,
        };
      });

      return {
        user: {
          id: user.id,
          uid: user.uid,
          nickname: user.nickname,
          avatar: user.avatar,
          registeredAt: user.createdAt,
        },
        orderCount: orders.length,
        orders,
        totalPaymentRmb: totalPaymentRmb.toFixed(2),
        totalPaymentPeso: totalPaymentPeso.toFixed(2),
        totalCommissionRmb: totalCommissionRmb.toFixed(2),
        totalCommissionPeso: totalCommissionPeso.toFixed(2),
      };
    })
  );

  return {
    records: usersWithCommissions,
    pagination: {
      page: parseInt(page),
      limit: parseInt(limit),
      total: count,
      totalPages: Math.ceil(count / limit),
    },
  };
};

/**
 * Generate invitation code
 * @returns {string} Invitation code
 */
const generateInvitationCode = () => {
  const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
  let code = '';
  for (let i = 0; i < 6; i++) {
    code += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return code;
};

/**
 * Get commission statistics for an inviter
 * @param {string} inviterId - Inviter user ID
 * @returns {Object} Commission statistics
 */
const getCommissionStats = async (inviterId) => {
  const user = await User.findByPk(inviterId);
  
  if (!user) {
    throw new Error('User not found');
  }

  // If user doesn't have invitation code, generate one
  let invitationCode = user.invitationCode;
  if (!invitationCode) {
    invitationCode = generateInvitationCode();
    await user.update({ invitationCode });
  }

  // Get total invites count
  const totalInvites = await User.count({
    where: { invitedBy: inviterId },
  });

  // Get commission statistics by currency
  const commissions = await Commission.findAll({
    where: { inviterId, status: 'credited' },
    attributes: ['commissionAmount', 'currency'],
  });

  // Calculate total commission by currency
  let totalCommissionRmb = 0;
  let totalCommissionPeso = 0;
  
  commissions.forEach(c => {
    const amount = parseFloat(c.commissionAmount);
    if (c.currency === 'PHP') {
      totalCommissionPeso += amount;
    } else {
      totalCommissionRmb += amount;
    }
  });

  // Get paid invites count (invitees who have made payments)
  const paidInvitesCount = await Commission.count({
    where: { inviterId, status: 'credited' },
    distinct: true,
    col: 'invitee_id',
  });

  return {
    totalInvites,
    paidInvites: paidInvitesCount,
    totalCommission: totalCommissionRmb.toFixed(2),
    totalCommissionRmb: totalCommissionRmb.toFixed(2),
    totalCommissionPeso: totalCommissionPeso.toFixed(2),
    commissionCount: commissions.length,
    availableBalance: parseFloat(user.balance).toFixed(2),
    availableBalanceRmb: parseFloat(user.balance).toFixed(2),
    availableBalancePeso: parseFloat(user.balancePeso || 0).toFixed(2),
    invitationCode: invitationCode,
  };
};

/**
 * Get all commission records (for admin)
 * @param {Object} options - Query options (page, limit, inviterId, inviteeId)
 * @returns {Object} Commission records with pagination
 */
const getAllCommissions = async (options = {}) => {
  const { page = 1, limit = 20, inviterId, inviteeId, status } = options;
  const offset = (page - 1) * limit;

  const where = {};
  if (inviterId) where.inviterId = inviterId;
  if (inviteeId) where.inviteeId = inviteeId;
  if (status) where.status = status;

  const { count, rows } = await Commission.findAndCountAll({
    where,
    include: [
      {
        model: User,
        as: 'inviter',
        attributes: ['id', 'uid', 'nickname'],
      },
      {
        model: User,
        as: 'invitee',
        attributes: ['id', 'uid', 'nickname'],
      },
      {
        model: PaymentOrder,
        as: 'paymentOrder',
        attributes: ['id', 'orderNo', 'amount'],
      },
    ],
    order: [['createdAt', 'DESC']],
    limit: parseInt(limit),
    offset: parseInt(offset),
  });

  const records = rows.map(commission => ({
    id: commission.id,
    inviter: commission.inviter,
    invitee: commission.invitee,
    paymentOrder: commission.paymentOrder,
    paymentAmount: parseFloat(commission.paymentAmount).toFixed(2),
    commissionRate: `${(parseFloat(commission.commissionRate) * 100).toFixed(2)}%`,
    commissionAmount: parseFloat(commission.commissionAmount).toFixed(2),
    currency: commission.currency || 'RMB',
    status: commission.status,
    createdAt: commission.createdAt,
  }));

  return {
    records,
    pagination: {
      page: parseInt(page),
      limit: parseInt(limit),
      total: count,
      totalPages: Math.ceil(count / limit),
    },
  };
};

/**
 * Get platform commission statistics (for admin)
 * @returns {Object} Platform commission statistics
 */
const getPlatformCommissionStats = async () => {
  const Op = require('sequelize').Op;
  
  // Total commission paid by currency
  const commissions = await Commission.findAll({
    where: { status: 'credited' },
    attributes: ['commissionAmount', 'currency'],
    raw: true,
  });
  
  let totalPaidRmb = 0;
  let totalPaidPeso = 0;
  commissions.forEach(c => {
    const amount = parseFloat(c.commissionAmount) || 0;
    if (c.currency === 'PHP') {
      totalPaidPeso += amount;
    } else {
      totalPaidRmb += amount;
    }
  });

  // Total commission count
  const totalCount = await Commission.count({
    where: { status: 'credited' },
  });

  // Get user balance statistics (pending withdrawal) - dual currency
  const users = await User.findAll({
    attributes: ['balance', 'balancePeso'],
    raw: true,
  });

  let pendingWithdrawalRmb = 0;
  let pendingWithdrawalPeso = 0;
  users.forEach(u => {
    pendingWithdrawalRmb += parseFloat(u.balance) || 0;
    pendingWithdrawalPeso += parseFloat(u.balancePeso) || 0;
  });

  return {
    totalCommissionPaid: parseFloat(totalPaidRmb).toFixed(2),
    totalCommissionPaidRmb: parseFloat(totalPaidRmb).toFixed(2),
    totalCommissionPaidPeso: parseFloat(totalPaidPeso).toFixed(2),
    totalCommissionCount: totalCount,
    pendingWithdrawal: pendingWithdrawalRmb.toFixed(2),
    pendingWithdrawalRmb: pendingWithdrawalRmb.toFixed(2),
    pendingWithdrawalPeso: pendingWithdrawalPeso.toFixed(2),
  };
};

module.exports = {
  calculateCommission,
  getCommissionsByInviter,
  getInvitedUsersWithCommissions,
  getCommissionStats,
  getAllCommissions,
  getPlatformCommissionStats,
};
