package org.dromara.main.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.main.domain.MainBackOrder;
import org.dromara.main.domain.MainBackRecord;
import org.dromara.main.domain.MainOrder;
import org.dromara.main.domain.Payment;
import org.dromara.main.domain.Refund;
import org.dromara.main.domain.vo.RefundVo;
import org.dromara.main.mapper.MainBackOrderMapper;
import org.dromara.main.mapper.MainBackRecordMapper;
import org.dromara.main.mapper.MainOrderMapper;
import org.dromara.main.mapper.PaymentMapper;
import org.dromara.main.mapper.RefundMapper;
import org.dromara.main.service.ICompanyAccountService;
import org.dromara.main.service.IPaymentService;
import org.dromara.main.service.IRefundService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * 退款服务实现
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class RefundServiceImpl implements IRefundService {

    private static final int PAYMENT_METHOD_ALIPAY = 2;
    private static final int PAYMENT_METHOD_BALANCE = 3;

    private final RefundMapper refundMapper;
    private final MainOrderMapper mainOrderMapper;
    private final MainBackOrderMapper mainBackOrderMapper;
    private final MainBackRecordMapper mainBackRecordMapper;
    private final PaymentMapper paymentMapper;
    private final ICompanyAccountService companyAccountService;
    private final IPaymentService paymentService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createRefund(Long orderId, BigDecimal refundAmount, String refundReason, Long operatorId, String operatorName) {
        MainOrder order = mainOrderMapper.selectById(orderId);
        if (order == null) {
            throw new ServiceException("订单不存在");
        }
        if (order.getOrderType() == null || (order.getOrderType() != 3 && order.getOrderType() != 4)) {
            throw new ServiceException("仅支持背调订单退款");
        }
        if (order.getBusinessId() == null) {
            throw new ServiceException("背调订单不存在");
        }

        MainBackOrder backOrder = mainBackOrderMapper.selectById(order.getBusinessId());
        if (backOrder == null) {
            throw new ServiceException("背调订单不存在");
        }

        if (order.getPayStatus() == null || order.getPayStatus() != 2) {
            throw new ServiceException("订单未支付，无法退款");
        }
        if (order.getOrderStatus() != null && (order.getOrderStatus() == 4 || order.getOrderStatus() == 5)) {
            throw new ServiceException("订单已在退款流程中，无法重复退款");
        }
        if (order.getRefundAmount() != null && order.getRefundAmount().compareTo(BigDecimal.ZERO) > 0) {
            throw new ServiceException("订单已退款，不支持多次退款");
        }
        if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("退款金额必须大于0");
        }
        if (order.getPaidAmount() == null || refundAmount.compareTo(order.getPaidAmount()) > 0) {
            throw new ServiceException("退款金额不能大于已支付金额");
        }

        boolean fullRefund = refundAmount.compareTo(order.getPaidAmount()) == 0;
        int refundType = fullRefund ? 1 : 2;

        Payment payment = paymentMapper.selectOne(
            Wrappers.<Payment>lambdaQuery()
                .eq(Payment::getOrderId, order.getId())
                .orderByDesc(Payment::getCreateTime)
                .last("limit 1")
        );

        Integer paymentMethod = payment == null || payment.getPaymentMethod() == null
            ? PAYMENT_METHOD_BALANCE
            : payment.getPaymentMethod();

        Refund refund = new Refund();
        refund.setTenantId(order.getTenantId());
        refund.setRefundNo(generateRefundNo());
        refund.setPaymentId(payment == null ? null : payment.getId());
        refund.setOrderId(order.getId());
        refund.setOrderNo(order.getOrderNo());
        refund.setTradeNo(payment == null ? null : payment.getTradeNo());
        refund.setRefundAmount(refundAmount);
        refund.setRefundReason(refundReason);
        refund.setRefundType(refundType);
        refund.setPaymentMethod(paymentMethod);
        refund.setRefundStatus(0);
        refund.setOperatorId(operatorId);
        refund.setOperatorName(operatorName);
        refundMapper.insert(refund);

        try {
            if (paymentMethod == PAYMENT_METHOD_BALANCE) {
                companyAccountService.refundToAvailable(
                    order.getBuyerId(),
                    refundAmount,
                    order.getId(),
                    order.getOrderNo(),
                    refundReason
                );
            } else if (paymentMethod == PAYMENT_METHOD_ALIPAY) {
                if (payment == null || payment.getTradeNo() == null || payment.getTradeNo().isBlank()) {
                    throw new ServiceException("支付宝交易号不存在，无法退款");
                }
                boolean success = paymentService.alipayRefund(payment.getTradeNo(), refundAmount, refund.getRefundNo(), refundReason);
                if (!success) {
                    throw new ServiceException("支付宝退款失败");
                }
            } else {
                throw new ServiceException("不支持的支付方式：" + paymentMethod);
            }

            refund.setRefundStatus(1);
            refund.setRefundTime(new Date());
            refundMapper.updateById(refund);
        } catch (Exception e) {
            refund.setRefundStatus(2);
            refund.setFailReason(e.getMessage());
            refundMapper.updateById(refund);
            log.error("退款失败：orderId={}, error={}", order.getId(), e.getMessage(), e);
            throw new ServiceException("退款失败：{}", e.getMessage());
        }

        if (paymentMethod == PAYMENT_METHOD_BALANCE && !fullRefund) {
            BigDecimal remainingAmount = order.getPaidAmount().subtract(refundAmount);
            if (remainingAmount.compareTo(BigDecimal.ZERO) > 0) {
                companyAccountService.deductInUseBalance(
                    order.getBuyerId(),
                    remainingAmount,
                    order.getId(),
                    order.getOrderNo(),
                    "部分退款，扣除剩余金额"
                );
            }
        }

        order.setRefundAmount(refundAmount);
        order.setOrderStatus(fullRefund ? 4 : 2);
        if (fullRefund) {
            order.setCancelTime(new Date());
        } else {
            order.setCompleteTime(new Date());
        }
        mainOrderMapper.updateById(order);

        backOrder.setStatus(fullRefund ? "3" : "2");
        mainBackOrderMapper.updateById(backOrder);

        List<MainBackRecord> records = mainBackRecordMapper.selectList(
            Wrappers.<MainBackRecord>lambdaQuery()
                .eq(MainBackRecord::getOrderId, backOrder.getId())
        );
        for (MainBackRecord record : records) {
            if (!"已完成".equals(record.getStatus()) && !"完成".equals(record.getStatus())) {
                record.setStatus("已取消");
                mainBackRecordMapper.updateById(record);
            }
        }

        log.info("退款完成：orderId={}, refundNo={}, refundAmount={}, refundType={}",
            order.getId(), refund.getRefundNo(), refundAmount, fullRefund ? "全额" : "部分");
        return refund.getId();
    }

    @Override
    public List<RefundVo> queryByOrderId(Long orderId) {
        return refundMapper.selectVoList(
            Wrappers.<Refund>lambdaQuery()
                .eq(Refund::getOrderId, orderId)
                .orderByDesc(Refund::getCreateTime)
        );
    }

    @Override
    public RefundVo queryById(Long refundId) {
        return refundMapper.selectVoById(refundId);
    }

    private String generateRefundNo() {
        return "RF" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomNumbers(4);
    }
}
