package com.ningdatech.carapi.irs.manage;

import java.io.*;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.ningdatech.basic.config.DefaultAsyncTaskConfig;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.cache.lock.DistributedLock;
import com.ningdatech.cache.model.cache.CacheKey;
import com.ningdatech.cache.redis.RedisOps;
import com.ningdatech.carapi.car.position.entity.VehiclePositionInfo;
import com.ningdatech.carapi.car.position.service.IVehiclePositionInfoService;
import com.ningdatech.carapi.car.vehicle.model.NdVehicleBaseInfo;
import com.ningdatech.carapi.car.vehicle.service.IVehicleBaseInfoService;
import com.ningdatech.carapi.common.constant.MissCertEnum;
import com.ningdatech.carapi.common.constant.ViolationTypeEnum;
import com.ningdatech.carapi.driver.entity.DriverInfo;
import com.ningdatech.carapi.driver.service.IDriverInfoService;
import com.ningdatech.carapi.irs.model.entity.IrsTempCarplate;
import com.ningdatech.carapi.irs.model.entity.VehicleAccidentIrsData;
import com.ningdatech.carapi.irs.model.entity.VehicleViolationIrsData;
import com.ningdatech.carapi.irs.service.*;
import com.ningdatech.carapi.qrcode.service.VehicleGetOnService;
import com.ningdatech.carapi.safe.constant.AccidentTypeEnum;
import com.ningdatech.carapi.safe.constant.VehicleAccidentReportStatusEnum;
import com.ningdatech.carapi.safe.entity.NdVehicleAccident;
import com.ningdatech.carapi.safe.entity.NdVehicleAccidentDead;
import com.ningdatech.carapi.safe.entity.NdVehicleViolation;
import com.ningdatech.carapi.safe.service.INdVehicleAccidentDeadService;
import com.ningdatech.carapi.safe.service.INdVehicleAccidentService;
import com.ningdatech.carapi.safe.service.INdVehicleViolationService;
import com.ningdatech.carapi.scheduler.contants.TaskContant;
import com.ningdatech.carapi.sys.entity.Company;
import com.ningdatech.carapi.sys.helper.RegionsCacheHelper;
import com.ningdatech.carapi.sys.helper.VehiclesCacheHelper;
import com.ningdatech.carapi.sys.service.CompanyService;
import com.ningdatech.file.utils.StrPool;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author CMM
 * @since 2023/05/11 10:57
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DataInitManage {

    @Value("${spring.redis.host}")
    public String REDIS_HOST;

    @Value("${spring.redis.port}")
    public String REDIS_PORT;

    private static final int GROUP_SIZE = 500;
    private static final int QUERY_SIZE = 2000;
    private static final long BIG_EXPIRE_TIME = 60 * 60 * 1000;

    private final DefaultAsyncTaskConfig defaultAsyncTaskConfig;
    private final IVehicleBaseInfoService vehicleBaseInfoService;
    private final AccidentService accidentService;
    private final RegionsCacheHelper regionsCacheHelper;
    private final VehicleGetOnService vehicleGetOnService;
    private final INdVehicleAccidentService vehicleAccidentService;
    private final INdVehicleAccidentDeadService vehicleAccidentDeadService;
    private final CarService carService;
    private final VehiclesCacheHelper vehiclesCacheHelper;
    private final INdVehicleViolationService vehicleViolationService;
    private final IDriverInfoService driverInfoService;
    private final CompanyService companyService;
    private final DistributedLock distributedLock;
    private final IVehicleAccidentIrsDataService accidentIrsDataService;
    private final IVehicleViolationIrsDataService violationIrsDataService;
    private final RedisOps redisOps;
    private final IIrsTempCarplateService irsTempCarplateService;
    private final IVehiclePositionInfoService iVehiclePositionInfoService;

    /**
     * 无驾驶证违法行为code列表
     */
    private static final List<String> NO_DRIVING_LICENSE_LIST =
        Arrays.asList("5075", "5072", "5077", "5057", "10159", "1082", "70619", "6018", "7503", "7504", "7006", "70069",
            "1015", "16444", "1644", "50411", "60182", "8005", "80059", "8605", "5603", "5703", "1610", "5041", "60541",
            "1110", "7061", "10050", "10051", "10052", "10059", "1006", "1010", "10109", "1013", "1014", "6086", "5006",
            "1005", "56031", "60181", "57021", "57031", "1704", "1701");

    /**
     * 无行驶证违法行为code列表
     */
    private static final List<String> NO_VEHICLE_LICENSE_LIST = Arrays.asList("5071", "5069", "1088", "5702", "5705",
        "7216", "7218", "1109", "6085", "5003", "57051", "50031", "57021", "5009", "5015");

    /**
     * 闯红灯(违反交通信号灯)
     */
    private static final List<String> VIOLATION_TRAFFIC_LIGHTS_LIST = Arrays.asList("13029", "1625", "16259", "1302");

    /**
     * 违规时段行驶
     */
    private static final List<String> VIOLATION_TIME_LIST = Arrays.asList("8025");

    /**
     * 违规路段行驶
     */
    private static final List<String> VIOLATION_ROAD_LIST =
        Arrays.asList("1048", "10489", "40099", "8004", "8803", "11229", "8005J", "8002", "8048", "4009", "10393",
            "10397", "1045", "10459", "1310", "13109", "1023", "10239", "8005", "8001C", "1122", "8014");

    public String dataInit() {
        LambdaQueryWrapper<NdVehicleBaseInfo> query = Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
            .select(NdVehicleBaseInfo::getCarPlate).isNotNull(NdVehicleBaseInfo::getCarPlate);
        List<NdVehicleBaseInfo> list = vehicleBaseInfoService.list(query);

        // 获取此次任务要查询的车牌号
        List<String> carPlates = list.stream().map(NdVehicleBaseInfo::getCarPlate).collect(Collectors.toList());

        List<NdVehicleBaseInfo> vehicleBaseInfos = vehicleBaseInfoService
            .list(Wrappers.lambdaQuery(NdVehicleBaseInfo.class).in(NdVehicleBaseInfo::getCarPlate, carPlates));
        Map<String, NdVehicleBaseInfo> vehicleBaseInfoMap =
            vehicleBaseInfos.stream().collect(Collectors.toMap(NdVehicleBaseInfo::getCarPlate, v -> v));

        Map<Long, Company> companyMap =
            companyService.list().stream().collect(Collectors.toMap(Company::getId, c -> c));

        // 获取已经存在的事故数据
        List<NdVehicleAccident> accidentTmpVas = vehicleAccidentService
            .list(Wrappers.lambdaQuery(NdVehicleAccident.class).in(NdVehicleAccident::getCarPlate, carPlates));
        Map<String, List<NdVehicleAccident>> accidentMap =
            CollUtils.group(accidentTmpVas, NdVehicleAccident::getCarPlate);

        // 获取已经存在的死亡事故数据
        List<NdVehicleAccidentDead> deadAccidentTmpVas = vehicleAccidentDeadService
            .list(Wrappers.lambdaQuery(NdVehicleAccidentDead.class).in(NdVehicleAccidentDead::getCarPlate, carPlates));
        Map<String, List<NdVehicleAccidentDead>> deadAccidentMap =
            CollUtils.group(deadAccidentTmpVas, NdVehicleAccidentDead::getCarPlate);

        log.info("此次任务数据量为 {}", list.size());

        List<String> lists = Lists.newArrayList();
        lists.add("浙B1Q567");
        lists.add("浙B3R397");
        lists.add("浙BE5516");
        lists.add("浙B1E907");
        lists.add("浙B0J292");
        lists.add("浙A8Y637");
        lists.add("浙C52502");
        lists.add("浙CL0175");
        lists.add("浙FM8020");
        lists.add("浙J61963");

        // 调用IRS接口,返回数据
        for (String carPlate : lists) {
            if (StrUtil.isNotBlank(carPlate)) {
                NdVehicleBaseInfo vehicleBaseInfo = vehicleBaseInfoMap.get(carPlate);
                Long companyId = vehicleBaseInfo.getCompanyId();
                Company company = companyMap.get(companyId);
                String dataJsonStr = accidentService.accidentQuery(carPlate);
                JSONObject object = JSON.parseObject(dataJsonStr, JSONObject.class);
                String data = object.getString("datas");
                List<String> array = JSON.parseArray(data, String.class);
                for (String datas : array) {
                    if (StrUtil.isNotBlank(datas)) {
                        List<JSONObject> accidentArray = JSON.parseArray(datas, JSONObject.class);
                        if (CollUtil.isEmpty(accidentArray)) {
                            log.info("该车牌号没有事故信息!");
                            continue;
                        }
                        for (JSONObject jsonObject : accidentArray) {
                            // 获取行政区划
                            String xzqh = jsonObject.getString("XZQH");
                            // 获取区域信息
                            Long regionId = regionsCacheHelper.getIdByCode(xzqh);
                            String regionName = regionsCacheHelper.getDisplayName(regionId);
                            // 获取事故日期
                            Timestamp sgfssj = jsonObject.getTimestamp("SGFSSJ");
                            LocalDateTime accidentTime = LocalDateTimeUtil.of(sgfssj);

                            // 获取事故地点
                            String sgdd = jsonObject.getString("SGDD");

                            // 先查出对应车牌号关联的责任驾驶员
                            String driverName = vehicleBaseInfo.getResponsibleDriverFirst();

                            if (Objects.isNull(driverName)) {
                                log.info("该车牌号没有责任驾驶员!");
                                continue;
                            }
                            // 获取车辆类型
                            Integer vehicleType = vehicleBaseInfo.getVehicleType();
                            // 获取当场、24小时、3日内、7日内、30日内死亡人数
                            Integer swrs = jsonObject.getInteger("SWRS");
                            Integer swrs24 = jsonObject.getInteger("SWRS24");
                            Integer swrs3 = jsonObject.getInteger("SWRS3");
                            Integer swrs7 = jsonObject.getInteger("SWRS7");
                            Integer swrs30 = jsonObject.getInteger("SWRS30");
                            // 获取受伤人数
                            Integer ssrs = jsonObject.getInteger("SSRS");
                            // 没有死亡人数
                            // 插入到事故表中
                            if (swrs == 0 && swrs24 == 0 && swrs3 == 0 && swrs7 == 0 && swrs30 == 0) {
                                NdVehicleAccident accident = new NdVehicleAccident();
                                // 判断当前事故对应的车牌号是否在在事故表中已存在事故数据
                                List<NdVehicleAccident> accidents = accidentMap.get(carPlate);
                                if (CollUtil.isNotEmpty(accidents)) {
                                    List<LocalDateTime> timeList = accidents.stream()
                                        .map(NdVehicleAccident::getAccidentTime).collect(Collectors.toList());
                                    // 如果该数据已经录入，直接跳过
                                    if (timeList.contains(accidentTime)) {
                                        log.info("该事故数据已录入！");
                                        continue;
                                    }
                                }
                                accident.setInjuries(ssrs);
                                accident.setRegionId(regionId);
                                accident.setRegionName(regionName);
                                // 获取事故时间
                                accident.setAccidentTime(accidentTime);
                                accident.setAccidentAddress(sgdd);
                                // 装配车牌号、事故驾驶员、车辆类型、企业名称
                                accident.setCarPlate(carPlate);
                                accident.setAccidentDriver(driverName);
                                accident.setVehicleType(vehicleType);
                                accident.setCompanyId(companyId);
                                if (Objects.nonNull(company)) {
                                    accident.setCompanyName(company.getName());
                                }
                                // 是否上报默认为未上报
                                accident.setReportStatus(VehicleAccidentReportStatusEnum.UNDER_REPORT.getCode());
                                vehicleAccidentService.saveOrUpdate(accident);
                            } else {
                                // 插入数据到死亡事故表中
                                NdVehicleAccidentDead accidentDead = new NdVehicleAccidentDead();
                                // 判断当前事故对应的车牌号是否在在事故表中已存在事故数据
                                List<NdVehicleAccidentDead> deadAccidents = deadAccidentMap.get(carPlate);
                                if (CollUtil.isNotEmpty(deadAccidents)) {
                                    List<LocalDateTime> timeList = deadAccidents.stream()
                                        .map(NdVehicleAccidentDead::getAccidentTime).collect(Collectors.toList());
                                    // 如果该数据已经录入，直接跳过
                                    if (timeList.contains(accidentTime)) {
                                        log.info("该死亡数据已录入!");
                                        continue;
                                    }
                                }
                                if (swrs30 != 0) {
                                    accidentDead.setDeathToll(swrs30);
                                } else if (swrs7 != 0) {
                                    accidentDead.setDeathToll(swrs7);
                                } else if (swrs3 != 0) {
                                    accidentDead.setDeathToll(swrs3);
                                } else if (swrs24 != 0) {
                                    accidentDead.setDeathToll(swrs24);
                                } else {
                                    accidentDead.setDeathToll(swrs);
                                }
                                accidentDead.setInjuries(ssrs);
                                accidentDead.setRegionId(regionId);
                                accidentDead.setRegionName(regionName);
                                // 获取事故时间
                                accidentDead.setAccidentTime(accidentTime);
                                accidentDead.setAccidentAddress(sgdd);
                                // 装配车牌号、事故驾驶员、企业名称
                                accidentDead.setCarPlate(carPlate);
                                accidentDead.setAccidentDriver(driverName);
                                accidentDead.setCompanyId(companyId);
                                if (Objects.nonNull(company)) {
                                    accidentDead.setCompanyName(company.getName());
                                }
                                // 是否上报默认为未上报
                                accidentDead.setReportStatus(VehicleAccidentReportStatusEnum.UNDER_REPORT.getCode());
                                vehicleAccidentDeadService.saveOrUpdate(accidentDead);
                            }
                        }
                    }
                }
            }
        }
        return "更新完成";
    }

    public String vehicleIllegaldataInit() {
        LambdaQueryWrapper<NdVehicleBaseInfo> query = Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
            .select(NdVehicleBaseInfo::getCarPlate).isNotNull(NdVehicleBaseInfo::getCarPlate);
        List<NdVehicleBaseInfo> list = vehicleBaseInfoService.list(query);

        List<String> carPlates = CollUtils.fieldList(list, NdVehicleBaseInfo::getCarPlate);

        // 获取车辆违章时间信息
        List<NdVehicleViolation> vioList = vehicleViolationService
            .list(Wrappers.lambdaQuery(NdVehicleViolation.class).in(NdVehicleViolation::getCarPlate, carPlates));
        Map<String, List<NdVehicleViolation>> listMap = CollUtils.group(vioList, NdVehicleViolation::getCarPlate);
        log.info("此次任务数据量为 {}", list.size());

        // 调用IRS接口,返回数据
        for (String hphm : carPlates) {
            String dataJsonStr = carService.vehicleIllegalQuery(hphm);
            JSONObject object = JSON.parseObject(dataJsonStr, JSONObject.class);
            String datas = object.getString("datas");
            List<JSONObject> vehicleIllegalArray = JSON.parseArray(datas, JSONObject.class);
            if (CollUtil.isEmpty(vehicleIllegalArray)) {
                log.info("该车牌号没有违章信息!");
                continue;
            }
            // 获取当前车牌号已经存在的违章时间数据
            List<NdVehicleViolation> violationList = listMap.get(hphm);
            List<JSONObject> vehicleIllegalInfo = null;
            if (CollUtil.isNotEmpty(violationList)) {
                List<String> violationTimeList = violationList.stream()
                    .map(v -> LocalDateTimeUtil.of(v.getViolationDate())
                        .format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_MINUTE_PATTERN)))
                    .collect(Collectors.toList());
                // 筛选出不在车辆违法信息表中的数据
                vehicleIllegalInfo = vehicleIllegalArray.stream()
                    .filter(v -> !violationTimeList.contains(LocalDateTimeUtil.of(v.getTimestamp("wfsj"))
                        .format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_MINUTE_PATTERN))))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(vehicleIllegalInfo)) {
                    log.info("该车牌号没有新增的违章信息");
                    continue;
                }
            } else {
                vehicleIllegalInfo = vehicleIllegalArray;
            }
            for (JSONObject jsonObject : vehicleIllegalInfo) {
                NdVehicleViolation vehicleViolation = new NdVehicleViolation();
                vehicleViolation.setCarPlate(hphm);
                // 获取行政区划
                String xzqh = jsonObject.getString("xzqh");
                // 获取区域信息
                Long regionId = regionsCacheHelper.getIdByCode(xzqh);
                String regionName = regionsCacheHelper.getDisplayName(regionId);
                vehicleViolation.setRegionId(regionId);
                vehicleViolation.setRegionName(regionName);
                // 获取违法日期
                Timestamp wfsj = jsonObject.getTimestamp("wfsj");
                LocalDateTime vehicleIllegalTime = LocalDateTimeUtil.of(wfsj);
                vehicleViolation.setViolationDate(vehicleIllegalTime);
                // 获取违法地址
                String wfdz = jsonObject.getString("wfdz");

                // 获取违法行为
                String wfxw = jsonObject.getString("wfxw");
                // 如果是闯红灯
                if (VIOLATION_TRAFFIC_LIGHTS_LIST.contains(wfxw)) {
                    vehicleViolation.setViolationType(ViolationTypeEnum.RED_LIGHT.getCode());
                    vehicleViolation.setAddressRedLight(wfdz);
                } else if (NO_DRIVING_LICENSE_LIST.contains(wfxw)) {
                    vehicleViolation.setViolationType(ViolationTypeEnum.MISS_CERT.getCode());
                    vehicleViolation.setMissingCertificateType(MissCertEnum.DRIVER_LINCENSE.getCode());
                } else if (NO_VEHICLE_LICENSE_LIST.contains(wfxw)) {
                    vehicleViolation.setViolationType(ViolationTypeEnum.MISS_CERT.getCode());
                    vehicleViolation.setMissingCertificateType(MissCertEnum.DRIVE_PERMIT.getCode());
                } else if (VIOLATION_TIME_LIST.contains(wfxw)) {
                    vehicleViolation.setViolationType(ViolationTypeEnum.PERIOD.getCode());
                    int hour = vehicleIllegalTime.getHour();
                    String period = null;
                    if (hour >= TaskContant.Data.VIOLATION_TIME_SEVEN && hour <= TaskContant.Data.VIOLATION_TIME_NINE) {
                        period = TaskContant.Data.VIOLATION_TIME_AM_START + StrPool.DASH
                            + TaskContant.Data.VIOLATION_TIME_AM_END;
                        vehicleViolation.setViolationPeriod(period);
                    } else if (hour >= TaskContant.Data.VIOLATION_TIME_SIXTEEN
                        && hour <= TaskContant.Data.VIOLATION_TIME_EIGHTEEN) {
                        period = TaskContant.Data.VIOLATION_TIME_PM_START + StrPool.DASH
                            + TaskContant.Data.VIOLATION_TIME_PM_END;
                        vehicleViolation.setViolationPeriod(period);
                    }
                } else if (VIOLATION_ROAD_LIST.contains(wfxw)) {
                    vehicleViolation.setViolationType(ViolationTypeEnum.SECTION.getCode());
                    vehicleViolation.setWaySection(wfdz);
                }
                // 获取当事人(驾驶员)
                String driverName = jsonObject.getString("dsr");
                // 根据车牌号获取企业信息
                NdVehicleBaseInfo vehicleBaseInfo = vehiclesCacheHelper.getByCarPlate(hphm);
                Long companyId = vehicleBaseInfo.getCompanyId();
                vehicleBaseInfo.setCompanyId(companyId);
                // 驾驶员姓名和企业名称获取驾驶员信息
                List<DriverInfo> driverInfoList = driverInfoService.list(Wrappers.lambdaQuery(DriverInfo.class)
                    .eq(DriverInfo::getDriverName, driverName).eq(DriverInfo::getCompanyId, companyId));
                if (CollUtil.isEmpty(driverInfoList)) {
                    log.info("该车牌号对应的企业下没有该驾驶员信息");
                } else {
                    // 获取最后一个
                    DriverInfo driverInfo = driverInfoList.get(driverInfoList.size() - 1);
                    vehicleViolation.setDriverId(driverInfo.getId());
                }
                vehicleViolation.setDriverName(driverName);
                vehicleViolationService.save(vehicleViolation);
            }
        }
        return "更新完成";

    }

    private ThreadPoolTaskExecutor getThreadPoolTaskExecutor() {
        return (ThreadPoolTaskExecutor)defaultAsyncTaskConfig.getAsyncExecutor();
    }

    @Async
    @Transactional
    public void accidentQueryDataSave() throws InterruptedException {
        String key = "ACCIDENT_QUERY_DATA_SAVE";
        if (!distributedLock.lock(key, BIG_EXPIRE_TIME)) {
            log.warn("正在执行中：{}", key);
            return;
        }
        try {
            List<String> carPlateList = getAccidentQueryCarPlateList();
            if (CollUtil.isEmpty(carPlateList)) {
                log.info("本月事故数据已更新完成!");
                return;
            }
            // 调用IRS接口,返回数据
            ThreadPoolTaskExecutor executor = getThreadPoolTaskExecutor();
            List<List<String>> partition = ListUtil.partition(carPlateList, GROUP_SIZE);
            CountDownLatch cdl = new CountDownLatch(partition.size());
            List<Future<List<VehicleAccidentIrsData>>> futures = partition.stream().map(w -> executor.submit(() -> {
                List<VehicleAccidentIrsData> tmpList = new ArrayList<>();
                for (String carPlate : w) {
                    try {
                        tmpList.addAll(getVehicleAccidentByCarPlate(carPlate));
                    } catch (Exception e) {
                        log.info("获取车辆违法信息异常：{}", carPlate);
                    }
                }
                cdl.countDown();
                return tmpList;
            })).collect(Collectors.toList());
            cdl.await();
            List<VehicleAccidentIrsData> irsData = collectResultByFutureTasks(futures);
            ListUtil.partition(irsData, GROUP_SIZE).forEach(accidentIrsDataService::saveBatch);
            log.info("共插入了：{} {} 条数据", key, irsData.size());
        } finally {
            distributedLock.releaseLock(key);
        }
    }

    private static <T> List<T> collectResultByFutureTasks(List<Future<List<T>>> futureTasks) {
        List<T> irsData = new ArrayList<>();
        futureTasks.forEach(w -> {
            try {
                irsData.addAll(w.get());
            } catch (Exception e) {
                log.warn("本组数据为空");
            }
        });
        return irsData;
    }

    private List<String> getAccidentQueryCarPlateList() {
        // 获取此次任务要查询的车牌号
        List<String> result = new ArrayList<>();
        List<String> carPlateList;
        String key = TaskContant.RedisKey.ACCIDENT_QUERY_IRS;
        List<String> objectList = redisOps.get(key);
        // 存储的车牌号为空
        if (CollUtil.isEmpty(objectList)) {
            List<String> carPlates = getCarPlates();
            // 将所有车牌号存入redis缓存中
            carPlates.stream().limit(QUERY_SIZE).forEach(result::add);
            if (carPlates.size() > result.size()) {
                carPlates.removeAll(result);
                redisOps.lPush(key, carPlates);
            }
        } else {
            // 每次获取缓存中的2000个车牌号
            List<Object> tmpCarPlates = redisOps.lRange(key, 0, (QUERY_SIZE - 1));
            if (CollUtil.isNotEmpty(tmpCarPlates)) {
                result = CollUtils.convert(tmpCarPlates, Object::toString);
                // 删除取出的数据
                redisOps.lRem(key, 0, result);
            }
        }
        return result;
    }

    private List<String> getVehicleIllegalCarPlateList(List<String> carPlates) {
        // 获取此次任务要查询的车牌号
        List<String> carPlateList = Lists.newArrayList();

        CacheKey cacheKey = new CacheKey(TaskContant.RedisKey.VEHICLE_ILLEGAL_QUERY_IRS, Duration.ofDays(20));
        Object object = redisOps.get(cacheKey, false);
        // key不存在(过期)
        if (Objects.isNull(object)) {
            // 将所有车牌号存入redis缓存中
            redisOps.sAdd(cacheKey, carPlates);
        }

        // 获取redis中的所有数据
        List<Object> objectList = redisOps.lRange(cacheKey.getKey(), 0, -1);

        // key未过期且车牌号已经查询完成
        if (Objects.nonNull(object) && CollUtil.isEmpty(objectList)) {
            return Collections.emptyList();
        } else if (Objects.nonNull(object) && CollUtil.isNotEmpty(objectList)) {
            // 每次获取缓存中的2000个车牌号
            List<Object> range = redisOps.lRange(cacheKey.getKey(), 0, (QUERY_SIZE - 1));
            carPlateList = range.stream().map(Object::toString).collect(Collectors.toList());
            // 去除已经取出的数据,仅保留第2000条之后的数据
            if (objectList.size() > QUERY_SIZE) {
                redisOps.lTrim(cacheKey.getKey(), QUERY_SIZE, -1);
            } else {
                // 数据全部取出后,删除key
                redisOps.del(cacheKey);
            }
        }
        return carPlateList;
    }

    private List<VehicleAccidentIrsData> getVehicleAccidentByCarPlate(String carPlate) {
        String dataJsonStr = accidentService.accidentQuery(carPlate);
        JSONObject object = JSON.parseObject(dataJsonStr, JSONObject.class);
        String data = object.getString("datas");
        List<String> array = JSON.parseArray(data, String.class);
        if (CollUtil.isEmpty(array)) {
            log.info("该车牌号没有事故信息!");
            return Collections.emptyList();
        }
        List<VehicleAccidentIrsData> irsData = new ArrayList<>();
        for (String datas : array) {
            if (StrUtil.isNotBlank(datas)) {
                List<JSONObject> accidentArray = JSON.parseArray(datas, JSONObject.class);
                if (CollUtil.isEmpty(accidentArray)) {
                    log.info("该车牌号没有事故信息!");
                    continue;
                }
                for (JSONObject jsonObject : accidentArray) {
                    VehicleAccidentIrsData accidentIrsData = new VehicleAccidentIrsData();
                    accidentIrsData.setCarPlate(carPlate);
                    accidentIrsData.setJsonStrData(datas);
                    // 获取事故日期
                    Timestamp sgfssj = jsonObject.getTimestamp("SGFSSJ");
                    LocalDateTime accidentTime = LocalDateTimeUtil.of(sgfssj);
                    accidentIrsData.setAccidentTime(accidentTime);
                    accidentIrsData.setCreateOn(LocalDateTime.now());
                    accidentIrsData.setUpdateOn(LocalDateTime.now());
                    irsData.add(accidentIrsData);
                }
            }
        }
        return irsData;
    }

    @Async
    @Transactional
    public void vehicleIllegalDataSave() throws InterruptedException {
        String key = "VEHICLE_ILLEGAL_DATA_SAVE";
        if (!distributedLock.lock(key, BIG_EXPIRE_TIME)) {
            log.warn("正在执行中：{}", key);
            return;
        }
        try {
            // 获取此次任务要查询的车牌号
            List<String> carPlateList = getVehicleIllegalCarPlateList(getCarPlates());
            if (CollUtil.isEmpty(carPlateList)) {
                log.info("本月车辆违法数据已更新完成!");
                return;
            }
            // 调用IRS接口,返回数据
            ThreadPoolTaskExecutor executor = getThreadPoolTaskExecutor();
            List<List<String>> partition = ListUtil.partition(carPlateList, GROUP_SIZE);
            CountDownLatch cdl = new CountDownLatch(partition.size());
            List<Future<List<VehicleViolationIrsData>>> futures = partition.stream().map(w -> executor.submit(() -> {
                List<VehicleViolationIrsData> tmpList = new ArrayList<>();
                for (String carPlate : w) {
                    try {
                        tmpList.addAll(getVehicleIllegalByCarPlate(carPlate));
                    } catch (Exception e) {
                        log.info("获取车辆违法信息异常：{}", carPlate);
                    }
                }
                cdl.countDown();
                return tmpList;
            })).collect(Collectors.toList());
            cdl.await();
            List<VehicleViolationIrsData> irsData = collectResultByFutureTasks(futures);
            ListUtil.partition(irsData, GROUP_SIZE).forEach(violationIrsDataService::saveBatch);
            log.info("共插入了：{} {} 条数据", key, irsData.size());
        } finally {
            distributedLock.releaseLock(key);
        }
    }

    private List<String> getCarPlates() {
        LambdaQueryWrapper<NdVehicleBaseInfo> query = Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
            .select(NdVehicleBaseInfo::getCarPlate).isNotNull(NdVehicleBaseInfo::getCarPlate);
        HashSet<String> carPlateSet = new HashSet<>();
        // 获取去重后的车辆信息
        List<NdVehicleBaseInfo> list = vehicleBaseInfoService.list(query).stream()
            .filter(v -> carPlateSet.add(v.getCarPlate())).collect(Collectors.toList());
        // 获取所有车牌号
        List<String> carPlates = CollUtils.fieldList(list, NdVehicleBaseInfo::getCarPlate);
        return carPlates;
    }

    private List<VehicleViolationIrsData> getVehicleIllegalByCarPlate(String carPlate) {
        String dataJsonStr = carService.vehicleIllegalQuery(carPlate);
        JSONObject object = JSON.parseObject(dataJsonStr, JSONObject.class);
        String data = object.getString("datas");
        List<JSONObject> array = JSON.parseArray(data, JSONObject.class);
        if (CollUtil.isEmpty(array)) {
            log.info("该车牌号没有违法行为信息!");
            return Collections.emptyList();
        }
        List<VehicleViolationIrsData> irsData = new ArrayList<>();
        for (JSONObject jsonObject : array) {
            if (Objects.nonNull(jsonObject)) {
                VehicleViolationIrsData vid = new VehicleViolationIrsData();
                vid.setCarPlate(carPlate);
                // 获取违法日期
                Timestamp wfsj = jsonObject.getTimestamp("wfsj");
                LocalDateTime vehicleIllegalTime = LocalDateTimeUtil.of(wfsj);
                vid.setViolationTime(vehicleIllegalTime);
                vid.setJsonStrData(data);
                String wfxw = jsonObject.getString("wfxw");
                vid.setViolationType(wfxw);
                String cfzl = jsonObject.getString("cfzl");
                vid.setViolationKind(cfzl);
                vid.setCreateOn(LocalDateTime.now());
                vid.setUpdateOn(LocalDateTime.now());
                irsData.add(vid);
            }
        }
        return irsData;
    }

    public void accidentQueryDataSingleSave() {
        List<String> carPlateList = getAccidentQueryCarPlateList();
        if (CollUtil.isEmpty(carPlateList)) {
            log.info("本月事故数据已更新完成!");
            return;
        }

        // 调用IRS接口,返回数据
        // 访问计数
        int count = 0;
        for (String carPlate : carPlateList) {
            String dataJsonStr = accidentService.accidentQuery(carPlate);
            count++;
            log.info("已访问事故查询IRS接口 {} 次", count);
            JSONObject object = JSON.parseObject(dataJsonStr, JSONObject.class);
            String data = object.getString("datas");
            List<String> array = JSON.parseArray(data, String.class);
            if (CollUtil.isEmpty(array)) {
                log.info("该车牌号没有事故信息!");
                continue;
            }
            // 获取车牌号的所有事故信息
            Map<String, List<VehicleAccidentIrsData>> accidentIrsDataMap = accidentIrsDataService.list().stream()
                .collect(Collectors.groupingBy(VehicleAccidentIrsData::getCarPlate));
            for (String datas : array) {
                if (StrUtil.isNotBlank(datas)) {
                    List<JSONObject> accidentArray = JSON.parseArray(datas, JSONObject.class);
                    if (CollUtil.isEmpty(accidentArray)) {
                        log.info("该车牌号没有事故信息!");
                        continue;
                    }

                    for (JSONObject jsonObject : accidentArray) {
                        VehicleAccidentIrsData accidentIrsData = new VehicleAccidentIrsData();
                        accidentIrsData.setCarPlate(carPlate);
                        accidentIrsData.setJsonStrData(datas);
                        // 获取事故日期
                        Timestamp sgfssj = jsonObject.getTimestamp("SGFSSJ");
                        LocalDateTime accidentTime = LocalDateTimeUtil.of(sgfssj);
                        if (accidentIrsDataMap.containsKey(carPlate)) {
                            List<VehicleAccidentIrsData> dataList = accidentIrsDataMap.get(carPlate);
                            Map<LocalDateTime, VehicleAccidentIrsData> dataMap = dataList.stream()
                                .collect(Collectors.toMap(VehicleAccidentIrsData::getAccidentTime, v -> v));
                            if (dataMap.containsKey(accidentTime)) {
                                VehicleAccidentIrsData irsData = dataMap.get(accidentTime);
                                // 数据已经存在
                                accidentIrsData.setId(irsData.getId());
                            }
                        }
                        accidentIrsData.setAccidentTime(accidentTime);
                        accidentIrsData.setCreateOn(LocalDateTime.now());
                        accidentIrsData.setUpdateOn(LocalDateTime.now());
                        accidentIrsDataService.saveOrUpdate(accidentIrsData);
                    }
                }
            }
        }
    }

    public void singleSave() throws FileNotFoundException {

        List<String> list = new ArrayList<>();
        Set<String> set = new HashSet<>();

        File directory = new File("");
        //临时文件存储路径
        String filePath = directory.getAbsolutePath() + File.separator + "irs";
        File f = new File( filePath +  File.separator +  "事故查询车牌号.xlsx");
        Workbook wb = readExcel(new FileInputStream(f), f.getName());
        Row row = null;
        if (wb != null) {
            //获取第一个sheet
            Sheet sheet = wb.getSheetAt(0);
            //获取最大行数
            int rownum = sheet.getPhysicalNumberOfRows();
            //获取第一行
            row = sheet.getRow(0);

            //获取最大列数
            for (int i = 1; i < rownum; i++) {
                row = sheet.getRow(i);
                // 车牌号
                String carPlate = Objects.nonNull(row.getCell(0)) ? row.getCell(0).toString() : StringUtils.EMPTY;
                list.add(carPlate);
            }
        }

        // 去重
        List<String> carPlateList = list.stream()
                .filter(set::add)
                .collect(Collectors.toList());

        // 调用IRS接口,返回数据
        // 访问计数
        int count = 0;
        for (String carPlate : carPlateList) {
            String dataJsonStr = accidentService.accidentQuery(carPlate);
            count++;
            log.info("已访问事故查询IRS接口 {} 次", count);
            log.info("此次访问的事故车牌号为 {}",carPlate);
            JSONObject object = JSON.parseObject(dataJsonStr, JSONObject.class);
            String data = object.getString("datas");
            List<String> array = JSON.parseArray(data, String.class);
            if (CollUtil.isEmpty(array)) {
                log.info("该车牌号没有事故信息!");
                continue;
            }
            // 获取车牌号的所有事故信息
            Map<String, List<VehicleAccidentIrsData>> accidentIrsDataMap = accidentIrsDataService.list().stream()
                    .collect(Collectors.groupingBy(VehicleAccidentIrsData::getCarPlate));
            for (String datas : array) {
                if (StrUtil.isNotBlank(datas)) {
                    List<JSONObject> accidentArray = JSON.parseArray(datas, JSONObject.class);
                    if (CollUtil.isEmpty(accidentArray)) {
                        log.info("该车牌号没有事故信息!");
                        continue;
                    }

                    for (JSONObject jsonObject : accidentArray) {
                        VehicleAccidentIrsData accidentIrsData = new VehicleAccidentIrsData();
                        accidentIrsData.setCarPlate(carPlate);
                        String jsonString = jsonObject.toJSONString();
                        accidentIrsData.setJsonStrData(jsonString);
                        // 获取事故日期
                        Timestamp sgfssj = jsonObject.getTimestamp("SGFSSJ");
                        LocalDateTime accidentTime = LocalDateTimeUtil.of(sgfssj);

                        if (accidentIrsDataMap.containsKey(carPlate)) {
                            List<VehicleAccidentIrsData> dataList = accidentIrsDataMap.get(carPlate);
                            Map<String, VehicleAccidentIrsData> dataMap = dataList.stream()
                                    .collect(Collectors.toMap(v -> v.getCarPlate() + v.getAccidentTime(),v -> v));
                            String key = accidentTime + carPlate;
                            if (dataMap.containsKey(key)) {
                                VehicleAccidentIrsData irsData = dataMap.get(key);
                                // 数据已经存在
                                accidentIrsData.setId(irsData.getId());
                            }
                        }
                        accidentIrsData.setAccidentTime(accidentTime);
                        accidentIrsData.setCreateOn(LocalDateTime.now());
                        accidentIrsData.setUpdateOn(LocalDateTime.now());
                        accidentIrsDataService.saveOrUpdate(accidentIrsData);
                    }
                }
            }
        }
    }

    //这个下面是单独函数
    public static Workbook readExcel(InputStream is, String extString) {
        Workbook wb = null;
        extString = extString.substring(extString.lastIndexOf("."));
        try {
            if (".xls".equals(extString)) {
                return wb = new HSSFWorkbook(is);
            } else if (".xlsx".equals(extString)) {
                return wb = new XSSFWorkbook(is);
            } else {
                return wb = null;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return wb;
    }

    public void illegalDataSingleSave() throws FileNotFoundException {
        List<String> list = new ArrayList<>();
        Set<String> set = new HashSet<>();

        File directory = new File("");
        //临时文件存储路径
        String filePath = directory.getAbsolutePath() + File.separator + "irs";
        File f = new File( filePath +  File.separator +  "车辆违法车牌号.xlsx");
        Workbook wb = readExcel(new FileInputStream(f), f.getName());
        Row row = null;
        if (wb != null) {
            //获取第一个sheet
            Sheet sheet = wb.getSheetAt(0);
            //获取最大行数
            int rownum = sheet.getPhysicalNumberOfRows();
            //获取第一行
            row = sheet.getRow(0);

            //获取最大列数
            for (int i = 1; i < rownum; i++) {
                row = sheet.getRow(i);
                // 车牌号
                String carPlate = Objects.nonNull(row.getCell(0)) ? row.getCell(0).toString() : StringUtils.EMPTY;
                list.add(carPlate);
            }
        }

        // 去重
        List<String> carPlateList = list.stream()
                .filter(set::add)
                .collect(Collectors.toList());

        // 调用IRS接口,返回数据
        // 访问计数
        int count = 0;
        for (String carPlate : carPlateList) {
            String dataJsonStr = carService.vehicleIllegalQuery(carPlate);
            log.info("获取到的数据为:" + dataJsonStr);
            count++;
            log.info("已访问车辆违法查询IRS接口 {} 次", count);
            log.info("此次访问的违法车牌号为 {}",carPlate);
            JSONObject object = JSON.parseObject(dataJsonStr, JSONObject.class);
            String data = object.getString("datas");
            log.info("data为：" + data);
            List<JSONObject> array = JSON.parseArray(data, JSONObject.class);
            if (CollUtil.isEmpty(array)) {
                log.info("该车牌号没有违法行为信息!");
                continue;
            }
            // 获取车牌号的所有违章信息
            Map<String, List<VehicleViolationIrsData>> violationIrsDataMap = violationIrsDataService.list().stream()
                    .collect(Collectors.groupingBy(VehicleViolationIrsData::getCarPlate));

            for (JSONObject jsonObject : array) {
                if (Objects.nonNull(jsonObject)) {
                    VehicleViolationIrsData vid = new VehicleViolationIrsData();
                    vid.setCarPlate(carPlate);
                    // 获取违法日期
                    Timestamp wfsj = jsonObject.getTimestamp("wfsj");
                    LocalDateTime vehicleIllegalTime = LocalDateTimeUtil.of(wfsj);

                    String wfxw = jsonObject.getString("wfxw");
                    vid.setViolationType(wfxw);

                    if (violationIrsDataMap.containsKey(carPlate)) {
                        List<VehicleViolationIrsData> dataList = violationIrsDataMap.get(carPlate);
                        // 对集合进行去重
                        HashSet<String> hashSet = new HashSet<>();
                        List<VehicleViolationIrsData> violationIrsDataList = dataList.stream()
                                .filter(d -> hashSet.add(d.getCarPlate() + d.getViolationTime() + d.getViolationType()))
                                .collect(Collectors.toList());
                        Map<String, VehicleViolationIrsData> dataMap = violationIrsDataList.stream()
                                .collect(Collectors.toMap(v -> v.getCarPlate() + v.getViolationTime() + v.getViolationType(),v -> v));
                        String key = carPlate + vehicleIllegalTime + wfxw;
                        if (dataMap.containsKey(key)) {
                            VehicleViolationIrsData irsData = dataMap.get(key);
                            // 数据已经存在
                            vid.setId(irsData.getId());
                        }
                    }
                    vid.setViolationTime(vehicleIllegalTime);
                    String jsonStr = jsonObject.toJSONString();
                    vid.setJsonStrData(jsonStr);
                    String cfzl = jsonObject.getString("cfzl");
                    vid.setViolationKind(cfzl);
                    vid.setCreateOn(LocalDateTime.now());
                    vid.setUpdateOn(LocalDateTime.now());
                    violationIrsDataService.saveOrUpdate(vid);
                }
            }
        }
    }

    // 保存不重复的车牌号到数据库中
    public void carPlateSave() {
        LambdaQueryWrapper<NdVehicleBaseInfo> query = Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
                .select(NdVehicleBaseInfo::getCarPlate).isNotNull(NdVehicleBaseInfo::getCarPlate);
        HashSet<String> carPlateSet = new HashSet<>();
        // 获取去重后的车辆信息
        List<NdVehicleBaseInfo> list = vehicleBaseInfoService.list(query).stream()
                .filter(v -> carPlateSet.add(v.getCarPlate())).collect(Collectors.toList());
        // 获取所有车牌号
        List<String> carPlates = CollUtils.fieldList(list, NdVehicleBaseInfo::getCarPlate);

        List<IrsTempCarplate> tempList = carPlates.stream().map(c -> {
            IrsTempCarplate tempCarPlate = new IrsTempCarplate();
            tempCarPlate.setCarPlate(c);
            return tempCarPlate;
        }).collect(Collectors.toList());
        irsTempCarplateService.saveBatch(tempList);
    }


    // 日志分析
    public void logSave() {
        // 关键词
        String keyword = "此次访问的车牌号为";

        try (BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\CMM\\Desktop\\0515\\info.log"));
             BufferedWriter writer = new BufferedWriter(new FileWriter("C:\\Users\\CMM\\Desktop\\0515\\output.log"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.matches(".*" + keyword + ".*")) {
                    // 获取指定内容在行中的起始位置
                    int startIndex = line.indexOf("为");
                    // 截取指定内容及其后面的内容
                    String extractedContent = line.substring(startIndex + 1);
                    // 将截取的内容写入输出文件
                    writer.write(extractedContent);
                    // 换行
                    writer.newLine();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        //// 关键词
        //String keyword = "此次访问的违法车牌号为";
        //
        //try (BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\CMM\\Desktop\\水泥车数据初始化\\0517\\info.log"));
        //     BufferedWriter writer = new BufferedWriter(new FileWriter("C:\\Users\\CMM\\Desktop\\水泥车数据初始化\\0517\\output.log"))) {
        //    String line;
        //    while ((line = reader.readLine()) != null) {
        //        if (line.matches(".*" + keyword + ".*")) {
        //            // 获取指定内容在行中的起始位置
        //            int startIndex = line.indexOf("为");
        //            // 截取指定内容及其后面的内容
        //            String extractedContent = line.substring(startIndex + 1);
        //            // 将截取的内容写入输出文件
        //            writer.write(extractedContent);
        //            // 换行
        //            writer.newLine();
        //        }
        //    }
        //} catch (IOException e) {
        //    e.printStackTrace();
        //}
        LocalDateTime startTime = LocalDateTimeUtil.parse(NdDateUtils.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_MINUTE_PATTERN));
        LocalDateTime endTime = LocalDateTimeUtil.parse(NdDateUtils.format(LocalDateTime.now().plusMinutes(1), DatePattern.NORM_DATETIME_MINUTE_PATTERN), DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_MINUTE_PATTERN));
        System.out.println(startTime);
        System.out.println(endTime);

    }

    /**
     * 从IRS事故数据表中更新数据到车辆事故数据表中
     * @return void
     * @author CMM
     * @since 2023/05/16 10:26
     */
    public void updateAccidentData() {

        // 从IRS事故数据表中更新数据到车辆事故数据表中
        Map<String, List<VehicleAccidentIrsData>> listMap =
                accidentIrsDataService.list().stream().collect(Collectors.groupingBy(VehicleAccidentIrsData::getCarPlate));

        // 获取车牌号
        Set<String> carPlateList =
                accidentIrsDataService.list().stream().map(VehicleAccidentIrsData::getCarPlate).collect(Collectors.toSet());

        // 获取车辆基本信息
        List<NdVehicleBaseInfo> vehicleBaseInfos = vehicleBaseInfoService
                .list(Wrappers.lambdaQuery(NdVehicleBaseInfo.class).in(NdVehicleBaseInfo::getCarPlate, carPlateList));
        Map<String, NdVehicleBaseInfo> vehicleBaseInfoMap =
                vehicleBaseInfos.stream().collect(Collectors.toMap(NdVehicleBaseInfo::getCarPlate, v -> v));

        // 获取企业信息
        Map<Long, Company> companyMap =
                companyService.list().stream().collect(Collectors.toMap(Company::getId, c -> c));

        // 获取已经存在的事故数据
        List<NdVehicleAccident> accidentTmpVas = vehicleAccidentService
                .list(Wrappers.lambdaQuery(NdVehicleAccident.class).in(NdVehicleAccident::getCarPlate, carPlateList));
        Map<String, NdVehicleAccident> accidentMap = accidentTmpVas.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(
                                Comparator.comparing(a -> a.getCarPlate() + StrPool.SEMICOLON + a.getAccidentTime()))),
                        ArrayList::new))
                .stream().collect(Collectors.toMap(d -> d.getCarPlate() + d.getAccidentTime(), d -> d));

        // 获取已经存在的死亡事故数据
        List<NdVehicleAccidentDead> deadAccidentTmpVas = vehicleAccidentDeadService.list(
                Wrappers.lambdaQuery(NdVehicleAccidentDead.class).in(NdVehicleAccidentDead::getCarPlate, carPlateList));
        Map<String, NdVehicleAccidentDead> deadAccidentMap = deadAccidentTmpVas.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(
                                Comparator.comparing(a -> a.getCarPlate() + StrPool.SEMICOLON + a.getAccidentTime()))),
                        ArrayList::new))
                .stream().collect(Collectors.toMap(d -> d.getCarPlate() + d.getAccidentTime(), d -> d));

        for (String carPlate : carPlateList) {
            NdVehicleBaseInfo vehicleBaseInfo = vehicleBaseInfoMap.get(carPlate);

            //if (Objects.isNull(vehicleBaseInfo)) {
            //    log.info("该车牌号不在系统中!");
            //    continue;
            //}
            //// 查出对应车牌号关联的责任驾驶员
            // String driverName = vehicleBaseInfo.getResponsibleDriverFirst();
            //
            // if (Objects.isNull(driverName)) {
            // log.info("该车牌号没有责任驾驶员!");
            // continue;
            // }

            Long companyId = null;
            Company company = null;
            if (Objects.nonNull(vehicleBaseInfo)) {
                companyId = vehicleBaseInfo.getCompanyId();
                company = companyMap.get(companyId);
            }

            // 获取IRS事故数据
            List<VehicleAccidentIrsData> accidentIrsDataList = listMap.get(carPlate);

            for (VehicleAccidentIrsData accidentIrsData : accidentIrsDataList) {
                // 解析获取事故时间等信息
                String jsonStrData = accidentIrsData.getJsonStrData();
                JSONObject jsonObject = JSON.parseObject(jsonStrData);

                // 获取行政区划
                String xzqh = jsonObject.getString("XZQH");
                // 获取区域信息
                Long regionId = regionsCacheHelper.getIdByCode(xzqh);
                String regionName = regionsCacheHelper.getDisplayName(regionId);
                // 获取事故地点
                String sgdd = jsonObject.getString("SGDD");
                // 获取车辆类型
                Integer vehicleType = null;
                if (Objects.nonNull(vehicleBaseInfo)) {
                    vehicleType = vehicleBaseInfo.getVehicleType();
                }
                // 获取受伤人数
                Integer ssrs = jsonObject.getInteger("SSRS");
                // 获取事故日期
                Timestamp sgfssj = jsonObject.getTimestamp("SGFSSJ");
                LocalDateTime accidentTime = LocalDateTimeUtil.of(sgfssj);
                // 获取简要案情
                String jyaq = jsonObject.getString("JYAQ");
                // 获取事故编号
                String sgbh = jsonObject.getString("SGBH");
                // 获取经纬度电子坐标
                String dzzb = jsonObject.getString("DZZB");
                String longitude = null;
                String latitude = null;
                if (StringUtils.isNotBlank(dzzb) && dzzb.contains(StrPool.COMMA)) {
                    String[] split = dzzb.split(StrPool.COMMA);
                    Double longitudeD = Double.valueOf(split[0]);
                    Double latitudeD = Double.valueOf(split[1]);
                    DecimalFormat df = new DecimalFormat("#.###");
                    longitude = df.format(longitudeD);
                    latitude = df.format(latitudeD);
                } else {
                    // 交管事故数据未上传经纬度坐标，从当天的GPS数据中根据车牌号和事故时间查询经纬度
                    LocalDateTime startTime = LocalDateTimeUtil.parse(
                            NdDateUtils.format(accidentTime, DatePattern.NORM_DATETIME_MINUTE_PATTERN),
                            DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_MINUTE_PATTERN));
                    LocalDateTime endTime = LocalDateTimeUtil.parse(
                            NdDateUtils.format(accidentTime.plusMinutes(1), DatePattern.NORM_DATETIME_MINUTE_PATTERN),
                            DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_MINUTE_PATTERN));
                    // 如果跨天了就设置相同地查询边界
                    if (!NdDateUtils.format(startTime, DatePattern.NORM_DATE_PATTERN)
                            .equals(NdDateUtils.format(endTime, DatePattern.NORM_DATE_PATTERN))) {
                        endTime = startTime;
                    }

                    List<VehiclePositionInfo> vehiclePositionInfos;
                    try {
                        vehiclePositionInfos = iVehiclePositionInfoService.dynamicGpsTableHistorySearch(carPlate,
                                accidentTime, endTime, NdDateUtils.format(startTime, "yyyy_MM_dd"));
                        if (CollUtil.isNotEmpty(vehiclePositionInfos)) {
                            VehiclePositionInfo positionInfo;
                            List<VehiclePositionInfo> positionInfoList = vehiclePositionInfos.stream()
                                    .filter(v -> v.getUpdateTime().equals(accidentTime)).collect(Collectors.toList());
                            if (CollUtil.isNotEmpty(positionInfoList)) {
                                positionInfo = positionInfoList.get(0);
                            } else {
                                // 没有时间完全一样的GPS数据，就取第一个
                                positionInfo = vehiclePositionInfos.get(0);
                            }
                            longitude = String.valueOf(positionInfo.getCarLongitude());
                            latitude = String.valueOf(positionInfo.getCarLatitude());
                        }
                    } catch (Exception e) {
                        // GPS数据中查询不到数据(GPS表可能被删除)
                        log.error(e.getMessage());
                    }
                }

                // 获取当场、24小时、3日内、7日内、30日内死亡人数
                Integer swrs = Objects.nonNull(jsonObject.getInteger("SWRS")) ? jsonObject.getInteger("SWRS") : 0;
                Integer swrs24 = Objects.nonNull(jsonObject.getInteger("SWRS24")) ? jsonObject.getInteger("SWRS24") : 0;
                Integer swrs3 = Objects.nonNull(jsonObject.getInteger("SWRS3")) ? jsonObject.getInteger("SWRS3") : 0;
                Integer swrs7 = Objects.nonNull(jsonObject.getInteger("SWRS7")) ? jsonObject.getInteger("SWRS7") : 0;
                Integer swrs30 = Objects.nonNull(jsonObject.getInteger("SWRS30")) ? jsonObject.getInteger("SWRS30") : 0;
                // 有死亡人数,再插入到死亡事故表中
                if (swrs != 0 || swrs24 != 0 || swrs3 != 0 || swrs7 != 0 || swrs30 != 0) {
                    // 插入数据到死亡事故表中
                    NdVehicleAccidentDead accidentDead = new NdVehicleAccidentDead();
                    // 判断是否已经插入过
                    if (deadAccidentMap.containsKey(carPlate + accidentTime)) {
                        NdVehicleAccidentDead dead = deadAccidentMap.get(carPlate + accidentTime);
                        accidentDead.setId(dead.getId());
                    }
                    if (swrs30 != 0) {
                        accidentDead.setDeathToll(swrs30);
                    } else if (swrs7 != 0) {
                        accidentDead.setDeathToll(swrs7);
                    } else if (swrs3 != 0) {
                        accidentDead.setDeathToll(swrs3);
                    } else if (swrs24 != 0) {
                        accidentDead.setDeathToll(swrs24);
                    } else {
                        accidentDead.setDeathToll(swrs);
                    }
                    accidentDead.setInjuries(ssrs);
                    accidentDead.setRegionId(regionId);
                    accidentDead.setRegionName(regionName);
                    // 获取事故时间
                    accidentDead.setAccidentTime(accidentTime);
                    accidentDead.setAccidentAddress(sgdd);
                    // 装配车牌号、事故驾驶员、企业名称
                    accidentDead.setCarPlate(carPlate);
                    // accidentDead.setAccidentDriver(driverName);
                    accidentDead.setCompanyId(companyId);
                    if (Objects.nonNull(company)) {
                        accidentDead.setCompanyName(company.getName());
                    }
                    // 是否上报默认为未上报
                    accidentDead.setReportStatus(VehicleAccidentReportStatusEnum.UNDER_REPORT.getCode());
                    accidentDead.setBriefCase(jyaq);
                    accidentDead.setAccidentNo(sgbh);
                    accidentDead.setLongitude(longitude);
                    accidentDead.setLatitude(latitude);
                    vehicleAccidentDeadService.saveOrUpdate(accidentDead);
                }
                // 插入到事故表中
                NdVehicleAccident accident = new NdVehicleAccident();
                // 判断事故类型
                if (swrs != 0 || swrs24 != 0 || swrs3 != 0 || swrs7 != 0 || swrs30 != 0){
                    accident.setAccidentType(AccidentTypeEnum.DEAD.getCode());
                } else if (Objects.nonNull(ssrs) && ssrs > 0) {
                    accident.setAccidentType(AccidentTypeEnum.INJURY.getCode());
                }else {
                    accident.setAccidentType(AccidentTypeEnum.OTHER.getCode());
                }
                // 获取已经存在的事故信息
                NdVehicleAccident vehicleAccident = accidentMap.get(carPlate + accidentTime);
                // 获取事故时间
                if (accidentMap.containsKey(carPlate + accidentTime)) {
                    accident.setId(vehicleAccident.getId());
                }
                accident.setInjuries(ssrs);
                if (swrs30 != 0) {
                    accident.setDeathToll(swrs30);
                } else if (swrs7 != 0) {
                    accident.setDeathToll(swrs7);
                } else if (swrs3 != 0) {
                    accident.setDeathToll(swrs3);
                } else if (swrs24 != 0) {
                    accident.setDeathToll(swrs24);
                } else {
                    accident.setDeathToll(swrs);
                }
                accident.setRegionId(regionId);
                accident.setRegionName(regionName);
                // 获取事故时间
                accident.setAccidentTime(accidentTime);
                accident.setAccidentAddress(sgdd);
                // 装配车牌号、事故驾驶员、车辆类型、企业名称
                accident.setCarPlate(carPlate);

                // accident.setAccidentDriver(driverName);
                accident.setVehicleType(vehicleType);
                accident.setCompanyId(companyId);
                if (Objects.nonNull(company)) {
                    accident.setCompanyName(company.getName());
                }
                // 是否上报默认为未上报
                accident.setReportStatus(VehicleAccidentReportStatusEnum.UNDER_REPORT.getCode());
                accident.setBriefCase(jyaq);
                accident.setAccidentNo(sgbh);
                accident.setLongitude(longitude);
                accident.setLatitude(latitude);
                vehicleAccidentService.saveOrUpdate(accident);
            }
        }
        log.info("事故数据更新完成!");
    }

    public void updateViolationData() {
        Map<Long, String> map = violationIrsDataService
                .list(Wrappers.lambdaQuery(VehicleViolationIrsData.class)
                        .select(VehicleViolationIrsData::getId, VehicleViolationIrsData::getViolationType))
                .stream()
                .collect(Collectors.toMap(VehicleViolationIrsData::getId, VehicleViolationIrsData::getViolationType));

        List<Long> violationIdList = map.keySet().stream().filter(c -> {
            String type = map.get(c);
            return NO_DRIVING_LICENSE_LIST.contains(type) || NO_VEHICLE_LICENSE_LIST.contains(type)
                    || VIOLATION_TRAFFIC_LIGHTS_LIST.contains(type) || VIOLATION_TIME_LIST.contains(type)
                    || VIOLATION_ROAD_LIST.contains(type);
        }).collect(Collectors.toList());

        // 获取需要更新的数据
        Map<String, List<VehicleViolationIrsData>> listMap =
                violationIrsDataService.list(Wrappers.lambdaQuery(VehicleViolationIrsData.class)
                                .select(VehicleViolationIrsData::getId,VehicleViolationIrsData::getCarPlate,
                                        VehicleViolationIrsData::getJsonStrData))
                        .stream().filter(v -> violationIdList.contains(v.getId()))
                        .collect(Collectors.groupingBy(VehicleViolationIrsData::getCarPlate));

        // 获取车牌号
        Set<String> carPlateList = listMap.keySet();
        // 过滤掉不在系统中的车牌号
        List<NdVehicleBaseInfo> carPlates = vehicleBaseInfoService.list(Wrappers.lambdaQuery(NdVehicleBaseInfo.class).select(NdVehicleBaseInfo::getCarPlate));
        List<String> carPlateLists = carPlateList.stream().filter(carPlates::contains).collect(Collectors.toList());
        // 违章数据的车牌号都不在系统中，不需要更新
        if (CollUtil.isEmpty(carPlateLists)){
            log.info("没有需要更新的数据!");
            return;
        }
        // 获取车辆基本信息
        List<NdVehicleBaseInfo> vehicleBaseInfos = vehicleBaseInfoService
                .list(Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
                        .select(NdVehicleBaseInfo::getCarPlate,NdVehicleBaseInfo::getCompanyId)
                        .in(NdVehicleBaseInfo::getCarPlate, carPlateLists));
        Map<String, NdVehicleBaseInfo> vehicleBaseInfoMap =
                vehicleBaseInfos.stream().collect(Collectors.toMap(NdVehicleBaseInfo::getCarPlate, v -> v));

        // 获取企业信息
        Map<Long, Company> companyMap =
                companyService.list().stream().collect(Collectors.toMap(Company::getId, c -> c));

        // 获取已经存在的违章数据
        List<NdVehicleViolation> violationTmpVas = vehicleViolationService
                .list(Wrappers.lambdaQuery(NdVehicleViolation.class).in(NdVehicleViolation::getCarPlate, carPlateLists));
        Map<String, NdVehicleViolation> violationMap = violationTmpVas.stream()
                .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(a -> a.getCarPlate()
                        + StrPool.SEMICOLON + a.getViolationDate() + StrPool.SEMICOLON + a.getViolationType()))), ArrayList::new))
                .stream().collect(Collectors.toMap(d -> d.getCarPlate() + d.getViolationDate() + d.getViolationType() + d.getViolationAddress(), d -> d));

        for (String carPlate : carPlateLists) {
            NdVehicleBaseInfo vehicleBaseInfo = vehicleBaseInfoMap.get(carPlate);

            Long companyId = vehicleBaseInfo.getCompanyId();
            Company company = null;
            if (Objects.nonNull(companyId)) {
                company = companyMap.get(companyId);
            }

            // 获取IRS违章数据
            List<VehicleViolationIrsData> violationIrsDataList = listMap.get(carPlate);

            for (VehicleViolationIrsData violationIrsData : violationIrsDataList) {

                // 解析获取事故时间等信息
                String jsonStrData = violationIrsData.getJsonStrData();
                JSONObject jsonObject = JSON.parseObject(jsonStrData);

                NdVehicleViolation vehicleViolation = new NdVehicleViolation();

                // 获取违法日期
                Timestamp wfsj = jsonObject.getTimestamp("wfsj");
                LocalDateTime vehicleIllegalTime = LocalDateTimeUtil.of(wfsj);
                vehicleViolation.setViolationDate(vehicleIllegalTime);
                // 获取违法地址
                String wfdz = jsonObject.getString("wfdz");
                // 获取违法行为
                String wfxw = jsonObject.getString("wfxw");
                // 获取违法编号
                String wfbh = jsonObject.getString("wfbh");

                // 获取经纬度
                String longitude = jsonObject.getString("jd");
                String latitude = jsonObject.getString("wd");

                // 判断是否已经插入过
                String key = carPlate + vehicleIllegalTime + wfdz + wfxw;
                if (violationMap.containsKey(key)) {
                    NdVehicleViolation violation = violationMap.get(key);
                    vehicleViolation.setId(violation.getId());
                }
                vehicleViolation.setCarPlate(carPlate);
                // 获取行政区划
                String xzqh = jsonObject.getString("xzqh");
                // 获取区域信息
                Long regionId = regionsCacheHelper.getIdByCode(xzqh);
                String regionName = regionsCacheHelper.getDisplayName(regionId);
                vehicleViolation.setRegionId(regionId);
                vehicleViolation.setRegionName(regionName);
                // 如果是闯红灯
                if (VIOLATION_TRAFFIC_LIGHTS_LIST.contains(wfxw)) {
                    vehicleViolation.setViolationType(ViolationTypeEnum.RED_LIGHT.getCode());
                    vehicleViolation.setAddressRedLight(wfdz);
                } else if (NO_DRIVING_LICENSE_LIST.contains(wfxw)) {
                    vehicleViolation.setViolationType(ViolationTypeEnum.MISS_CERT.getCode());
                    vehicleViolation.setMissingCertificateType(MissCertEnum.DRIVER_LINCENSE.getCode());
                } else if (NO_VEHICLE_LICENSE_LIST.contains(wfxw)) {
                    vehicleViolation.setViolationType(ViolationTypeEnum.MISS_CERT.getCode());
                    vehicleViolation.setMissingCertificateType(MissCertEnum.DRIVE_PERMIT.getCode());
                } else if (VIOLATION_TIME_LIST.contains(wfxw)) {
                    vehicleViolation.setViolationType(ViolationTypeEnum.PERIOD.getCode());
                    int hour = vehicleIllegalTime.getHour();
                    int minute = vehicleIllegalTime.getMinute();
                    String period = null;
                    // 时间段暂时设置为违章时间所在小时的前后半小时
                    if (minute < 30) {
                        period = vehicleIllegalTime.minusHours(1).getHour() + TaskContant.Data.VIOLATION_TIME_HALF
                                + StrPool.DASH + hour + TaskContant.Data.VIOLATION_TIME_HALF;
                    } else {
                        period = hour + TaskContant.Data.VIOLATION_TIME_START + StrPool.DASH
                                + vehicleIllegalTime.plusHours(1).getHour() + TaskContant.Data.VIOLATION_TIME_START;
                    }
                    vehicleViolation.setViolationPeriod(period);
                    // if (hour >= TaskContant.Data.VIOLATION_TIME_SEVEN && hour <=
                    // TaskContant.Data.VIOLATION_TIME_NINE) {
                    // period = TaskContant.Data.VIOLATION_TIME_AM_START + StrPool.DASH
                    // + TaskContant.Data.VIOLATION_TIME_AM_END;
                    // vehicleViolation.setViolationPeriod(period);
                    // } else if (hour >= TaskContant.Data.VIOLATION_TIME_SIXTEEN
                    // && hour <= TaskContant.Data.VIOLATION_TIME_EIGHTEEN) {
                    // period = TaskContant.Data.VIOLATION_TIME_PM_START + StrPool.DASH
                    // + TaskContant.Data.VIOLATION_TIME_PM_END;
                    // vehicleViolation.setViolationPeriod(period);
                    // }
                } else if (VIOLATION_ROAD_LIST.contains(wfxw)) {
                    vehicleViolation.setViolationType(ViolationTypeEnum.SECTION.getCode());
                    vehicleViolation.setWaySection(wfdz);
                }
                // 获取当事人(驾驶员)
                String driverName = jsonObject.getString("dsr");

                vehicleViolation.setCompanyId(companyId);
                if (Objects.nonNull(company)) {
                    vehicleViolation.setCompanyName(company.getName());
                }
                // 驾驶员姓名和企业名称获取驾驶员信息
                List<DriverInfo> driverInfoList = driverInfoService.list(Wrappers.lambdaQuery(DriverInfo.class)
                        .eq(DriverInfo::getDriverName, driverName).eq(DriverInfo::getCompanyId, companyId));
                if (CollUtil.isEmpty(driverInfoList)) {
                    log.info("该车牌号对应的企业下没有该驾驶员信息");
                } else {
                    // 获取最后一个
                    DriverInfo driverInfo = driverInfoList.get(driverInfoList.size() - 1);
                    vehicleViolation.setDriverId(driverInfo.getId());
                }
                vehicleViolation.setDriverName(driverName);
                vehicleViolation.setLongitude(longitude);
                vehicleViolation.setLatitude(latitude);
                vehicleViolation.setViolationNo(wfbh);
                vehicleViolation.setViolationAddress(wfdz);
                vehicleViolationService.saveOrUpdate(vehicleViolation);
            }
        }
        log.info("违章数据更新完成!");
    }
}
