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

/**
 * Admin Withdrawal Service
 * Handles withdrawal management operations for admin panel
 */

/**
 * Get paginated withdrawal list with search and filters
 * @param {Object} options - Query options
 * @returns {Promise<Object>} Withdrawal list with pagination
 */
const getWithdrawalList = async (options = {}) => {
  const {
    page = 1,
    limit = 20,
    status = '',
    search = '',
    sortBy = 'createdAt',
    sortOrder = 'DESC',
  } = options;

  const offset = (page - 1) * limit;

  // Build where clause
  const where = {};

  // Filter by status
  if (status) {
    where.status = status;
  }

  // Search by withdrawal number or user info
  let userIds = [];
  if (search) {
    // Search for users matching the search term
    const users = await User.findAll({
      where: {
        [Op.or]: [
          { nickname: { [Op.like]: `%${search}%` } },
          { realName: { [Op.like]: `%${search}%` } },
          { phone: { [Op.like]: `%${search}%` } },
        ],
      },
      attributes: ['id'],
    });
    userIds = users.map(u => u.id);

    // Also search by withdrawal number
    where[Op.or] = [
      { withdrawalNo: { [Op.like]: `%${search}%` } },
      ...(userIds.length > 0 ? [{ userId: { [Op.in]: userIds } }] : []),
    ];
  }

  // Query withdrawals with user information
  const { count, rows: withdrawals } = await Withdrawal.findAndCountAll({
    where,
    limit: parseInt(limit),
    offset,
    order: [[sortBy, sortOrder]],
    include: [
      {
        model: User,
        as: 'user',
        attributes: ['id', 'nickname', 'realName', 'phone', 'whatsapp', 'wechatId'],
      },
    ],
  });

  // Format response
  const formattedWithdrawals = withdrawals.map(withdrawal => ({
    id: withdrawal.id,
    withdrawalNo: withdrawal.withdrawalNo,
    amount: parseFloat(withdrawal.amount).toFixed(2),
    paymentMethod: withdrawal.paymentMethod,
    paymentDetails: withdrawal.paymentDetails,
    status: withdrawal.status,
    reviewedBy: withdrawal.reviewedBy,
    reviewedAt: withdrawal.reviewedAt,
    rejectionReason: withdrawal.rejectionReason,
    completedAt: withdrawal.completedAt,
    createdAt: withdrawal.createdAt,
    updatedAt: withdrawal.updatedAt,
    user: withdrawal.user ? {
      id: withdrawal.user.id,
      nickname: withdrawal.user.nickname,
      realName: withdrawal.user.realName,
      phone: withdrawal.user.phone,
      whatsapp: withdrawal.user.whatsapp,
      wechatId: withdrawal.user.wechatId,
    } : null,
  }));

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

/**
 * Approve withdrawal request
 * @param {String} withdrawalId - Withdrawal ID
 * @param {String} adminId - Admin ID performing the action
 * @param {String} notes - Optional notes
 * @returns {Promise<Object>} Updated withdrawal
 */
const approveWithdrawal = async (withdrawalId, adminId, notes = '') => {
  const transaction = await sequelize.transaction();

  try {
    // Get withdrawal with lock
    const withdrawal = await Withdrawal.findByPk(withdrawalId, {
      transaction,
      lock: transaction.LOCK.UPDATE,
      include: [
        {
          model: User,
          as: 'user',
          attributes: ['id', 'balance'],
        },
      ],
    });

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

    // Check if withdrawal is in waiting status
    if (withdrawal.status !== 'waiting') {
      throw new Error(`Cannot approve withdrawal with status: ${withdrawal.status}`);
    }

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

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

    // Check if user has sufficient balance
    const withdrawalAmount = parseFloat(withdrawal.amount);
    const userBalance = parseFloat(user.balance);

    if (userBalance < withdrawalAmount) {
      throw new Error('User has insufficient balance');
    }

    // Update user balance
    const newBalance = userBalance - withdrawalAmount;
    await user.update({
      balance: newBalance,
    }, { transaction });

    // Update withdrawal status
    await withdrawal.update({
      status: 'completed',
      reviewedBy: adminId,
      reviewedAt: new Date(),
      completedAt: new Date(),
    }, { transaction });

    await transaction.commit();

    logger.info(`Withdrawal ${withdrawal.withdrawalNo} approved by admin ${adminId}`);

    return {
      id: withdrawal.id,
      withdrawalNo: withdrawal.withdrawalNo,
      amount: parseFloat(withdrawal.amount).toFixed(2),
      status: withdrawal.status,
      reviewedBy: withdrawal.reviewedBy,
      reviewedAt: withdrawal.reviewedAt,
      completedAt: withdrawal.completedAt,
      userBalance: newBalance.toFixed(2),
    };
  } catch (error) {
    await transaction.rollback();
    logger.error('Approve withdrawal error:', error);
    throw error;
  }
};

/**
 * Reject withdrawal request
 * @param {String} withdrawalId - Withdrawal ID
 * @param {String} adminId - Admin ID performing the action
 * @param {String} reason - Rejection reason (required)
 * @returns {Promise<Object>} Updated withdrawal
 */
const rejectWithdrawal = async (withdrawalId, adminId, reason) => {
  if (!reason || reason.trim() === '') {
    throw new Error('Rejection reason is required');
  }

  const transaction = await sequelize.transaction();

  try {
    // Get withdrawal with lock
    const withdrawal = await Withdrawal.findByPk(withdrawalId, {
      transaction,
      lock: transaction.LOCK.UPDATE,
    });

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

    // Check if withdrawal is in waiting status
    if (withdrawal.status !== 'waiting') {
      throw new Error(`Cannot reject withdrawal with status: ${withdrawal.status}`);
    }

    // Update withdrawal status
    await withdrawal.update({
      status: 'rejected',
      reviewedBy: adminId,
      reviewedAt: new Date(),
      rejectionReason: reason,
    }, { transaction });

    await transaction.commit();

    logger.info(`Withdrawal ${withdrawal.withdrawalNo} rejected by admin ${adminId}`);

    return {
      id: withdrawal.id,
      withdrawalNo: withdrawal.withdrawalNo,
      amount: parseFloat(withdrawal.amount).toFixed(2),
      status: withdrawal.status,
      reviewedBy: withdrawal.reviewedBy,
      reviewedAt: withdrawal.reviewedAt,
      rejectionReason: withdrawal.rejectionReason,
    };
  } catch (error) {
    await transaction.rollback();
    logger.error('Reject withdrawal error:', error);
    throw error;
  }
};

/**
 * Get withdrawal details
 * @param {String} withdrawalId - Withdrawal ID
 * @returns {Promise<Object>} Withdrawal details with user info
 */
const getWithdrawalDetails = async (withdrawalId) => {
  const withdrawal = await Withdrawal.findByPk(withdrawalId, {
    include: [
      {
        model: User,
        as: 'user',
        attributes: ['id', 'nickname', 'realName', 'phone', 'whatsapp', 'wechatId', 'balance'],
      },
    ],
  });

  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,
    reviewedBy: withdrawal.reviewedBy,
    reviewedAt: withdrawal.reviewedAt,
    rejectionReason: withdrawal.rejectionReason,
    completedAt: withdrawal.completedAt,
    createdAt: withdrawal.createdAt,
    updatedAt: withdrawal.updatedAt,
    user: withdrawal.user ? {
      id: withdrawal.user.id,
      nickname: withdrawal.user.nickname,
      realName: withdrawal.user.realName,
      phone: withdrawal.user.phone,
      whatsapp: withdrawal.user.whatsapp,
      wechatId: withdrawal.user.wechatId,
      balance: parseFloat(withdrawal.user.balance).toFixed(2),
    } : null,
  };
};

module.exports = {
  getWithdrawalList,
  approveWithdrawal,
  rejectWithdrawal,
  getWithdrawalDetails,
};
