package com.clx.performance.component;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.clx.order.enums.OrderEnum;
import com.clx.order.enums.UpdateEnum;
import com.clx.order.enums.VehicleUsageEnum;
import com.clx.order.feign.OrderFeign;
import com.clx.order.param.feign.RollbackOrderWeightParam;
import com.clx.order.vo.feign.FeignOrderInfoVO;
import com.clx.order.vo.feign.FeignOrderVO;
import com.clx.performance.dao.OrderChildDao;
import com.clx.performance.dao.OrderGoodsDao;
import com.clx.performance.dto.OrderCancelResult;
import com.clx.performance.enums.*;
import com.clx.performance.extranal.user.DriverService;
import com.clx.performance.extranal.user.OrderService;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.param.pc.OrderCancelParam;
import com.clx.performance.service.OrderChildLogService;
import com.clx.performance.service.OrderGoodsService;
import com.clx.performance.service.OrderGoodsTruckBindService;
import com.clx.performance.service.breakcontract.BreakContractSettlementOwnerService;
import com.clx.performance.service.child.OrderChildPostService;
import com.clx.user.enums.driver.DriverInfoEnum;
import com.msl.common.base.Optional;
import com.msl.common.exception.ServiceSystemException;
import com.msl.common.result.Result;
import com.msl.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

@Component
@Slf4j
public class OrderCancelComponent implements InitializingBean {

    @Autowired
    private OrderChildDao orderChildDao;

    @Autowired
    private OrderGoodsDao orderGoodsDao;

    @Autowired
    private OrderGoodsTruckBindService orderGoodsTruckBindService;

    @Autowired
    private GoodsOrderTruckRecordComponent goodsOrderTruckRecordComponent;

    @Autowired
    private OrderFeign orderFeign;

    @Autowired
    private DriverService driverService;

    @Autowired
    private BreakContractSettlementOwnerService breakContractSettlementOwnerService;

    @Autowired
    private OrderChildLogService orderChildLogService;

    @Autowired
    private OrderChildPostService orderChildPostService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private OrderGoodsService orderGoodsService;

    @Autowired
    private OwnerAccountComponent ownerAccountComponent;

    public static Map<Integer, String> statusCodeMap = new HashMap<>();


    public static Map<Integer, BiFunction<String, Integer, OrderCancelResult>> cancelTypeMap = new HashMap<>();

