package com.clx.performance.strategy.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.clx.order.enums.OrderEnum;
import com.clx.order.feign.OrderFeign;
import com.clx.order.param.feign.UpdateOrderInfoResidueWeightParam;
import com.clx.performance.param.pc.OrderGoodsChildParams;
import com.clx.performance.param.pc.OrderGoodsParams;
import com.clx.order.vo.feign.FeignOrderVO;
import com.clx.performance.component.*;
import com.clx.performance.constant.RabbitKeyConstants;
import com.clx.performance.dao.OrderGoodsDao;
import com.clx.performance.dao.OrderGoodsTruckBindDao;
import com.clx.performance.enums.*;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.service.ordergoods.OrderGoodsPostService;
import com.clx.performance.strategy.GoodsOrderStrategy;
import com.msl.common.exception.ServiceSystemException;
import com.msl.common.utils.DateUtils;
import com.msl.user.data.UserSessionData;
import com.msl.user.utils.TokenUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * 部分平台
 */
@Component("PartGoodsOrderStrategy")
@Slf4j
@AllArgsConstructor
public class PartGoodsOrderStrategy extends GoodsOrderStrategy implements InitializingBean {

    private final OrderGoodsIdGenerate orderGoodsIdGenerate;

    private final OrderGoodsTruckBindDao orderGoodsTruckBindDao;

    private final OrderGoodsDao orderGoodsDao;

    private final OrderFeign orderFeign;

    private final OrderGoodsStatusLazyComponent orderGoodsStatusLazyComponent;

    private final GoodsOrderStrategyContext goodsOrderStrategyContext;

    private final RabbitTemplate rabbitTemplate;

    private final GoodsOrderTruckRecordComponent goodsOrderTruckRecordComponent;

    private final IdGenerateSnowFlake idGenerateSnowFlake;
    private final OrderGoodsPostService orderGoodsPostService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LocalDateTime goodsOrderProcess(OrderGoodsParams orderGoodsParams, FeignOrderVO orderInfo, LocalDateTime now) {
        String orderNo = orderGoodsParams.getOrderNo();
        FeignOrderVO orderInfoFeign = orderFeign.getOrderInfoFeign(orderNo);
        if (!OrderEnum.Status.ON_ORDER.getCode().equals(orderInfoFeign.getOrderStatus())&&
                !OrderEnum.Status.IN_TRANSIT.getCode().equals(orderInfoFeign.getOrderStatus())&&
                !OrderEnum.Status.PLATFORM_UNDERTAKING.getCode().equals(orderInfoFeign.getOrderStatus()
                )
        ) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前订单状态已发生变化,不可被提取");
        }
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();

        LocalDateTime sendLazyTime = null;
        List<OrderGoodsChildParams> childParamsList = orderGoodsParams.getOrderGoodsChildParams();
        BigDecimal platSum = childParamsList.stream().filter(i -> "1".equals(i.getVehicleUsage())).map(OrderGoodsChildParams::getExtractWeight).reduce(
                BigDecimal.ZERO, BigDecimal::add);
        BigDecimal ownSum = childParamsList.stream().filter(i -> !"1".equals(i.getVehicleUsage())).map(OrderGoodsChildParams::getExtractWeight).reduce(
                BigDecimal.ZERO, BigDecimal::add);
        BigDecimal platformCarryWeight = new BigDecimal(orderInfo.getPlatformResidueCarryWeight());
        if (platformCarryWeight.compareTo(platSum) < 0) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前平台承运货单总吨数已超平台承运订单总吨数");
        }
        BigDecimal ownCarryWeight = new BigDecimal(orderInfo.getOwnResidueCarryWeight());
        if (ownCarryWeight.compareTo(ownSum) < 0) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前自有承运货单总吨数已超自有承运订单总吨数");
        }
        Map<String, LocalDateTime> mqMap = new HashMap<>();
        List<OrderGoods> orderGoodsList = new LinkedList<>();
        long batchNumber = idGenerateSnowFlake.nextId(5L);

        long beginOrderGoodsId = orderGoodsIdGenerate.getOrderGoodsId(childParamsList.size());
        for (OrderGoodsChildParams child : childParamsList) {
            if (OrderGoodsPendingOrderWayStatusEnum.Status.EXCLUSIVE.getCode().equals(child.getPendingOrderWay())) {
                if (child.getNeedTruckNum() == null) {
                    throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "定向派单必须选择车辆");

                }
                if (child.getNeedTruckNum() != child.getTruckList().size()) {
                    throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "定向派单需要车数与已选车辆数量不一致");

                }
            }
            OrderGoods orderGoods = new OrderGoods();
            //提取吨数
            orderGoods.setExtractWeight(child.getExtractWeight());
            orderGoods.setResidueTransportWeight(child.getExtractWeight());
            orderGoods.setAlreadyTransportWeight(BigDecimal.ZERO);

            orderGoods.setLossPrice(orderInfo.getLossPrice());
            orderGoods.setTruckDemand(TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getCode());
            orderGoods.setVehicleUsage(Integer.valueOf(child.getVehicleUsage()));

            //提取方式 1提取全部 2提取部分
            Integer extractWay = child.getExtractWay();
            orderGoods.setExtractWay(extractWay);
            //需要车辆
            orderGoods.setNeedTruckNum(child.getNeedTruckNum());
            //挂单方式
            orderGoods.setPendingOrderWay(child.getPendingOrderWay());
            //挂单时间
            LocalDateTime postedTime = DateUtils.parseDateTime(child.getPendingOrderTime()).get();
            //设置批次号
            orderGoods.setBatchNumber(batchNumber);
            if (sendLazyTime == null) {
                sendLazyTime = postedTime;
            } else if (sendLazyTime.isAfter(postedTime)) {
                sendLazyTime = postedTime;
            }

            orderGoods.setPendingOrderTime(postedTime);
            orderGoods.setPendingOrderFreight(child.getPendingOrderFreight());

            orderGoods.setLastArriveSendTime(DateUtils.parseDateTime(child.getLastArriveSendTime()).get());
            //定向运单失效时间
