package com.clx.performance.component;

import cn.hutool.core.collection.CollectionUtil;
import com.clx.order.enums.VehicleUsageEnum;
import com.clx.order.feign.OrderFeign;
import com.clx.order.param.feign.RollbackOrderWeightParam;
import com.clx.performance.constant.RedisConstants;
import com.clx.performance.dao.OrderChildDao;
import com.clx.performance.dao.OrderGoodsDao;
import com.clx.performance.dao.OrderGoodsTruckBindDao;
import com.clx.performance.enums.*;
import com.clx.performance.extranal.user.DriverService;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.service.OrderChildLogService;
import com.clx.performance.service.breakcontract.BreakContractDriverRecordService;
import com.clx.performance.service.child.OrderChildPostService;
import com.clx.user.enums.driver.DriverInfoEnum;
import com.msl.common.base.Optional;
import com.msl.common.utils.DateUtils;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * 货单最晚接单时间、最晚到达货源地时间处理
 */
@Component
@Slf4j
@AllArgsConstructor
public class OrderGoodsStatusLazyComponent implements InitializingBean {

    private final RedisTemplate<String, String> redisTemplate;

    private final OrderGoodsDao orderGoodsDao;

    private final OrderFeign orderFeign;

    private final OrderGoodsTruckBindDao orderGoodsTruckBindDao;

    private final GoodsOrderTruckRecordComponent goodsOrderTruckRecordComponent;

    private final OrderChildDao orderChildDao;

    private final DriverService driverService;

    private final BreakContractDriverRecordService breakContractDriverRecordService;

    private final OrderChildLogService orderChildLogService;

    private final OrderChildPostService orderChildPostService;


    //根据货单最晚接单时间处理
    public void expireProduceByLastOrderTime(LocalDateTime localDateTime, String orderGoodsNo) {
        redisTemplate.opsForZSet().add(RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ORDER_TIME, orderGoodsNo, localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli());
    }

    //删除货单最晚接单时间处理
    public void deleteRedisRecordForLastOrderTime(String orderGoodsNo) {
        redisTemplate.opsForZSet().remove(RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ORDER_TIME, orderGoodsNo);
    }

    //删除货单最晚到达货源地时间处理
    public void deleteRedisRecordForLastArriveSendTime(String orderGoodsNo) {
        redisTemplate.opsForZSet().remove(RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ARRIVE_SEND_TIME, orderGoodsNo);
    }

    //根据货单最晚到达货源地时间处理
    public void expireProduceByLastArriveSendTime(LocalDateTime localDateTime, String orderGoodsNo) {
        redisTemplate.opsForZSet().add(RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ARRIVE_SEND_TIME, orderGoodsNo, localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli());
    }


