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

/**
 * Withdrawal Service
 * Handles withdrawal requests and processing
 */

// Minimum withdrawal amount (configurable) - default 1 yuan
const MIN_WITHDRAWAL_AMOUNT = parseFloat(process.env.MIN_WITHDRAWAL_AMOUNT || '1.00');

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

/**
 * Create withdrawal request
 * @param {string} userId - User ID
 * @param {Object} withdrawalData - Withdrawal data
 * @returns {Object} Created withdrawal
 */
const createWithdrawal = async (userId, withdrawalData) => {
  const { amount, paymentMethod, paymentDetails } = withdrawalData;

  // Validate amount
  const withdrawalAmount = parseFloat(amount);
  if (isNaN(withdrawalAmount) || withdrawalAmount <= 0) {
    throw new Error('Invalid withdrawal amount');
  }

  // Check minimum amount
  if (withdrawalAmount < MIN_WITHDRAWAL_AMOUNT) {
    throw new Error(`Minimum withdrawal amount is ${MIN_WITHDRAWAL_AMOUNT}`);
  }

  // Validate payment method
  const validMethods = ['wechat', 'alipay', 'bank'];
  if (!validMethods.includes(paymentMethod)) {
    throw new Error('Invalid payment method');
  }

  // Validate payment details
  if (!paymentDetails || typeof paymentDetails !== 'object' || Array.isArray(paymentDetails)) {
    throw new Error('Payment details are required');
  }

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

  try {
    // Get user with lock
    const user = await User.findByPk(userId, {
      transaction,
      lock: transaction.LOCK.UPDATE,
    });

    if (!user) {
      throw new Error('User not found');
    }

    // Check if user has sufficient balance
    const userBalance = parseFloat(user.balance);
    if (userBalance < withdrawalAmount) {
      throw new Error('Insufficient balance');
    }

    // Generate unique withdrawal number
    let withdrawalNo;
    let exists = true;
    
    while (exists) {
      withdrawalNo = generateWithdrawalNo();
      const existingWithdrawal = await Withdrawal.findOne({
        where: { withdrawalNo },
        transaction,
      });
      exists = !!existingWithdrawal;
    }

    // Create withdrawal record
    const withdrawal = await Withdrawal.create({
      userId,
      withdrawalNo,
      amount: withdrawalAmount,
      paymentMethod,
      paymentDetails,
      status: 'waiting',
    }, { transaction });

    await transaction.commit();

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

/**
 * Get withdrawal records for user
 * @param {string} userId - User ID
 * @param {Object} options - Query options (page, limit, status)
 * @returns {Object} Withdrawal records with pagination
 */
const getWithdrawals = async (userId, options = {}) => {
  const { page = 1, limit = 20, status } = options;
  const offset = (page - 1) * limit;

  const user = await User.findByPk(userId);
  
  if (!user) {
    throw new Error('User not found');
  }

  // Build query conditions
  const where = { userId };
  if (status) {
    where.status = status;
  }

  // Get withdrawals with pagination
  const { count, rows } = await Withdrawal.findAndCountAll({
    where,
    order: [['createdAt', 'DESC']],
    limit: parseInt(limit),
    offset: parseInt(offset),
  });

  // Format records
  const records = rows.map(withdrawal => ({
    id: withdrawal.id,
    withdrawalNo: withdrawal.withdrawalNo,
    amount: parseFloat(withdrawal.amount).toFixed(2),
    paymentMethod: withdrawal.paymentMethod,
    paymentDetails: withdrawal.paymentDetails,
    status: withdrawal.status,
    reviewedAt: withdrawal.reviewedAt,
    rejectionReason: withdrawal.rejectionReason,
    completedAt: withdrawal.completedAt,
    createdAt: withdrawal.createdAt,
  }));

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

/**
 * Get withdrawal details by ID
 * @param {string} userId - User ID
 * @param {string} withdrawalId - Withdrawal ID
 * @returns {Object} Withdrawal details
 */
const getWithdrawalById = async (userId, withdrawalId) => {
  const withdrawal = await Withdrawal.findOne({
    where: {
      id: withdrawalId,
      userId,
    },
  });

  if (!withdrawal) {
    throw new Error('Withdrawal not found');
  }

  return {
    id: withdrawal.id,
    withdrawalNo: withdrawal.withdrawalNo,
    amount: parseFloat(withdrawal.amount).toFixed(2),
    paymentMethod: withdrawal.paymentMethod,
    paymentDetails: withdrawal.paymentDetails,
    status: withdrawal.status,
    reviewedAt: withdrawal.reviewedAt,
    rejectionReason: withdrawal.rejectionReason,
    completedAt: withdrawal.completedAt,
    createdAt: withdrawal.createdAt,
    updatedAt: withdrawal.updatedAt,
  };
};

module.exports = {
  createWithdrawal,
  getWithdrawals,
  getWithdrawalById,
  generateWithdrawalNo,
  MIN_WITHDRAWAL_AMOUNT,
};
