package com.xxfc.platform.order.biz;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.github.wxiaoqi.security.admin.feign.UserFeign;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.github.wxiaoqi.security.common.util.IntervalUtil;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.xxfc.platform.order.biz.inner.OrderMsgBiz;
import com.xxfc.platform.order.contant.enumerate.*;
import com.xxfc.platform.order.entity.*;
import com.xxfc.platform.order.pojo.DedDetailDTO;
import com.xxfc.platform.order.pojo.mq.OrderMQDTO;
import com.xxfc.platform.universal.constant.DictionaryKey;
import com.xxfc.platform.universal.entity.Dictionary;
import com.xxfc.platform.universal.feign.ThirdFeign;
import com.xxfc.platform.universal.vo.OrderRefundVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.jexl2.MapContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xxfc.platform.order.mapper.OrderRefundMapper;
import com.github.wxiaoqi.security.common.biz.BaseBiz;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.github.wxiaoqi.security.common.constant.CommonConstants.SYS_FALSE;
import static com.github.wxiaoqi.security.common.constant.CommonConstants.SYS_TRUE;
import static com.xxfc.platform.universal.constant.DictionaryKey.APP_ORDER;

/**
 * 订单退款记录表
 *
 * @author zjw
 * @email nishijjo@qq.com
 * @date 2019-06-18 11:08:09
 */
@Service
@Slf4j
public class OrderRefundBiz extends BaseBiz<OrderRefundMapper,OrderRefund> {
    @Autowired
    ThirdFeign thirdFeign;

    @Autowired
    BaseOrderBiz baseOrderBiz;

    @Autowired
    OrderRentVehicleBiz orderRentVehicleBiz;

    @Autowired
    OrderVehicleCrosstownBiz crosstownBiz;

    @Autowired
    OrderViolationBiz orderViolationBiz;

    @Autowired
    OrderMsgBiz orderMsgBiz;

    @Autowired
    UserFeign userFeign;

    @Autowired
    OrderDepositRefundRecordBiz orderDepositRefundRecordBiz;

    /**
     * 退还部分押金
     * @param orderMQDTO
     */
    public void refundPartDeposit(OrderMQDTO orderMQDTO){
        Map<String, Dictionary> dictionaryMap = thirdFeign.dictionaryGetAll4Map().getData();
        BigDecimal illegalReserve = new BigDecimal(dictionaryMap.get(APP_ORDER+ "_"+ DictionaryKey.ILLEGAL_RESERVE).getDetail());

        //未退还， 进行挂起保留违章预备金 的退还
        if(RefundStatusEnum.NONE.getCode().equals(orderMQDTO.getRefundStatus())) {
            Integer crosstownTypeEnum;
            Integer depositRefundRecordStatus;
            //判断是否定损过
            if(SYS_TRUE.equals(orderMQDTO.getOrderRentVehicleDetail().getFixedLossStatus())) {
                crosstownTypeEnum = CrosstownTypeEnum.FIXED_LOSS.getCode();
                depositRefundRecordStatus = DepositRefundStatus.FIXLOSSREFUND.getCode();
            }else {
                crosstownTypeEnum = CrosstownTypeEnum.ARRIVE.getCode();
                depositRefundRecordStatus = DepositRefundStatus.REFUNDARRIVAL.getCode();
            }
            OrderVehicleCrosstown crosstown = crosstownBiz.selectOne(new OrderVehicleCrosstown(){{
                setOrderId(orderMQDTO.getId());
                setType(crosstownTypeEnum);
            }});

            if(null == crosstown) {
                throw new BaseException(ResultCode.PARAM_ILLEGAL_CODE, new HashSet<String>(){{
                    add("退款第一部分押金失败，获取不了还车/定损记录，订单号："+ orderMQDTO.getId());
                }});
            }
            //还车扣除款 剩余的 钱，再减去违章预备金
            BigDecimal refundAmont = crosstown.getRestDeposit().subtract(illegalReserve);
            BigDecimal originalRefundAmount = crosstown.getRestDeposit().add(crosstown.getDeductionCost()).subtract(illegalReserve);
            List<DedDetailDTO> dddList = JSONUtil.toBean(crosstown.getDedDetail(), List.class);
            String refundDesc = "退还押金："+ refundAmont.toString()+ "(已扣除 违章预备金："+ illegalReserve.toString();
            for(DedDetailDTO ddd : dddList) {
                refundDesc += ", "+ ddd.getDeductions()+ ":"+ ddd.getCost();
            }
            refundDesc += ")";
            refundTrigger(orderMQDTO, orderMQDTO.getOrderRentVehicleDetail(), illegalReserve, originalRefundAmount, refundAmont, refundDesc, RefundStatusEnum.RESIDUE_ILLEGAL.getCode(), RefundTypeEnum.PART_DEPOSIT);

            DepositRefundRecord depositRefundRecord = orderDepositRefundRecordBiz.findByCrossIdAndStatus(crosstown.getId(), depositRefundRecordStatus);
            depositRefundRecord.setIscomplete(Boolean.TRUE);
            orderDepositRefundRecordBiz.updateSelectiveById(depositRefundRecord);

            orderMsgBiz.handelMsgDeposit(orderMQDTO.getOrderRentVehicleDetail(), orderMQDTO, userFeign.userDetailById(orderMQDTO.getUserId()).getData());
        }
//        else {
//            //还车扣除款 剩余的 钱，再减去违章预备金
//            BigDecimal originalRefundAmount = orderMQDTO.getOrderRentVehicleDetail().getReturnPayResidue();
//            BigDecimal refundAmont = originalRefundAmount;
//            String refundDesc = "退还剩余违章保证金："+ refundAmont.toString();
//
//            //已退还部分， 进行剩余的保留违章预备金 的退还
//                //获取违章记录
//            List<OrderViolation> orderViolations = orderViolationBiz.selectList(new OrderViolation(){{
//                setDetailId(orderMQDTO.getOrderRentVehicleDetail().getId());
//            }});
//
//            if(orderViolations.size() > 0) {
//                refundDesc += "(已扣除 违章金额："+ illegalReserve.toString();
//                for(OrderViolation ov : orderViolations) {
//                    refundDesc += ", "+ ov.getPrice();
//                    refundAmont = refundAmont.subtract(ov.getPrice());
//                }
//                refundDesc += ")";
//                refundTrigger(orderMQDTO, orderMQDTO.getOrderRentVehicleDetail(), illegalReserve, originalRefundAmount, refundAmont, refundDesc, RefundStatusEnum.REFUND_DEPOSIT.getCode(), RefundTypeEnum.RESIDUE_DEPOSIT);
//            }
//        }
    }