    /**
     * 根据货单最晚接单时间处理的
     */
    @XxlJob("OrderGoodsSuccess")
    @Transactional(rollbackFor = Exception.class)
    public void consumingLastOrderTime() {
        log.info("货单-最晚接单时间-定时器启动");
        long nowTimeMillis = System.currentTimeMillis();
        LocalDateTime nowDateTime = new Date(nowTimeMillis).toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
        Set<ZSetOperations.TypedTuple<String>> orderGoodsIds = redisTemplate.opsForZSet().rangeByScoreWithScores(
                RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ORDER_TIME,
                0, nowTimeMillis  //延时任务score最小值
                //延时任务score最大值（当前时间）
        );
        if (orderGoodsIds == null) {
            log.info("货单-最晚接单时间-定时器查询redis条数为null");
            return;
        }
        if (orderGoodsIds.isEmpty()) {
            log.info("货单-最晚接单时间-定时器查询redis条数为空");
            return;
        }
        if (!CollectionUtil.isEmpty(orderGoodsIds)) {
            log.info("货单-最晚接单时间-定时器查询redis条数：{}", orderGoodsIds.size());

            for (ZSetOperations.TypedTuple<String> orderGoodsId : orderGoodsIds) {
                log.info("货单" + orderGoodsId + "过了最晚接单时间");
                String orderGoodsNo = orderGoodsId.getValue();
                log.info("处理当前货单编号:{}", orderGoodsNo);
                Optional<OrderGoods> optional = orderGoodsDao.getByOrderGoodsNo(orderGoodsNo);
                if (!optional.isPresent()) {
                    redisTemplate.opsForZSet().remove(RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ORDER_TIME, orderGoodsId.getValue());
                    log.info("当前货单编号未查询出货单数据，执行删除redis ORDER_GOODS_STATUS_LAZY id: {}", orderGoodsId.getValue());
                    continue;
                }
                OrderGoods orderGoods = optional.get();

                if (orderGoods.getResidueTransportWeight().compareTo(BigDecimal.ZERO) == 0) {
                    List<OrderChild> orderChildren = orderChildDao.selectInTransitOrderChildByOrderGoodsNo(orderGoodsNo);
                    if (CollectionUtil.isNotEmpty(orderChildren)) {
                        //更新货单已完结
                        log.info("当前货单虽然可拉运吨数为0,但是存在未拉运完成的运单,所以更新为已完结,货单编号{}", orderGoodsNo);
                        orderGoodsDao.updateOrderGoodsStatusByOrderGoodsNo(orderGoodsNo, OrderGoodsStatusEnum.Status.COMPLETED.getCode());
                    } else {
                        //更新货单已完成
                        log.info("当前货单可拉运吨数为0,未存在未拉运完成的运单,所以更新为已完成,货单编号{}", orderGoodsNo);
                        orderGoodsDao.updateOrderGoodsStatusByOrderGoodsNo(orderGoodsNo, OrderGoodsStatusEnum.Status.SUCCESS.getCode());
                    }


                } else {
                    //大于35吨的归还吨数在这里处理
                    if(orderGoods.getResidueTransportWeight().compareTo(new BigDecimal("35")) >= 0){
                        RollbackOrderWeightParam param = new RollbackOrderWeightParam();
                        param.setOrderNo(orderGoods.getOrderNo());
                        param.setResidueWeight(orderGoods.getResidueTransportWeight());
                        if (orderGoods.getTruckDemand().equals(TruckDemandEnum.TruckType.PLATFORM_CAR.getCode())
                                || orderGoods.getTruckDemand().equals(TruckDemandEnum.TruckType.OWNER_CAR.getCode())) {
                            param.setOwnResidueCarryWeight(BigDecimal.ZERO);
                            param.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                        } else {
                            if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.PLATFORM.getCode())) {
                                param.setOwnResidueCarryWeight(BigDecimal.ZERO);
                                param.setPlatformResidueCarryWeight(orderGoods.getResidueTransportWeight());
                            } else if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.OWN.getCode())) {
                                param.setOwnResidueCarryWeight(orderGoods.getResidueTransportWeight());
                                param.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                            }
                        }
                        orderFeign.rollbackOrderWeight(param);
                    }
                    //更新已完结
                    orderGoodsDao.updateOrderGoodsStatusByOrderGoodsNo(orderGoodsNo, OrderGoodsStatusEnum.Status.COMPLETED.getCode());

