package com.jeequan.jeepay.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.model.applyment.PaywayFee;
import com.jeequan.jeepay.core.model.mchconfig.MchDivisionConfig;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.db.entity.PayOrder;
import com.jeequan.jeepay.db.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.db.entity.PayOrderDivisionRefundRecord;
import com.jeequan.jeepay.db.entity.RefundOrder;
import com.jeequan.jeepay.service.mapper.PayOrderDivisionRecordMapper;
import com.jeequan.jeepay.service.mapper.PayOrderDivisionRefundRecordMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * <p>
 * 支付订单分账退款记录表 服务实现类
 * </p>
 *
 * @author [mybatis plus generator]
 * @since 2022-06-09
 */
@Service
public class PayOrderDivisionRefundRecordService extends ServiceImpl<PayOrderDivisionRefundRecordMapper, PayOrderDivisionRefundRecord> {

    @Autowired private PayOrderDivisionRecordMapper payOrderDivisionRecordMapper;
    @Autowired
    private OrderProfitSettRecordService orderProfitSettRecordService;

    public IPage<PayOrderDivisionRefundRecord> listByPage(IPage iPage, PayOrderDivisionRefundRecord queryObject) {

        LambdaQueryWrapper<PayOrderDivisionRefundRecord> condition = PayOrderDivisionRefundRecord.gw();
        if (StringUtils.isNotEmpty(queryObject.getMchNo())) {
            condition.eq(PayOrderDivisionRefundRecord::getMchNo, queryObject.getMchNo());
        }

        condition.eq(queryObject.getDivisionRecordId() != null, PayOrderDivisionRefundRecord::getDivisionRecordId, queryObject.getDivisionRecordId());
        condition.eq(StringUtils.isNotEmpty(queryObject.getPayOrderRefundOrderId()), PayOrderDivisionRefundRecord::getPayOrderRefundOrderId, queryObject.getPayOrderRefundOrderId());

        if(queryObject.getReceiverId() != null){
            condition.eq(PayOrderDivisionRefundRecord::getReceiverId, queryObject.getReceiverId());
        }

        if(queryObject.getTaskId() != null){
            condition.eq(PayOrderDivisionRefundRecord::getTaskId, queryObject.getTaskId());
        }

        if(StringUtils.isNotEmpty(queryObject.getAppId())){
            condition.like(PayOrderDivisionRefundRecord::getAppId, queryObject.getAppId());
        }

        if(queryObject.getState() != null){
            condition.eq(PayOrderDivisionRefundRecord::getState, queryObject.getState());
        }

        if(StringUtils.isNotEmpty(queryObject.getPayOrderId())){
            condition.eq(PayOrderDivisionRefundRecord::getPayOrderId, queryObject.getPayOrderId());
        }

        if(StringUtils.isNotEmpty(queryObject.getAccNo())){
            condition.eq(PayOrderDivisionRefundRecord::getAccNo, queryObject.getAccNo());
        }

        // 时间范围条件
        Date[] dateRange = queryObject.buildQueryDateRange();
        if (dateRange[0] != null) {
            condition.ge(PayOrderDivisionRefundRecord::getCreatedAt, dateRange[0]);
        }
        if (dateRange[1] != null) {
            condition.le(PayOrderDivisionRefundRecord::getCreatedAt, dateRange[1]);
        }

        condition.orderByDesc(PayOrderDivisionRefundRecord::getCreatedAt); //时间倒序

        return page(iPage, condition);

    }


    /** 更新退款单状态  and  记录状态 **/
    @Transactional
    public void updateRefundRecordAndDivisionRecord(PayOrderDivisionRefundRecord updateRecord, Long divisionRecordId, Long refundAmount){

        // 更新退款表
        updateById(updateRecord);

        // 支付成功后， 更新主表
        if(updateRecord.getState() == PayOrderDivisionRefundRecord.STATE_SUCCESS){
            payOrderDivisionRecordMapper.updateRefundAmountAndCount(divisionRecordId, refundAmount);
        }
    }