//                    orderGoods.setDirectionalExpireTime(DateUtils.parseDateTime(child.getDirectionalExpireTime()).get());
            orderGoods.setSeniorLogisticsManagerId(child.getSeniorLogisticsManagerId());
            orderGoods.setSeniorLogisticsManagerName(child.getSeniorLogisticsManagerName());

            orderGoods.setOrderNo(orderNo);
            Integer pendingOrderWay = orderGoods.getPendingOrderWay();
            String orderNoPrefix = PendingOrderWayStatusEnum.Status.GK.getCode().equals(pendingOrderWay) ||
                    PendingOrderWayStatusEnum.Status.FLEET_GK.getCode().equals(pendingOrderWay)
                    ? PendingOrderWayStatusEnum.Status.GK.getName() : PendingOrderWayStatusEnum.Status.DX.getName();
            String orderGoodsNo = orderNoPrefix + beginOrderGoodsId;
            orderGoods.setOrderGoodsNo(orderGoodsNo);

            orderGoods.setOrderGoodsStatus(OrderGoodsStatusEnum.Status.CREATED.getCode());
            orderGoods.setSendAddressId(orderInfo.getSendAddressId());
            orderGoods.setSendAddressShorter(orderInfo.getSendAddressShorter());
            orderGoods.setSendSystemAddressId(orderInfoFeign.getSendSystemAddressId());
            //收发货经纬度
            orderGoods.setSendLongitude(orderInfo.getSendLongitude());
            orderGoods.setSendLatitude(orderInfo.getSendLatitude());
            orderGoods.setReceiveLatitude(orderInfo.getReveiveLatitude());
            orderGoods.setReceiveLongitude(orderInfo.getReveiveLongitude());
            orderGoods.setReceiveAddressId(orderInfo.getReveiveAddressId());
            orderGoods.setReceiveAddressShorter(orderInfo.getReveiveAddressShorter());
            orderGoods.setReceiveSystemAddressId(orderInfoFeign.getReveiveSystemAddressId());
            orderGoods.setGoodsName(orderInfo.getGoodsName());
            orderGoods.setGoodsId(orderInfo.getGoodsNameId());

            orderGoods.setCreateTime(now);
            orderGoods.setModifiedTime(now);
            orderGoods.setUserName(loginUserInfo.getUserName());
            orderGoods.setUserNo(loginUserInfo.getUserNo());

            //设置新加的三个最晚时间
            orderGoods.setLastOrderTime(DateUtils.parseDateTime(child.getLastOrderTime()).get());
            orderGoods.setLastLoadTime(DateUtils.parseDateTime(child.getLastLoadTime()).get());
            orderGoods.setLastArriveReceiveTime(DateUtils.parseDateTime(child.getLastArriveReceiveTime()).get());


            //设置结算周期
            orderGoods.setSettlementAccountPeriod(orderInfo.getSettlementAccountPeriod());
            //设置结算方式
            orderGoods.setSettlementWay(orderInfo.getSettlementWay());

            // 平台服务费
            orderGoods.setPlatformFreightQuotationTaxType(orderInfoFeign.getPlatformFreightQuotationTaxType());
            orderGoods.setInvoiceServiceFeeRate(orderInfoFeign.getPlatformFreightQuotationTaxRate());
            orderGoods.setPlatformServiceFeeRate(orderInfoFeign.getPlatformServiceFeeRate());
            orderGoods.setDeposit(orderInfoFeign.getDeposit());

            if (CollectionUtil.isNotEmpty(child.getTruckList())) {
                orderGoodsTruckBindDao.saveBatchEntity(orderNo, orderGoodsNo, child.getTruckList(), now);
                goodsOrderTruckRecordComponent.saveTruckRecord(orderGoodsNo, child.getTruckList());
            }
            mqMap.put(orderGoodsNo, postedTime);
            orderGoodsStatusLazyComponent.expireProduceByLastOrderTime(orderGoods.getLastOrderTime(), orderGoodsNo);
            orderGoodsStatusLazyComponent.expireProduceByLastArriveSendTime(orderGoods.getLastArriveSendTime(), orderGoodsNo);

            beginOrderGoodsId = beginOrderGoodsId + 1;
            orderGoodsList.add(orderGoods);
        }
        log.info("------------------------{}", JSON.toJSONString(orderGoodsList));

        orderGoodsDao.saveBatchEntity(orderGoodsList);

        // 货单新增后置逻辑
        orderGoodsPostService.orderGoodsAdd(orderGoodsList);

        BigDecimal residueWeight = new BigDecimal(orderInfo.getResidueWeight());
        if (platSum.compareTo(BigDecimal.ZERO) != 0 && ownSum.compareTo(BigDecimal.ZERO) != 0) {
            BigDecimal residuePlatSum = new BigDecimal(orderInfo.getPlatformResidueCarryWeight());
            BigDecimal residueOwnSum = new BigDecimal(orderInfo.getOwnResidueCarryWeight());

            UpdateOrderInfoResidueWeightParam param = new UpdateOrderInfoResidueWeightParam();
            param.setOrderId(orderInfo.getId());
            param.setUpdateType("4");
            param.setResidueWeight(residueWeight.subtract(platSum).subtract(ownSum));
            param.setOwnWeight(residueOwnSum.subtract(ownSum));
            param.setPlatWeight(residuePlatSum.subtract(platSum));
            orderFeign.updateOrderInfoResidueWeight(param);
        } else if (platSum.compareTo(BigDecimal.ZERO) != 0 && ownSum.compareTo(BigDecimal.ZERO) == 0) {
            BigDecimal residuePlatSum = new BigDecimal(orderInfo.getPlatformResidueCarryWeight());

            UpdateOrderInfoResidueWeightParam param = new UpdateOrderInfoResidueWeightParam();
            param.setOrderId(orderInfo.getId());
            param.setUpdateType("2");
            param.setResidueWeight(residueWeight.subtract(platSum));
            param.setPlatWeight(residuePlatSum.subtract(platSum));
            orderFeign.updateOrderInfoResidueWeight(param);
        } else if (platSum.compareTo(BigDecimal.ZERO) == 0 && ownSum.compareTo(BigDecimal.ZERO) != 0) {
            BigDecimal residueOwnSum = new BigDecimal(orderInfo.getOwnResidueCarryWeight());

            UpdateOrderInfoResidueWeightParam param = new UpdateOrderInfoResidueWeightParam();
            param.setOrderId(orderInfo.getId());
            param.setUpdateType("3");
            param.setResidueWeight(residueWeight.subtract(ownSum));
            param.setOwnWeight(residueOwnSum.subtract(ownSum));
            orderFeign.updateOrderInfoResidueWeight(param);
        }


        sendMq(mqMap, now);
        return sendLazyTime;
    }

    @Override
    public void afterPropertiesSet() {
        goodsOrderStrategyContext.strategyContext.put(TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getCode(), this);
    }

    public void sendMq(Map<String, LocalDateTime> mqMap, LocalDateTime now) {
        log.info("执行sendMq方法,mqMap大小为：{}", mqMap.size());
        for (Map.Entry<String, LocalDateTime> entry : mqMap.entrySet()) {
            log.info("货单更改挂单中,发送货单更改挂单中延迟消息,时间:{},orderGoodsNo:{}", entry.getValue(), entry.getKey());
            Message message = MessageBuilder.withBody(entry.getKey().getBytes()).build();
            long epochMilli = 0L;
            if (entry.getValue().isAfter(now)) {
                epochMilli = Duration.between(now,entry.getValue()).toMillis();
                log.info("货单更改挂单中,选择时间在当前时间之后，则设置延迟队列时间,时间为：{}", epochMilli);
            }
            if (epochMilli == 0L) {
                log.info("货单更改挂单中,epochMilli时间为0,时间为：{}", epochMilli);
                log.info("货单更改挂单中直接发延迟队列，因为时间早于当前时间");
                rabbitTemplate.send(
                        RabbitKeyConstants.ORDER_GOODS_ON_DEAD_EXCHANGE, RabbitKeyConstants.ORDER_GOODS_ON_DEAD_ROUTE_KEY, message
                );
            } else {
                log.info("货单更改挂单中,epochMilli时间不为0,时间为：{}", epochMilli);
                log.info("货单更改挂单中发送延迟消息，因为挂单时间大于当前时间{}", epochMilli);

                message.getMessageProperties().setHeader("x-delay", epochMilli);
                rabbitTemplate.send(
                        RabbitKeyConstants.ORDER_GOODS_ON_DEAD_EXCHANGE, RabbitKeyConstants.ORDER_GOODS_ON_DEAD_ROUTE_KEY, message
                );
            }
        }
    }
}
