const User = require('../models/User');
const Appointment = require('../models/Appointment');
const PaymentOrder = require('../models/PaymentOrder');
const Admin = require('../models/Admin');
const { sequelize } = require('../config/database');
const commissionService = require('./commissionService');

/**
 * Payment Order Service
 * Handles payment order creation and management
 */

/**
 * Generate unique order number
 * Format: PO + timestamp + random 4 digits
 * @returns {string} Order number
 */
const generateOrderNo = () => {
  const timestamp = Date.now().toString();
  const random = Math.floor(1000 + Math.random() * 9000);
  return `PO${timestamp}${random}`;
};

/**
 * Create payment order
 * @param {Object} data - Payment order data
 * @param {string} adminId - Admin ID who creates the order
 * @returns {Object} Created payment order with commission info
 */
const createPaymentOrder = async (data, adminId) => {
  const { userId, appointmentId, amount, amountPeso, amountRmb, serviceContent, paymentTime, notes } = data;

  // Validate required fields
  if (!userId) {
    throw new Error('请输入用户ID');
  }
  // At least one amount must be provided (check for actual positive numbers)
  const pesoAmount = amountPeso !== null && amountPeso !== undefined ? parseFloat(amountPeso) : 0;
  const rmbAmount = amountRmb !== null && amountRmb !== undefined ? parseFloat(amountRmb) : 0;
  const legacyAmount = amount !== null && amount !== undefined ? parseFloat(amount) : 0;
  
  const hasAmount = pesoAmount > 0 || rmbAmount > 0 || legacyAmount > 0;
  if (!hasAmount) {
    throw new Error('请输入有效的支付金额（比索或人民币至少填写一项）');
  }
  if (!serviceContent) {
    throw new Error('请输入服务内容');
  }
  if (!paymentTime) {
    throw new Error('请选择支付时间');
  }

  // Verify user exists - support both UUID and UID (6-digit number)
  let user;
  // Check if userId is a UUID format or a UID (6-digit number)
  const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId);
  
  if (isUUID) {
    user = await User.findByPk(userId);
  } else {
    // Try to find by UID (6-digit display ID)
    user = await User.findOne({ where: { uid: userId } });
  }
  
  if (!user) {
    throw new Error('用户不存在，请检查用户UID是否正确');
  }
  
  // Use the actual user ID (UUID) for creating the order
  const actualUserId = user.id;

  // Verify appointment exists if provided
  let actualAppointmentId = null;
  if (appointmentId) {
    // Check if appointmentId is a UUID or an appointment number
    const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(appointmentId);
    
    let appointment;
    if (isUUID) {
      appointment = await Appointment.findByPk(appointmentId);
    } else {
      // Try to find by appointment number
      appointment = await Appointment.findOne({ where: { appointmentNo: appointmentId } });
    }
    
    if (!appointment) {
      throw new Error('预约单不存在，请检查预约单号是否正确');
    }
    actualAppointmentId = appointment.id;
  }

  // Generate unique order number
  let orderNo;
  let exists = true;
  while (exists) {
    orderNo = generateOrderNo();
    const existingOrder = await PaymentOrder.findOne({ where: { orderNo } });
    exists = !!existingOrder;
  }

  // Calculate total amount for commission (use RMB if available)
  const totalAmountForCommission = rmbAmount > 0 ? rmbAmount : legacyAmount;

  // Create payment order
  const paymentOrder = await PaymentOrder.create({
    orderNo,
    userId: actualUserId,
    appointmentId: actualAppointmentId,
    amount: legacyAmount > 0 ? legacyAmount : null, // Legacy field
    amountPeso: pesoAmount > 0 ? pesoAmount : null,
    amountRmb: rmbAmount > 0 ? rmbAmount : null,
    serviceContent,
    paymentTime: new Date(paymentTime),
    notes: notes || null,
    createdBy: adminId,
    status: 'active',
  });

  // Calculate commission (if applicable, based on RMB amount)
  let commission = null;
  if (totalAmountForCommission > 0) {
    try {
      commission = await commissionService.calculateCommission(paymentOrder.id);
    } catch (error) {
      // Log error but don't fail the order creation
      console.error('Commission calculation error:', error.message);
    }
  }

  return {
    paymentOrder: {
      id: paymentOrder.id,
      orderNo: paymentOrder.orderNo,
      userId: paymentOrder.userId,
      appointmentId: paymentOrder.appointmentId,
      amount: paymentOrder.amount ? parseFloat(paymentOrder.amount).toFixed(2) : null,
      amountPeso: paymentOrder.amountPeso ? parseFloat(paymentOrder.amountPeso).toFixed(2) : null,
      amountRmb: paymentOrder.amountRmb ? parseFloat(paymentOrder.amountRmb).toFixed(2) : null,
      serviceContent: paymentOrder.serviceContent,
      paymentTime: paymentOrder.paymentTime,
      notes: paymentOrder.notes,
      status: paymentOrder.status,
      createdAt: paymentOrder.createdAt,
    },
    commission: commission ? {
      id: commission.id,
      inviterId: commission.inviterId,
      commissionAmount: parseFloat(commission.commissionAmount).toFixed(2),
      commissionRate: `${(parseFloat(commission.commissionRate) * 100).toFixed(2)}%`,
    } : null,
  };
};