    public void refundTrigger(BaseOrder baseOrder, OrderRentVehicleDetail orvd, BigDecimal residueAmount, BigDecimal originalRefundAmount, BigDecimal refundAmont, String refundDesc, Integer refundStatus, RefundTypeEnum refundTypeEnum) {
        //退款子流程: 订单基础，退款描述，退款金额
        refundSubProcess(baseOrder, refundDesc, originalRefundAmount, refundAmont, refundTypeEnum.getCode(), refundStatus);
        //设置剩余没有返还的钱
        orderRentVehicleBiz.updateSelectiveById(new OrderRentVehicleDetail(){{
            setId(orvd.getId());
            setReturnPayResidue(residueAmount);
        }});
    }

    /**
     * 租车退款流程(不含押金的通用方法)
     * @param baseOrder
     * @param startTime
     * @param dicParentKey
     */
    public void rentRefundProcess(BaseOrder baseOrder, Long startTime, String dicParentKey){
        rentRefundProcess(baseOrder, BigDecimal.ZERO, startTime, dicParentKey);
    }

    /**
     * 租车（包括旅游）退款流程(含押金)
     * @param baseOrder
     * @param depositAmount
     * @param timeLag 与开始时间的时间差
     * @param dicParentKey
     */
    public void rentRefundProcess(BaseOrder baseOrder, BigDecimal depositAmount, Long timeLag, String dicParentKey) {
        //计算退款金额
        // 1、押金 + 租金(规则扣除)
        BigDecimal originalRefundAmount = BigDecimal.ZERO.add(baseOrder.getGoodsAmount().subtract(baseOrder.getCouponAmount()));
        StringBuilder refundDescBuilder = new StringBuilder("取消订单退款:");
        if(null == depositAmount) {
            depositAmount = BigDecimal.ZERO;
        }else {
            //触发押金退款
            refundSubProcess(baseOrder, refundDescBuilder.toString(), depositAmount, depositAmount, RefundTypeEnum.DEPOSIT.getCode(), RefundStatusEnum.ALL.getCode());
        }
        //商品价格 - 优惠券减免的价格
        BigDecimal refundGoodsAmount = calculateRefund(originalRefundAmount, timeLag, dicParentKey, refundDescBuilder);
        refundGoodsAmount = refundGoodsAmount.setScale(2, RoundingMode.HALF_UP);

        //退款金额
//        BigDecimal refundAmount = depositAmount.add(refundGoodsAmount);
//        originalRefundAmount = depositAmount.add(originalRefundAmount);
        BigDecimal refundAmount = refundGoodsAmount;

        //退款子流程: 订单基础，退款描述，退款金额
        refundSubProcess(baseOrder, refundDescBuilder.toString(), originalRefundAmount, refundAmount, RefundTypeEnum.ORDER_FUND.getCode(), RefundStatusEnum.ALL.getCode());
    }

