package com.ningdatech.carapi.homepage.service.impl;

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.carapi.car.datascreen.model.dto.DataScreenParam;
import com.ningdatech.carapi.car.vehicle.mapper.VehicleBaseInfoMapper;
import com.ningdatech.carapi.car.vehicle.model.NdVehicleBaseInfo;
import com.ningdatech.carapi.common.aop.BuildChildrenRegionEntity;
import com.ningdatech.carapi.datascope.aop.XmlDataScope;
import com.ningdatech.carapi.homepage.constant.HomepageConstant;
import com.ningdatech.carapi.homepage.entity.dto.HomepageAbnormalBehaviorPageParamDTO;
import com.ningdatech.carapi.homepage.entity.model.OnlineNumCnt;
import com.ningdatech.carapi.homepage.entity.po.DriverAbnormalBehaviorNumPO;
import com.ningdatech.carapi.homepage.entity.po.VehicleNumPO;
import com.ningdatech.carapi.homepage.mapper.HomepageMapper;
import com.ningdatech.carapi.homepage.service.IHomepageService;
import com.ningdatech.carapi.scheduler.mapper.VehicleOnlineStatusDayMapper;

import cn.hutool.core.collection.ListUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author CMM
 * @description 首页查询车辆信息
 * @since 2022/11/10 17:10
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class HomepageServiceImpl implements IHomepageService {
    private final HomepageMapper homepageMapper;
    private final VehicleBaseInfoMapper vehicleBaseInfoMapper;
    private final VehicleOnlineStatusDayMapper statusDayMapper;
    private final StringRedisTemplate stringRedisTemplate;

    @Override
    @XmlDataScope
    @BuildChildrenRegionEntity
    public VehicleNumPO vehicleNum(DataScreenParam param) {
        return vehicleBaseInfoMapper.searchVehicleNum(param);
    }

    @Override
    @XmlDataScope
    @BuildChildrenRegionEntity
    public Integer searchAccumulativeOnlineNum(DataScreenParam param) {
        String tableName = "nd_vehicle_online_status_day_" + NdDateUtils.format(new Date(),"yyyy_MM");
        if(statusDayMapper.countTable(tableName) == 0){
            return homepageMapper.searchAccumulativeOnlineNum(param);
        }
        return homepageMapper.searchAccumulativeOnlineNumByTable(tableName,param);
    }

    @Override
    @XmlDataScope
    @BuildChildrenRegionEntity
    public DriverAbnormalBehaviorNumPO driverAbnormalBehaviorNum(HomepageAbnormalBehaviorPageParamDTO param) {
        return homepageMapper.selectDriverAbnormalBehaviorNum(param);
    }

    @Override
    public List<OnlineNumCnt> getOnlineNumCnt(List<NdVehicleBaseInfo> vehicleBaseInfos) {
        Map<Object, Object> onlineMap = stringRedisTemplate.opsForHash().entries("online_index");

        // 分批
        List<List<NdVehicleBaseInfo>> batchList = new ArrayList<>(ListUtil.partition(new ArrayList<>(vehicleBaseInfos), 5000));
        // 创建线程池 线程数是 分批的数量
        ExecutorService executorService = Executors.newFixedThreadPool(batchList.size());
        // 线程计数器,就是 分批的数
        CountDownLatch countDownLatch = new CountDownLatch(batchList.size());
        List<OnlineNumCnt> cntList = Lists.newArrayList();
        batchList.forEach(e -> {
            // 创建一个变量
            AtomicInteger value = new AtomicInteger();
            //每个分批用一个线程执行
            executorService.execute(()->{
                List<NdVehicleBaseInfo> resultList = e.stream().filter(v -> {
                    // 取到每个数据进行业务执行
                    String carPlate = v.getCarPlate();
                    LocalDateTime startTime = LocalDateTime.now();
                    String timeStamp = (String) onlineMap.get(carPlate);
                    if (Objects.nonNull(timeStamp)) {
                        // 将时间戳转换为Instant对象
                        Instant instant = Instant.ofEpochSecond(Long.parseLong(timeStamp));
                        // 将Instant对象转换为LocalDateTime对象
                        LocalDateTime endTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
                        Duration minuteDuration = Duration.between(endTime,startTime);
                        long minute = minuteDuration.toMinutes();
                        // 判断最后一次上传时间距离当前时间是否大于5分钟
                        if (minute <= HomepageConstant.TIME_INTERVAL) {
                            return true;
                        }
                    }
                    return false;
                }).collect(Collectors.toList());
                log.info("当前线程单组在线数为{}",resultList.size());
                // 创建一个 Lambda 表达式，使用闭包给变量赋值
                Consumer<Integer> consumer = (newValue) -> {
                    value.set(newValue);
                    log.info("Value updated to " + value);
                };
                consumer.accept(resultList.size());
                OnlineNumCnt onlineNumCnt = new OnlineNumCnt();
                onlineNumCnt.setCnt(value.get());
                cntList.add(onlineNumCnt);
            });
            countDownLatch.countDown();
        });
        try {
            // 等待所有线程执行完成
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new BizException(e.getMessage());
        }
        executorService.shutdown();
        try {
            executorService.awaitTermination(5, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            throw new BizException(e.getMessage());
        }
        if (executorService.isTerminated()) {
            log.info("子线程执行完毕");
            log.info("主线程开始");
        }
        return cntList;
    }
}
