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 commission for a payment order
 * @param {string} paymentOrderId - Payment order ID
 * @returns {Object|null} Commission record 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();

  // Calculate commission amount
  const paymentAmount = parseFloat(paymentOrder.amount);
  const commissionAmount = paymentAmount * commissionRate;

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

  try {
    // Create commission record
    const commission = await Commission.create({
      inviterId: inviteeUser.invitedBy,
      inviteeId: inviteeUser.id,
      paymentOrderId: paymentOrder.id,
      paymentAmount: paymentAmount,
      commissionRate: commissionRate,
      commissionAmount: commissionAmount,
      status: 'credited',
    }, { transaction });

    // Update inviter's balance
    const inviter = await User.findByPk(inviteeUser.invitedBy, { transaction });
    if (inviter) {
      inviter.balance = parseFloat(inviter.balance) + commissionAmount;
      await inviter.save({ transaction });
    }

    await transaction.commit();

    return commission;
  } 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: {
      id: commission.invitee.id,
      uid: commission.invitee.uid,
      nickname: commission.invitee.nickname,
      avatar: commission.invitee.avatar,
    },
    paymentOrder: {
      id: commission.paymentOrder.id,
      orderNo: commission.paymentOrder.orderNo,
      serviceContent: commission.paymentOrder.serviceContent,
      paymentTime: commission.paymentOrder.paymentTime,
    },
    paymentAmount: parseFloat(commission.paymentAmount).toFixed(2),
    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),
    },
  };
};

/**
 * 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
  const commissions = await Commission.findAll({
    where: { inviterId, status: 'credited' },
    attributes: ['commissionAmount'],
  });

  const totalCommission = commissions.reduce(
    (sum, c) => sum + parseFloat(c.commissionAmount),
    0
  );

  // 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: totalCommission.toFixed(2),
    commissionCount: commissions.length,
    availableBalance: parseFloat(user.balance).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),
    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 () => {
  // Total commission paid
  const totalPaid = await Commission.sum('commissionAmount', {
    where: { status: 'credited' },
  }) || 0;

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

  // Get user balance statistics (pending withdrawal)
  const users = await User.findAll({
    where: sequelize.where(
      sequelize.cast(sequelize.col('balance'), 'DECIMAL(10,2)'),
      { [require('sequelize').Op.gt]: 0 }
    ),
    attributes: ['balance'],
  });

  const pendingWithdrawal = users.reduce(
    (sum, u) => sum + parseFloat(u.balance),
    0
  );

  return {
    totalCommissionPaid: parseFloat(totalPaid).toFixed(2),
    totalCommissionCount: totalCount,
    pendingWithdrawal: pendingWithdrawal.toFixed(2),
  };
};

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