    /**
     * 货主取消订单
     * @param param
     * @return
     */
    public List<String> ownerProcess(OrderCancelParam param) {
        String orderNo = param.getOrderNo();
        Integer orderStatusCode = OrderEnum.Status.CANCELED.getCode();

        //根据不同的取消类型执行不同的取消逻辑
        OrderCancelResult result = cancelTypeMap.get(param.getCancelType()).apply(orderNo, orderStatusCode);
        orderStatusCode = result.getOrderStatusCode();
        this.breakContractSettlementOwner(orderNo, orderStatusCode, param.getCancelType());
        log.info("执行货主取消订单更改状态");
        if (!orderFeign.updateOrderStatusByOrderNo(orderNo, orderStatusCode).succeed()) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "货主取消订单失败,原因：远程调用取消订单失败");
        }
        ownerAccountComponent.thawOwnerAccountByOrderNo(orderNo);
        List<String> childNoList = result.getChildNoList();
        if (CollectionUtil.isNotEmpty(childNoList)) {
            for (String childNo : childNoList) {
                // 订单取消
                orderChildPostService.orderCancel(childNo);
            }
        }
        return childNoList;

    }

    /**
     * 货主取消未拉运+未到达货源地吨数
     * @param orderNo
     * @param orderStatusCode
     * @return
     */
    private OrderCancelResult cancelOrderAndOrderGoodsAndOrderChild(String orderNo, Integer orderStatusCode) {
        log.info("3:货主取消未拉运+未到达货源地吨数");
        String now = DateUtils.formatDateTime(LocalDateTime.now()).get();
        List<String> childNoList = new LinkedList<>();
        List<OrderChild> orderChildren = orderChildDao.selectResidueWeight(orderNo, OrderChildEnum.Status.ARRIVE_SEND.getCode());
        log.info("执行货主取消未拉运+未到达货源地吨数,当前运单个数" + orderChildren.size());
        for (OrderChild orderChild : orderChildren) {
            log.info("取消的运单：{}", JSONUtil.parse(orderChild));
            //释放车辆
            driverService.updateOrderStatus(orderChild.getDriverUserNo(), DriverInfoEnum.DriverStatus.NO.getCode(), orderChild.getTruckId(), 1);
            childNoList.add(orderChild.getChildNo());
            orderChildLogService.saveOrderChildLog(orderChild.getChildNo(),
                    OrderChildEnum.Status.OWNER_CANCEL.getCode(), OrderChildEnum.Status.OWNER_CANCEL.getName(),
                    OrderChildLogEnum.CreateType.OWNER.getCode(), 0L, OrderChildLogEnum.CreateType.OWNER.getMsg()
            );
        }

        Map<String, List<OrderChild>> orderChildMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(childNoList)) {
            log.info("childNoList:{}", childNoList);
            orderChildDao.batchUpdateOrderChildStatus(
                    OrderChildEnum.Status.OWNER_CANCEL.getCode(), "货主取消",
                    now, now, childNoList);
            orderChildMap = orderChildren.stream()
                    .collect(Collectors.groupingBy(OrderChild::getOrderGoodsNo));

        }
        List<OrderGoods> orderGoodsList = orderGoodsDao.getOrderGoodsListByOrderNo(orderNo);

        for (OrderGoods orderGoods : orderGoodsList) {
            OrderGoods update = new OrderGoods();
            update.setId(orderGoods.getId());
            if (CollectionUtil.isEmpty(orderChildMap.get(orderGoods.getOrderGoodsNo()))) {
                update.setOrderGoodsStatus(OrderGoodsStatusEnum.Status.CANCEL.getCode());
            } else {
                BigDecimal reduce = BigDecimal.ZERO;
                for (OrderChild orderChild : orderChildMap.get(orderGoods.getOrderGoodsNo())) {
                    reduce = reduce.add(orderChild.getWeight());
                }

                if (orderGoods.getExtractWeight().compareTo(orderGoods.getResidueTransportWeight().add(reduce)) == 0) {
                    update.setOrderGoodsStatus(OrderGoodsStatusEnum.Status.CANCEL.getCode());
                } else {
                    orderStatusCode = OrderEnum.Status.COMPLETED.getCode();
                    update.setOrderGoodsStatus(OrderGoodsStatusEnum.Status.COMPLETED.getCode());
                }
            }
            if (orderGoods.getPendingOrderWay().equals(PendingOrderWayStatusEnum.Status.DX.getCode())) {
                orderGoodsTruckBindService.updateCancelTruckBind(orderGoods.getOrderGoodsNo());
            }
            goodsOrderTruckRecordComponent.deleteTruckRecord(orderGoods.getOrderGoodsNo());

            orderGoodsDao.updateEntityByKey(update);
        }
        return OrderCancelResult.builder().orderStatusCode(orderStatusCode).childNoList(childNoList).build();
    }

    /**
     * 货主取消未拉运吨数的货单
     * @param orderNo
     * @param orderStatusCode
     * @return
     */
    public OrderCancelResult cancelOrderAndOrderGoods(String orderNo, Integer orderStatusCode) {
        log.info("2:货主取消未拉运吨数的货单");
        List<OrderGoods> orderGoodsList = orderGoodsDao.getOrderGoodsListByOrderNo(orderNo);
        for (OrderGoods orderGoods : orderGoodsList) {
            OrderGoods update = new OrderGoods();
            update.setId(orderGoods.getId());
            if (orderGoods.getResidueTransportWeight().compareTo(orderGoods.getExtractWeight()) == 0) {
                update.setOrderGoodsStatus(OrderGoodsStatusEnum.Status.CANCEL.getCode());
            } else {
                orderStatusCode = OrderEnum.Status.COMPLETED.getCode();
                update.setOrderGoodsStatus(OrderGoodsStatusEnum.Status.COMPLETED.getCode());
            }
            if (orderGoods.getPendingOrderWay().equals(PendingOrderWayStatusEnum.Status.DX.getCode())) {
                orderGoodsTruckBindService.updateCancelTruckBind(orderGoods.getOrderGoodsNo());
            }
            goodsOrderTruckRecordComponent.deleteTruckRecord(orderGoods.getOrderGoodsNo());

            orderGoodsDao.updateEntityByKey(update);
        }
        return OrderCancelResult.builder().orderStatusCode(orderStatusCode).build();
    }

    /**
     * 货主只取消订单
     * @param orderNo
     * @param orderStatusCode
     * @return
     */
    private OrderCancelResult cancelOrder(String orderNo, Integer orderStatusCode) {
        List<OrderGoods> orderGoodsList;
        log.info("1:货主只取消订单");
        if (CollectionUtil.isNotEmpty(orderChildDao.getOrderChildByOrderNo(orderNo))) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前订单已发生变化,请重新选择取消方式");
        }
        orderGoodsList = orderGoodsDao.getOrderGoodsListByOrderNo(orderNo);
        if (CollectionUtil.isNotEmpty(orderGoodsList)) {
            List<Integer> ids = new LinkedList<>();
            for (OrderGoods orderGoods : orderGoodsList) {
                if (orderGoods.getPendingOrderWay().equals(PendingOrderWayStatusEnum.Status.DX.getCode())) {
                    orderGoodsTruckBindService.updateCancelTruckBind(orderGoods.getOrderGoodsNo());
                }
                goodsOrderTruckRecordComponent.deleteTruckRecord(orderGoods.getOrderGoodsNo());

                ids.add(orderGoods.getId());
            }
            orderGoodsDao.batchUpdateOrderGoodsStatus(OrderGoodsStatusEnum.Status.CANCEL.getCode(),
                    ids);
        }
        return OrderCancelResult.builder().orderStatusCode(orderStatusCode).build();
    }

    public void backFillTonnage(OrderGoods orderGoods, BigDecimal weight) {
        if (orderGoods.getOrderGoodsStatus().equals(OrderGoodsStatusEnum.Status.CANCEL.getCode())
                || orderGoods.getOrderGoodsStatus().equals(OrderGoodsStatusEnum.Status.COMPLETED.getCode())
        ) {
            Integer truckDemand = orderGoods.getTruckDemand();
            //返回到货单
            orderGoodsDao.updateOrderGoodsSetResidueWeightAndAlreadyWeight(weight, weight, orderGoods.getId());

            RollbackOrderWeightParam rollbackOrderWeightParam = new RollbackOrderWeightParam();
            rollbackOrderWeightParam.setOrderNo(orderGoods.getOrderNo());
            rollbackOrderWeightParam.setResidueWeight(weight);

            //归还吨数
            if (!truckDemand.equals(TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getCode())) {
                if (truckDemand.equals(TruckDemandEnum.TruckType.PLATFORM_CAR.getCode())) {
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(BigDecimal.ZERO);
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(weight);
                } else if (truckDemand.equals(TruckDemandEnum.TruckType.OWNER_CAR.getCode())) {
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(weight);
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                }
            } else {
                if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.OWN.getCode())) {
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(weight);
                } else {
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(weight);
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(BigDecimal.ZERO);
                }

            }

            Result<Object> result = orderFeign.rollbackOrderWeight(rollbackOrderWeightParam);
            if (!result.succeed()) {
                throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "远程调用更新订单余量失败");
            }
        }
    }

    /**
     * @Author kavin
     * @Description 货单低于35吨自动归还吨数到订单/货单吨数不够扣减，从订单上借吨数
     * @Param [orderGoods, weight,updateType(1: 增加 2：减少)]
     * @return 
     **/
    public void backFillOrderWeight(OrderGoods orderGoods, BigDecimal weight, Integer updateType) {
        Integer truckDemand = orderGoods.getTruckDemand();
        java.util.Optional<UpdateEnum> byCode1 = UpdateEnum.getByCode(updateType);
        String updateTypeMsg = byCode1.isPresent()?byCode1.get().getMsg():"未知调整类型";
        java.util.Optional<TruckDemandEnum.TruckType> byCode = TruckDemandEnum.TruckType.getByCode(truckDemand);
        String truckDemandValue = byCode.isPresent()?byCode.get().getMsg():"未知用车需求";
        log.info("订单号：{},货单号:{},用车需求:{},进行订单剩余吨数{} ,调整吨数:{}",
                orderGoods.getOrderNo(),orderGoods.getOrderGoodsNo(),truckDemandValue,updateTypeMsg,weight);
        String orderNo = orderGoods.getOrderNo();
        Optional<FeignOrderInfoVO> optional = orderService.getOrderInfo(orderNo);
        if(!optional.isPresent()){
            log.warn("通过订单号未查询到对应的订单信息,订单号:{}",orderNo);
            throw new ServiceSystemException(PerformanceResultEnum.DATA_NOT_FIND);
        }
        FeignOrderInfoVO orderInfo = optional.get();
        boolean isSub = Objects.equals(UpdateEnum.SUB.getCode(), updateType);

        RollbackOrderWeightParam rollbackOrderWeightParam = new RollbackOrderWeightParam();
        rollbackOrderWeightParam.setOrderNo(orderGoods.getOrderNo());
        rollbackOrderWeightParam.setResidueWeight(weight);
        rollbackOrderWeightParam.setUpdateType(updateType);

        //归还吨数
        if (!truckDemand.equals(TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getCode())) {
            if (truckDemand.equals(TruckDemandEnum.TruckType.PLATFORM_CAR.getCode())) {
                if(isSub && weight.compareTo(orderInfo.getResidueWeight()) > 0 ){
                    log.warn("货单用车需求: {},订单号：{},货单号：{},平台剩余吨数:{},需要扣减吨数:{},不足扣减",
                            truckDemandValue,orderNo,orderGoods.getOrderGoodsNo(),orderInfo.getPlatformResidueCarryWeight()
                            ,weight);
                    throw new ServiceSystemException(PerformanceResultEnum.ORDER_WEIGHT_LACK);
                }
            } else if (truckDemand.equals(TruckDemandEnum.TruckType.OWNER_CAR.getCode())) {
                if(isSub && weight.compareTo(orderInfo.getResidueWeight()) > 0 ){
                    log.warn("货单用车需求: {},订单号：{},货单号：{},自有剩余吨数:{},需要扣减吨数:{},不足扣减",
                            truckDemandValue,orderNo,orderGoods.getOrderGoodsNo(),orderInfo.getOwnResidueCarryWeight()
                            ,weight);
                    throw new ServiceSystemException(PerformanceResultEnum.ORDER_WEIGHT_LACK);
                }
            }
            rollbackOrderWeightParam.setOwnResidueCarryWeight(BigDecimal.ZERO);
            rollbackOrderWeightParam.setPlatformResidueCarryWeight(BigDecimal.ZERO);
        } else {
            if (Objects.equals(orderGoods.getVehicleUsage(),VehicleUsageEnum.Status.OWN.getCode())) {
                if(isSub && weight.compareTo(orderInfo.getOwnResidueCarryWeight()) > 0 ){
                    log.warn("货单用车需求: {},订单号：{},货单号：{},自有剩余吨数:{},需要扣减吨数:{},不足扣减",
                            TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getMsg(),orderNo,orderGoods.getOrderGoodsNo(),
                            orderInfo.getOwnResidueCarryWeight(),weight);
                    throw new ServiceSystemException(PerformanceResultEnum.ORDER_WEIGHT_LACK);
                }
                rollbackOrderWeightParam.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                rollbackOrderWeightParam.setOwnResidueCarryWeight(weight);
            } else {
                if(isSub && weight.compareTo(orderInfo.getPlatformResidueCarryWeight()) > 0 ){
                    log.warn("货单用车需求: {},订单号：{},货单号：{},平台剩余吨数:{},需要扣减吨数:{},不足扣减",
                            truckDemandValue,orderNo,orderGoods.getOrderGoodsNo(),
                            orderInfo.getPlatformResidueCarryWeight(),weight);
                    throw new ServiceSystemException(PerformanceResultEnum.ORDER_WEIGHT_LACK);
                }
                rollbackOrderWeightParam.setPlatformResidueCarryWeight(weight);
                rollbackOrderWeightParam.setOwnResidueCarryWeight(BigDecimal.ZERO);
            }
        }
        Result<Object> result = orderFeign.rollbackOrderWeight(rollbackOrderWeightParam);
        if (!result.succeed()) {
            log.warn("订单号：{} 的订单做吨数调整，对应货单号:{} 调整失败，调整吨数：{},调整类型:{}",
                    orderNo,orderGoods.getOrderGoodsNo(),weight,updateTypeMsg);
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "远程调用更新订单余量失败");
        }
    }


    /**
     * 客服取消归还吨数
     *
     * @param orderGoodsNo
     * @param weight
     */
    public void backFillTonnageForArtificial(String orderGoodsNo, BigDecimal weight) {
        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(orderGoodsNo).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        if (orderGoods.getOrderGoodsStatus().equals(OrderGoodsStatusEnum.Status.CANCEL.getCode())
                || orderGoods.getOrderGoodsStatus().equals(OrderGoodsStatusEnum.Status.COMPLETED.getCode())
        ) {
            Integer truckDemand = orderGoods.getTruckDemand();
            //返回到货单
            orderGoodsDao.updateOrderGoodsSetResidueWeightAndAlreadyWeight(weight, weight, orderGoods.getId());

            RollbackOrderWeightParam rollbackOrderWeightParam = new RollbackOrderWeightParam();
            rollbackOrderWeightParam.setOrderNo(orderGoods.getOrderNo());
            rollbackOrderWeightParam.setResidueWeight(weight);

            //归还吨数
            if (!truckDemand.equals(TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getCode())) {
                if (truckDemand.equals(TruckDemandEnum.TruckType.PLATFORM_CAR.getCode())) {
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(BigDecimal.ZERO);
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(weight);
                } else if (truckDemand.equals(TruckDemandEnum.TruckType.OWNER_CAR.getCode())) {
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(weight);
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                }
            } else {
                if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.OWN.getCode())) {
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(weight);
                } else {
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(weight);
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(BigDecimal.ZERO);
                }
            }

            Result<Object> result = orderFeign.rollbackOrderWeight(rollbackOrderWeightParam);
            if (!result.succeed()) {
                throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "远程调用更新订单余量失败");
            }
            ArrayList<OrderGoods> list = new ArrayList<>();
            list.add(orderGoods);
            orderGoodsService.batchUpdateResidueWeight(list);
        } else {
            //返回到货单
            orderGoodsDao.updateOrderGoodsSetResidueWeightAndAlreadyWeight(weight, weight, orderGoods.getId());

        }
    }


    public void breakContractSettlementOwner(String orderNo, Integer updateStatus, Integer cancelType) {
        FeignOrderVO orderInfoFeign = orderFeign.getOrderInfoFeign(orderNo);
        Integer orderStatus = orderInfoFeign.getOrderStatus();
        log.info("执行处理违约,订单号：{}, updateStatus:{}, 订单状态{}", orderNo, updateStatus, orderStatus);
        if (OrderEnum.Status.COMPLETED.getCode().equals(updateStatus) || statusCodeMap.containsKey(orderStatus)) {
            try {
                breakContractSettlementOwnerService.saveSettlementOwnerForCancelOrder(orderInfoFeign.getTransportWeight(), orderInfoFeign.getValidFreightPrice(), orderNo, cancelType);
                log.info("执行处理违约完毕");

            } catch (Exception e) {
                log.info("执行处理违约失败{}", e.getMessage());
            }
        }

    }


    @Override
    public void afterPropertiesSet() throws Exception {
        statusCodeMap.put(OrderEnum.Status.QUOTATION_CONFIRMED.getCode(), OrderEnum.Status.QUOTATION_CONFIRMED.getName());
        statusCodeMap.put(OrderEnum.Status.PLATFORM_UNDERTAKING.getCode(), OrderEnum.Status.PLATFORM_UNDERTAKING.getName());
        statusCodeMap.put(OrderEnum.Status.POST_ORDER.getCode(), OrderEnum.Status.POST_ORDER.getName());
        statusCodeMap.put(OrderEnum.Status.ON_ORDER.getCode(), OrderEnum.Status.ON_ORDER.getName());
        statusCodeMap.put(OrderEnum.Status.IN_TRANSIT.getCode(), OrderEnum.Status.IN_TRANSIT.getName());
        cancelTypeMap.put(1, this::cancelOrder);
        cancelTypeMap.put(2, this::cancelOrderAndOrderGoods);
        cancelTypeMap.put(3, this::cancelOrderAndOrderGoodsAndOrderChild);
    }
}