    /**
     * 生成分账退回记录
     * <p>
     * 业务操作是否入库：
     * 不入库：  一般用作： 订单退款时，查询退分金额， 比如直付通需要再退款时调用退分明细。
     * 入库： 一般是事后退分， 计算退分金额的时候
     **/
    public PayOrderDivisionRefundRecord genRecord(PayOrderDivisionRecord record, RefundOrder refundOrder, PayOrder refundBeforePayOrder) {

        // --  重新计算分账金额  --
        // 计算基数： 支付订单金额 -  已成功退款金额 - 本次退款金额
        Long calBaseAmount = refundBeforePayOrder.getAmount() - refundBeforePayOrder.getRefundAmount() - refundOrder.getRefundAmount();

        // 避免基数小于 0
        if (calBaseAmount < 0) {
            calBaseAmount = 0L;
        }

        PaywayFee paywayFee = orderProfitSettRecordService.findByPayOrderMchProfit(refundBeforePayOrder);
        MutablePair<String, Long> feeAndSnapshot = paywayFee.calFeeAndSnapshot(calBaseAmount);

        // 商户手续费
        Long mchFee = feeAndSnapshot.right;

        // 如果分账金额订单是基于： 订单金额， 那么不应该再减去手续费了。
        if (MchDivisionConfig.CAL_BASE_AMOUNT_TYPE_ORDER_AMOUNT.equals(record.getCalBaseAmountType())) {
            mchFee = 0L;
        }

        // （ （ 支付订单金额 -  已成功退款金额 - 本次退款金额 ） - 商户手续费  ） X 分账比例
        Long calDivisionAmount = AmountUtil.calPercentageFee((calBaseAmount - mchFee), record.getDivisionProfit());

        // 本次退款金额 = 已分账金额 - 已退分金额 - 重新计算的分账金额。
        Long divisionRefundAmount = record.getCalDivisionAmount() - record.getRefundAmount() - calDivisionAmount;

        // 第一次退款失败， 可以发起第二次。  此时 已分账金额 - 已退分金额 可能为 0， 避免出现负数。
        if (divisionRefundAmount < 0) {
            divisionRefundAmount = 0L;
        }

        PayOrderDivisionRefundRecord refundRecord = new PayOrderDivisionRefundRecord();
        refundRecord.setDivisionRefundId(SeqKit.genRefundOrderId()); // 分账退款订单号（支付系统生成订单号）
        refundRecord.setMchNo(record.getMchNo()); // 商户号
        refundRecord.setIsvNo(record.getIsvNo()); // 服务商号
        refundRecord.setAppId(record.getAppId()); // 应用ID
        refundRecord.setMchName(record.getMchName()); // 商户名称
        refundRecord.setMchType(record.getMchType()); // 类型: 1-普通商户, 2-特约商户(服务商模式)',
        refundRecord.setIfCode(record.getIfCode()); // 支付接口代码
        refundRecord.setPayOrderId(record.getPayOrderId()); // 系统支付订单号
        refundRecord.setPayOrderChannelOrderNo(record.getPayOrderChannelOrderNo()); // 支付订单渠道订单号
        refundRecord.setPayOrderAmount(record.getPayOrderAmount()); // 订单支付金额
        refundRecord.setPayOrderRefundOrderId(refundOrder.getRefundOrderId()); // 支付订单退款订单号
        refundRecord.setPayOrderRefundAmount(refundOrder.getRefundAmount()); // 支付订单退款发生金额, 单位：分
        refundRecord.setDivisionRecordId(record.getRecordId()); // 分账记录ID
        refundRecord.setDivisionBatchOrderId(record.getBatchOrderId()); // 系统分账批次号
        refundRecord.setReceiverId(record.getReceiverId()); // 账号快照》 分账接收者ID
        refundRecord.setTaskId(record.getTaskId()); // 账号快照》 分账任务ID
        refundRecord.setReceiverAlias(record.getReceiverAlias()); // 接收者账号别名
        refundRecord.setAccType(record.getAccType()); // 账号快照》 分账接收账号类型: 0-个人 1-商户
        refundRecord.setAccNo(record.getAccNo()); // 账号快照》 分账接收账号
        refundRecord.setAccName(record.getAccName()); // 账号快照》 分账接收账号名称
        refundRecord.setChannelAccNo(record.getChannelAccNo()); // 账号快照》 渠道分账接收账号（账号创建完成后渠道侧账号）
        refundRecord.setRelationType(record.getRelationType()); // 账号快照》 分账关系类型（参考微信）， 如： SERVICE_PROVIDER 服务商等
        refundRecord.setRelationTypeName(record.getRelationTypeName()); // 账号快照》 当选择自定义时，需要录入该字段。 否则为对应的名称
        refundRecord.setDivisionAmount(record.getCalDivisionAmount()); // 分账金额,单位分
        refundRecord.setDivisionProfit(record.getDivisionProfit()); // 账号快照》 配置的实际分账比例
        refundRecord.setDivisionRefundAmount(divisionRefundAmount); // 分账退款金额,单位分

        refundRecord.setState(PayOrderDivisionRefundRecord.STATE_ING); // 状态: 0-退款中 1-退款成功 2-退款失败

        return refundRecord;
    }

}