                    log.info("删除redis ORDER_GOODS_STATUS_LAZY id: {}", orderGoodsId.getValue());
                }
                orderGoodsTruckBindDao.updateOrderGoodsBindStatus(orderGoodsNo, OrderGoodsTruckBindEnum.Status.EXPIRE.getCode());
                goodsOrderTruckRecordComponent.deleteTruckRecord(orderGoodsNo);

                redisTemplate.opsForZSet().remove(RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ORDER_TIME, orderGoodsId.getValue());

            }
        }
    }


    /**
     * 最晚到达货源地运单关闭
     */
    @XxlJob("OrderChildCancel")
    @Transactional(rollbackFor = Exception.class)
    public void consumingLastArriveSendTime() {
        log.info("货单-最晚到达货源地时间-定时器启动");
        long nowTimeMillis = System.currentTimeMillis();
        String now = DateUtils.formatDateTime(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss").get();
        Set<ZSetOperations.TypedTuple<String>> orderGoodsIds = redisTemplate.opsForZSet().rangeByScoreWithScores(
                RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ARRIVE_SEND_TIME,
                0, nowTimeMillis  //延时任务score最小值
                //延时任务score最大值（当前时间）
        );
        if (orderGoodsIds == null) {
            log.info("货单-最晚到达货源地时间-定时器查询redis条数为null");
            return;
        }
        if (orderGoodsIds.isEmpty()) {
            log.info("货单-最晚到达货源地时间-定时器查询redis条数为空");
            return;
        }
        if (!CollectionUtil.isEmpty(orderGoodsIds)) {
            log.info("货单-最晚到达货源地时间-定时器查询redis条数：{}", orderGoodsIds.size());

            for (ZSetOperations.TypedTuple<String> orderGoodsId : orderGoodsIds) {
                log.info("货单" + orderGoodsId.getValue() + "过了最晚到达货源地时间");
                String orderGoodsNo = orderGoodsId.getValue();
                log.info("处理当前货单编号:{}", orderGoodsNo);
                Optional<OrderGoods> optional = orderGoodsDao.getByOrderGoodsNo(orderGoodsNo);
                if (!optional.isPresent()) {
                    redisTemplate.opsForZSet().remove(RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ARRIVE_SEND_TIME, orderGoodsId.getValue());
                    log.info("当前货单编号未查询出货单数据，执行删除redis ORDER_GOODS_STATUS_LAZY id: {}", orderGoodsId.getValue());
                    continue;
                }
                OrderGoods orderGoods = optional.get();

                List<OrderChild> orderChildrenList = orderChildDao.selectArriveSendOrderChild(orderGoodsNo);

                BigDecimal childSum = BigDecimal.ZERO;

                List<String> childNoList = new LinkedList<>();
                for (OrderChild orderChild : orderChildrenList) {
                    childSum = childSum.add(orderChild.getWeight());
                    childNoList.add(orderChild.getChildNo());
                    //释放车辆
                    driverService.updateOrderStatus(orderChild.getDriverUserNo(), DriverInfoEnum.DriverStatus.NO.getCode(), orderChild.getTruckId(), 1);
                    orderChild.setCancelTime(DateUtils.parseDateTime(now).get());
                    orderChild.setFinishTime(DateUtils.parseDateTime(now).get());

                    //保存运单日志数据
                    orderChildLogService.saveDriverOrderChildLog(orderChild.getChildNo(), OrderChildLogEnum.Type.PLATFORM_CANCEL.getCode(),
                            OrderChildLogEnum.Type.PLATFORM_CANCEL.getMsg(), 0L, "系统");

                    // 到达货源地超时取消
                    orderChildPostService.arriveSendAddressTimeoutCancel(orderChild);
                }
                log.info("取消运单ID集合：{}", childNoList);
                if (CollectionUtil.isNotEmpty(childNoList)) {
                    orderChildDao.batchUpdateOrderChildStatus(OrderChildEnum.Status.PLATFORM_CANCEL.getCode(), "系统自动取消，未按照最晚装货时间到达货源地", now, now, childNoList);
                }


                //当前货单已经到了最晚接单时间，所有相关状态均已经处理完毕，此刻单独处理运单的数据
                if (OrderGoodsStatusEnum.Status.SUCCESS.getCode().equals(orderGoods.getOrderGoodsStatus())
                        || OrderGoodsStatusEnum.Status.COMPLETED.getCode().equals(orderGoods.getOrderGoodsStatus())
                ) {
                    RollbackOrderWeightParam param = new RollbackOrderWeightParam();
                    param.setOrderNo(orderGoods.getOrderNo());
                    param.setResidueWeight(childSum);

                    //当前情况需要回填订单的余量
                    if (orderGoods.getTruckDemand().equals(1) || orderGoods.getTruckDemand().equals(3)) {
                        param.setOwnResidueCarryWeight(BigDecimal.ZERO);
                        param.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                    } else {
                        if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.PLATFORM.getCode())) {
                            param.setOwnResidueCarryWeight(BigDecimal.ZERO);
                            param.setPlatformResidueCarryWeight(orderGoods.getResidueTransportWeight());
                        } else if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.OWN.getCode())) {
                            param.setOwnResidueCarryWeight(orderGoods.getResidueTransportWeight());
                            param.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                        }
                    }
                    //只更新货单已拉运吨数
                    orderGoodsDao.updateOrderGoodsSetResidueWeightAndAlreadyWeight(childSum, childSum, orderGoods.getId());
                    orderFeign.rollbackOrderWeight(param);
                } else {
                    //只更新货单未拉运吨数,已拉运吨数
                    orderGoodsDao.updateOrderGoodsSetResidueWeightAndAlreadyWeight(childSum, childSum, orderGoods.getId());
                }
                redisTemplate.opsForZSet().remove(RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ARRIVE_SEND_TIME, orderGoodsId.getValue());


            }
        }
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        Optional<List<OrderGoods>> optional = orderGoodsDao.getOrderGoodsList();
        if (optional.isPresent()) {
            for (OrderGoods orderGoods : optional.get()) {
                //处理最晚接单时间，货单处理，并回退吨数
                redisTemplate.opsForZSet().add(RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ORDER_TIME, orderGoods.getOrderGoodsNo(), orderGoods.getLastOrderTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());
                //处理最晚到达货源地，运单取消处理，并回退吨数
                redisTemplate.opsForZSet().add(RedisConstants.ORDER_GOODS_STATUS_LAZY_LAST_ARRIVE_SEND_TIME, orderGoods.getOrderGoodsNo(), orderGoods.getLastArriveSendTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());

            }
        }
    }
}
