package com.clx.performance.component;

import cn.hutool.core.collection.CollectionUtil;
import com.clx.order.feign.OrderFeign;
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.OrderChildEnum;
import com.clx.performance.enums.OrderChildLogEnum;
import com.clx.performance.enums.OrderGoodsStatusEnum;
import com.clx.performance.enums.OrderGoodsTruckBindEnum;
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.OrderGoodsService;
import com.clx.performance.service.breakcontract.BreakContractDriverRecordService;
import com.clx.performance.service.child.OrderChildPostService;
import com.clx.performance.utils.spring.ApplicationContextUtils;
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.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();
        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();
                BigDecimal residueTransportWeight = ApplicationContextUtils.getBean(OrderGoodsService.class).
                        calcOrderGoodsResidueWeight(orderGoods.getExtractWeight(),orderGoods.getAlreadyTransportWeight());;

                if (residueTransportWeight.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 {
                    OrderGoods update = new OrderGoods();
                    update.setId(orderGoods.getId());
                    update.setOrderGoodsStatus(OrderGoodsStatusEnum.Status.COMPLETED.getCode());
                    //更新已完结
                    orderGoodsDao.updateEntityByKey(update);
                    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);
                    goodsOrderTruckRecordComponent.releaseDriverCard(orderGoodsNo, orderChild.getTruckNo());
                }
                log.info("取消运单ID集合：{}", childNoList);
                if (CollectionUtil.isNotEmpty(childNoList)) {
                    orderChildDao.batchUpdateOrderChildStatus(OrderChildEnum.Status.PLATFORM_CANCEL.getCode(), "系统自动取消，未按照最晚装货时间到达货源地", now, now, childNoList);
                }

                //更新货单未拉运吨数,已拉运吨数
                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());

            }
        }
    }
}