/**
 * Get payment orders with filters
 * @param {Object} options - Query options
 * @returns {Object} Payment orders with pagination and statistics
 */
const getPaymentOrders = async (options = {}) => {
  const { page = 1, limit = 20, userId, status, startDate, endDate, search, currency } = options;
  const offset = (page - 1) * limit;
  const Op = require('sequelize').Op;

  const where = {};
  if (userId) where.userId = userId;
  if (status) where.status = status;
  
  // Currency filter: 'rmb' → amountRmb > 0, 'peso' → amountPeso > 0
  // Invalid currency values are ignored (treated as no filter)
  if (currency === 'rmb') {
    where.amountRmb = { [Op.gt]: 0 };
  } else if (currency === 'peso') {
    where.amountPeso = { [Op.gt]: 0 };
  }
  
  if (startDate || endDate) {
    where.paymentTime = {};
    if (startDate) where.paymentTime[Op.gte] = new Date(startDate);
    if (endDate) where.paymentTime[Op.lte] = new Date(endDate);
  }

  if (search) {
    where[Op.or] = [
      { orderNo: { [Op.like]: `%${search}%` } },
      { serviceContent: { [Op.like]: `%${search}%` } },
    ];
  }

  // Execute both queries in parallel: orders list and statistics
  const [ordersResult, statisticsResult] = await Promise.all([
    // Query for paginated orders
    PaymentOrder.findAndCountAll({
      where,
      include: [
        {
          model: User,
          as: 'user',
          attributes: ['id', 'uid', 'nickname', 'phone'],
        },
        {
          model: Appointment,
          as: 'appointment',
          attributes: ['id', 'appointmentNo'],
          required: false,
        },
        {
          model: Admin,
          as: 'creator',
          attributes: ['id', 'username', 'email'],
        },
      ],
      order: [['createdAt', 'DESC']],
      limit: parseInt(limit),
      offset: parseInt(offset),
    }),
    // Query for amount statistics (sum of all matching orders, not just current page)
    PaymentOrder.findOne({
      where,
      attributes: [
        [sequelize.fn('COALESCE', sequelize.fn('SUM', sequelize.col('amount_rmb')), 0), 'totalRmb'],
        [sequelize.fn('COALESCE', sequelize.fn('SUM', sequelize.col('amount_peso')), 0), 'totalPeso'],
      ],
      raw: true,
    }),
  ]);

  const { count, rows } = ordersResult;

  // Format statistics with two decimal places
  const statistics = {
    totalRmb: parseFloat(statisticsResult?.totalRmb || 0).toFixed(2),
    totalPeso: parseFloat(statisticsResult?.totalPeso || 0).toFixed(2),
  };

  // Get commission status for each order
  const Commission = require('../models/Commission');
  const orderIds = rows.map(o => o.id);
  const commissions = await Commission.findAll({
    where: { paymentOrderId: orderIds },
    attributes: ['paymentOrderId', 'commissionAmount', 'status'],
  });
  const commissionMap = {};
  commissions.forEach(c => {
    commissionMap[c.paymentOrderId] = {
      amount: parseFloat(c.commissionAmount).toFixed(2),
      status: c.status,
    };
  });

  const records = rows.map(order => ({
    id: order.id,
    orderNo: order.orderNo,
    user: order.user,
    appointment: order.appointment,
    amount: order.amount ? parseFloat(order.amount).toFixed(2) : null,
    amountPeso: order.amountPeso ? parseFloat(order.amountPeso).toFixed(2) : null,
    amountRmb: order.amountRmb ? parseFloat(order.amountRmb).toFixed(2) : null,
    serviceContent: order.serviceContent,
    paymentTime: order.paymentTime,
    notes: order.notes,
    status: order.status,
    creator: order.creator,
    commission: commissionMap[order.id] || null,
    createdAt: order.createdAt,
  }));

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

/**
 * Get payment order by ID
 * @param {string} orderId - Payment order ID
 * @returns {Object} Payment order details
 */
const getPaymentOrderById = async (orderId) => {
  const order = await PaymentOrder.findByPk(orderId, {
    include: [
      {
        model: User,
        as: 'user',
        attributes: ['id', 'uid', 'nickname', 'phone', 'invitedBy'],
      },
      {
        model: Appointment,
        as: 'appointment',
        required: false,
      },
      {
        model: Admin,
        as: 'creator',
        attributes: ['id', 'username', 'email'],
      },
    ],
  });

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

  // Get commission info
  const Commission = require('../models/Commission');
  const commission = await Commission.findOne({
    where: { paymentOrderId: orderId },
    include: [
      {
        model: User,
        as: 'inviter',
        attributes: ['id', 'uid', 'nickname'],
      },
    ],
  });

  return {
    id: order.id,
    orderNo: order.orderNo,
    user: order.user,
    appointment: order.appointment,
    amount: order.amount ? parseFloat(order.amount).toFixed(2) : null,
    amountPeso: order.amountPeso ? parseFloat(order.amountPeso).toFixed(2) : null,
    amountRmb: order.amountRmb ? parseFloat(order.amountRmb).toFixed(2) : null,
    serviceContent: order.serviceContent,
    paymentTime: order.paymentTime,
    notes: order.notes,
    status: order.status,
    cancelReason: order.cancelReason,
    creator: order.creator,
    commission: commission ? {
      id: commission.id,
      inviter: commission.inviter,
      commissionAmount: parseFloat(commission.commissionAmount).toFixed(2),
      commissionRate: `${(parseFloat(commission.commissionRate) * 100).toFixed(2)}%`,
      status: commission.status,
      createdAt: commission.createdAt,
    } : null,
    createdAt: order.createdAt,
    updatedAt: order.updatedAt,
  };
};

/**
 * Cancel payment order
 * @param {string} orderId - Payment order ID
 * @param {string} cancelReason - Reason for cancellation
 * @returns {Object} Cancelled payment order
 */
const cancelPaymentOrder = async (orderId, cancelReason) => {
  const transaction = await sequelize.transaction();

  try {
    const order = await PaymentOrder.findByPk(orderId, { transaction });

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

    if (order.status === 'cancelled') {
      throw new Error('Payment order is already cancelled');
    }

    if (!cancelReason || !cancelReason.trim()) {
      throw new Error('请输入取消原因');
    }

    // Cancel the order
    order.status = 'cancelled';
    order.cancelReason = cancelReason.trim();
    await order.save({ transaction });

    // Cancel related commission and revert balance
    const Commission = require('../models/Commission');
    const commission = await Commission.findOne({
      where: { paymentOrderId: orderId, status: 'credited' },
      transaction,
    });

    if (commission) {
      // Revert inviter's balance
      const inviter = await User.findByPk(commission.inviterId, { transaction });
      if (inviter) {
        inviter.balance = parseFloat(inviter.balance) - parseFloat(commission.commissionAmount);
        if (inviter.balance < 0) inviter.balance = 0;
        await inviter.save({ transaction });
      }

      // Cancel commission
      commission.status = 'cancelled';
      await commission.save({ transaction });
    }

    await transaction.commit();

    return {
      id: order.id,
      orderNo: order.orderNo,
      status: order.status,
      cancelReason: order.cancelReason,
      commissionCancelled: !!commission,
    };
  } catch (error) {
    await transaction.rollback();
    throw error;
  }
};

module.exports = {
  createPaymentOrder,
  getPaymentOrders,
  getPaymentOrderById,
  cancelPaymentOrder,
  generateOrderNo,
};
