package com.ningdatech.carapi.irs.task;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import org.springframework.stereotype.Component;

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.carapi.car.vehicle.model.NdVehicleBaseInfo;
import com.ningdatech.carapi.car.vehicle.service.IVehicleBaseInfoService;
import com.ningdatech.carapi.irs.entity.DriversLicenseRaw;
import com.ningdatech.carapi.irs.service.DriverService;
import com.ningdatech.carapi.irs.service.IDriversLicenseRawService;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.io.FileUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * @author CMM
 * @description
 * @since 2023/05/21 15:38
 */
@Component
@Slf4j
@Data
public class MyVehicleLicenseQueryTask implements Runnable {

    private final DriverService driverService;
    private final IVehicleBaseInfoService vehicleBaseInfoService;
    private final IDriversLicenseRawService driversLicenseRawService;

    /**
     * 接口访问次数限制
     */
    private Integer BIGGEST_ACCESS_NUM = 95;
    /**
     * 存储数据下标的文件名
     */
    private String ACCIDENT_QUERY_INDEX_FILE = "vehicleLicenseIndex.txt";
    /**
     * 上次中断的驾驶员下标
     */
    private Long lastIndex = 0L;
    /**
     * 上次执行的次数
     */
    private Integer lastCount = 0;
    /**
     * 是否继续执行任务
     */
    private boolean isRunning = true;

    public MyVehicleLicenseQueryTask(DriverService driverService, IVehicleBaseInfoService vehicleBaseInfoService,
        IDriversLicenseRawService driversLicenseRawService) {
        this.driverService = driverService;
        this.vehicleBaseInfoService = vehicleBaseInfoService;
        this.driversLicenseRawService = driversLicenseRawService;
    }

    @Override
    public void run() {

        log.info("========== 根据IRS更新行驶证数据 ==========任务开始");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        while (isRunning) {
            // 读取上次中断的数据下标和和已经执行的次数
            readLastIndex();
            Map<Long, String> infoMap =
                    vehicleBaseInfoService.list(Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
                                    .select(NdVehicleBaseInfo::getId,NdVehicleBaseInfo::getCarPlate))
                            .stream().collect(Collectors.toMap(NdVehicleBaseInfo::getId, NdVehicleBaseInfo::getCarPlate));
            OptionalLong maxKey = infoMap.keySet().stream().mapToLong(Long::longValue).max();
            Long maxIndex = null;
            if (maxKey.isPresent()){
                maxIndex = maxKey.getAsLong();
            }
            // 校验下标对应的车牌号是否一致
            String carNo;
            carNo = infoMap.get(lastIndex);
            while (Objects.isNull(carNo)) {
                log.info("车辆id{}不存在,请检查该车辆信息是否已经被删除!", lastIndex);
                // 查找下一个车辆信息,直到车辆信息存在
                lastIndex++;
                if (Objects.nonNull(maxIndex) && lastIndex.compareTo(maxIndex) > 0){
                    log.info("系统中没有待查询的车牌号");
                    return;
                }
                carNo = infoMap.get(lastIndex);
            }

            // 从车辆信息表中从上次执行中断的下标获取一定数量的车牌号
            int cnt = BIGGEST_ACCESS_NUM - lastCount;
            LambdaQueryWrapper<NdVehicleBaseInfo> query =
                Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
                    .ge(NdVehicleBaseInfo::getId, lastIndex)
                    .last("limit " + cnt)
                    .select(NdVehicleBaseInfo::getCarPlate, NdVehicleBaseInfo::getId)
                    .isNotNull(NdVehicleBaseInfo::getCarPlate);
            List<NdVehicleBaseInfo> list = vehicleBaseInfoService.list(query);
            log.info("此次任务车辆数量为:" + list.size());
            if (CollUtil.isNotEmpty(list)) {
                List<String> carPlateList = list.stream().sorted(Comparator.comparing(NdVehicleBaseInfo::getId))
                    .map(NdVehicleBaseInfo::getCarPlate).collect(Collectors.toList());
                Map<String, Long> carMap = list.stream().collect(Collectors.toMap(NdVehicleBaseInfo::getCarPlate, NdVehicleBaseInfo::getId));
                String[] carPlates = carPlateList.stream().toArray(String[]::new);
                // 执行查询任务
                executeTask(carPlates,carMap);
                // 当访问次数达到当日设定数量时,结束循环，初始化累计访问次数
                if (BIGGEST_ACCESS_NUM.equals(lastCount) || lastIndex.equals(maxIndex)) {
                    isRunning = false;
                    // 任务执行完毕后保存最终的数据下标
                    TreeMap<Long, String> sortedMap = new TreeMap<>(infoMap);
                    Map.Entry<Long, String> higherEntry = sortedMap.higherEntry(lastIndex);
                    if (Objects.nonNull(higherEntry)){
                        lastIndex = higherEntry.getKey();
                    }
                    saveLastIndex(lastIndex, 0);
                }
            } else {
                log.info("本月任务已查询完成!");
                return;
            }
        }
        stopWatch.stop();
        log.info("共更新行驶证数据：" + lastCount + "条");
        log.info("========== 根据IRS更新行驶证数据==========任务结束 {}s", stopWatch.getTotalTimeSeconds());

    }