    public BigDecimal calculateRefund(BigDecimal goodsAmount, Long timeLag, String dicParentKey, StringBuilder refundDescBuilder) {
        BigDecimal refundGoodsAmount = goodsAmount;

        //根据时间处理goodsAmount
        //获取出发时间 到现在 距离时间
        Integer hourLag = Long.valueOf(timeLag/(1000L * 60L * 60L)).intValue();

        Map<String, Dictionary> dictionaryMap = thirdFeign.dictionaryGetAll4Map().getData();
        Set<Dictionary> rentRefunds = dictionaryMap.get(dicParentKey).getChildrens();

        for(com.xxfc.platform.universal.entity.Dictionary dic : rentRefunds) {
            if(StrUtil.isBlank(dic.getName())) {
                continue;
            }
            String[] names = dic.getName().split("\\|");
            if(names.length < 2) {
                continue;
            }

            //符合范围
            if(IntervalUtil.staticIsInTheInterval(hourLag.toString(), names[0])){
                refundGoodsAmount = new BigDecimal((IntervalUtil.evaluate(dic.getDetail(), new MapContext(){{
                    //ga : goodsAmount
                    set("ga", goodsAmount);
                }})).toString());
                refundDescBuilder = refundDescBuilder.insert(0, names[1]+ ",");
                break;
            }
        }

        return refundGoodsAmount;
    }

    /**
     * 退款子流程
     * @param baseOrder
     * @param refundDesc
     * @param refundAmount
     * @param refundType
     * @param refundStatus
     */
    public void refundSubProcess(BaseOrder baseOrder, String refundDesc, BigDecimal originalRefundAmount, BigDecimal refundAmount, Integer refundType, Integer refundStatus) {
        String refundTradeNo = null;
        //0 小于 退款金额
        if(BigDecimal.ZERO.compareTo(refundAmount) < 0) {
            OrderRefundVo orv = new OrderRefundVo();
            orv.setAmount(baseOrder.getRealAmount().multiply(new BigDecimal("100")).intValue());
            orv.setOrderNo(baseOrder.getNo());
            orv.setRefundDesc(refundDesc+ refundAmount.toString());
            orv.setRefundAmount(refundAmount.multiply(new BigDecimal("100")).intValue());
            ObjectRestResponse<String> result = thirdFeign.refund(orv);
            refundTradeNo = result.getData();
            if(null == refundTradeNo) {
                log.error("退款没有refundTradeNo，订单号为："+ baseOrder.getNo()+ ", 微服务调用结果为"+ JSONUtil.toJsonStr(result));
            }
        }

        //记录订单退款记录
        Integer flag = addOrderRefund(baseOrder.getId(), refundDesc, originalRefundAmount, refundAmount, refundTradeNo, refundType);

        //更新订单的退款状态和退款时间
        BaseOrder updateBaseOrder = new BaseOrder();
        updateBaseOrder.setId(baseOrder.getId());
        updateBaseOrder.setRefundStatus(refundStatus);
        updateBaseOrder.setRefundTime(System.currentTimeMillis());
        updateBaseOrder.setVersion(baseOrder.getVersion());
        if(SYS_TRUE.equals(flag) && null != refundStatus) {
            BeanUtil.copyProperties(baseOrderBiz.updateSelectiveByIdReT(updateBaseOrder), baseOrder);
        }
    }

    /**
     * 记录订单退款记录
     * @param orderId
     * @param refundDesc
     * @param refundAmount
     * @param refundTradeNo
     */
    private Integer addOrderRefund(Integer orderId, String refundDesc, BigDecimal originalRefundAmount, BigDecimal refundAmount, String refundTradeNo, Integer refundType) {
        //如果返回的流水为空，则当做失败
        Integer refundStatus = SYS_TRUE;
        if(StrUtil.isBlank(refundTradeNo)) {
            refundStatus = SYS_FALSE;
        }

        //创建订单退款记录
        OrderRefund orderRefund = new OrderRefund(){{
            setOrderId(orderId);
            setRefundTime(System.currentTimeMillis());
            setTradeNo(refundTradeNo);
            setRefundType(RefundTypeEnum.ORDER_FUND.getCode());
        }};
        orderRefund.setOriginalRefundAmount(originalRefundAmount);
        orderRefund.setDeductAmount(originalRefundAmount.subtract(refundAmount));
        orderRefund.setRefundAmount(refundAmount);
        orderRefund.setRefundDesc(refundDesc);
        orderRefund.setRefundStatus(refundStatus);
        orderRefund.setRefundType(refundType);
        insertSelective(orderRefund);

        return refundStatus;
    }
}