    private void executeTask(String[] carPlates, Map<String, Long> carMap) {
        for (int i = 0; i < carPlates.length; i++) {
            // 执行任务代码
            String carPlate = carPlates[i];
            String dataJsonStr;
            try {
                dataJsonStr = driverService.vehicleLicenseQuery(carPlate,i);
                if (Objects.nonNull(dataJsonStr)) {
                    JSONObject jsonObject = JSON.parseObject(dataJsonStr, JSONObject.class);
                    String msg = jsonObject.getString("msg");
                    if (msg.contains("签名错误")) {
                        // 签名错误
                        lastIndex = carMap.get(carPlate);
                        lastCount++;
                        saveLastIndex(lastIndex, lastCount);
                        log.error("签名错误，任务中断时车牌号下标为{}", lastIndex);
                        break;
                    }
                }
            } catch (Exception e) {
                // 接口请求异常,结束循环
                lastIndex = carMap.get(carPlate);
                lastCount++;
                saveLastIndex(lastIndex, lastCount);
                log.error("任务中断时车牌号下标为{},中断原因：{}", lastIndex,e.getMessage());
                break;
            }
            if (Objects.isNull(dataJsonStr)) {
                // 刷新请求秘钥失败,接口调用内容返回空,任务中断，保存下标
                lastIndex = carMap.get(carPlate);
                saveLastIndex(lastIndex, lastCount);
                log.error("车辆行驶证查询接口调用失败,车牌号为:" + carPlate);
                break;
            }
            int index = i + 1;
            // 如果还有下一个待查询车牌号
            if (index < carPlates.length) {
                lastIndex = carMap.get(carPlates[index]);
            }else {
                // 已经是最后一个车牌号
                lastIndex = carMap.get(carPlates[i]);
            }
            log.info("下次待查询车牌号下标为:" + lastIndex);
            lastCount++;
            log.info("已访问行驶证查询IRS接口 {} 次", lastCount);
            log.info("此次访问的车牌号为 {}", 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("该车牌号没有行驶证信息!");
                continue;
            }
            // 获取身份证号的所有行驶证信息
            Map<String, List<DriversLicenseRaw>> vehicleLicenseMap =
                driversLicenseRawService.list().stream().collect(Collectors.groupingBy(DriversLicenseRaw::getCarPlate));

            for (JSONObject jsonObject : array) {
                if (Objects.nonNull(jsonObject)) {
                    // 获取发证日期，判断是否重复
                    Timestamp fZRQ = jsonObject.getTimestamp("fZRQ");

                    List<DriversLicenseRaw> licenseRaws = Lists.newArrayList();
                    List<DriversLicenseRaw> driversLicenseRaws = vehicleLicenseMap.get(carPlate);
                    if (CollUtil.isNotEmpty(driversLicenseRaws)) {
                        licenseRaws = driversLicenseRaws.stream().filter(d -> {
                            String detail = d.getDrivingLicenseDetail();
                            JSONObject json = JSON.parseObject(detail, JSONObject.class);
                            Timestamp timestamp = json.getTimestamp("fZRQ");
                            if (timestamp.equals(fZRQ)) {
                                return true;
                            } else {
                                return false;
                            }
                        }).collect(Collectors.toList());
                    }

                    // 没有跟当前发证日期相同地行驶证信息，保存新增的行驶证信息
                    if (CollUtil.isEmpty(licenseRaws)) {
                        DriversLicenseRaw driversLicenseRaw = new DriversLicenseRaw();
                        driversLicenseRaw.setCarPlate(carPlate);
                        String jsonString = jsonObject.toJSONString();
                        driversLicenseRaw.setDrivingLicenseDetail(jsonString);
                        driversLicenseRaw.setCreateOn(LocalDateTime.now());
                        driversLicenseRaw.setUpdateOn(LocalDateTime.now());
                        driversLicenseRawService.save(driversLicenseRaw);
                    }
                }
            }
        }
    }

    private void saveLastIndex(Long lastIndex, Integer lastCount) {

        File directory = new File("");
        // 临时文件存储路径
        String filePath = directory.getAbsolutePath() + File.separator + "irs";
        File file = new File(filePath + File.separator + ACCIDENT_QUERY_INDEX_FILE);

        try {
            FileWriter fileWriter = new FileWriter(file);
            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

            bufferedWriter.write(Long.toString(lastIndex));
            bufferedWriter.newLine();
            bufferedWriter.write(Integer.toString(lastCount));
            bufferedWriter.newLine();

            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void readLastIndex() {
        File directory = new File("");
        // 临时文件存储路径
        String filePath = directory.getAbsolutePath() + File.separator + "irs";
        File file = new File(filePath + File.separator + ACCIDENT_QUERY_INDEX_FILE);
        try {
            List<String> dataList = FileUtil.readLines(file, StandardCharsets.UTF_8);
            if (CollUtil.isNotEmpty(dataList) && dataList.size() == 2) {
                lastIndex = Long.valueOf(dataList.get(0));
                lastCount = Integer.valueOf(dataList.get(1));
            }
        } catch (Exception e) {
            log.info("读取下标和车牌号失败!");
            e.printStackTrace();
        }
    }
}
