package com.ningdatech.carapi.irs.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.StopWatch;
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.ningdatech.carapi.driver.entity.DriverInfo;
import com.ningdatech.carapi.driver.service.IDriverInfoService;
import com.ningdatech.carapi.irs.entity.DriversLicenseRaw;
import com.ningdatech.carapi.irs.service.DriverService;
import com.ningdatech.carapi.irs.service.IDriversLicenseRawService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.*;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

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

    private final DriverService driverService;
    private final IDriverInfoService driverInfoService;
    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 MyDrivingLicenseQueryTask(DriverService driverService, IDriverInfoService driverInfoService, IDriversLicenseRawService driversLicenseRawService) {
        this.driverService = driverService;
        this.driverInfoService = driverInfoService;
        this.driversLicenseRawService = driversLicenseRawService;
    }

    @Override
    public void run() {

        log.info("========== 根据IRS更新驾驶证数据 ==========任务开始");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        while (isRunning) {

            // 读取上次中断的数据下标和和已经执行的次数
            readLastIndex();
            Map<Long, DriverInfo> infoMap = driverInfoService.list().stream()
                    .collect(Collectors.toMap(DriverInfo::getId, v -> v));
            // 校验文件中存储的下标对应的身份证号是否一致
            DriverInfo info;
            info = infoMap.get(lastIndex);
            while (Objects.isNull(info)) {
                log.error("文件中存储的驾驶员id{}不存在,请检查该驾驶员信息是否已经被删除!",lastIndex);
                // 查找下一个驾驶员信息,直到驾驶员信息存在
                lastIndex++;
                info = infoMap.get(lastIndex);
            }

            // 从车辆信息表中从上次执行中断的下标获取一定数量的车牌号
            LambdaQueryWrapper<DriverInfo> query =
                Wrappers.lambdaQuery(DriverInfo.class).ge(DriverInfo::getId, lastIndex)
                    .le(DriverInfo::getId, BIGGEST_ACCESS_NUM - lastCount + lastIndex - 1)
                    .select(DriverInfo::getIdCard).isNotNull(DriverInfo::getIdCard);
            List<DriverInfo> list = driverInfoService.list(query);

            Set<String> idCardSet = list.stream().map(DriverInfo::getIdCard).collect(Collectors.toSet());
            String[] idCards = idCardSet.toArray(new String[idCardSet.size()]);
            try {
                executeTask(idCards);
            } catch (Exception e) {
                // 下标恢复到上次执行失败的驾驶员下标
                lastIndex--;
                // 线程被中断，退出循环
                isRunning = false;
                e.printStackTrace();
            } finally {
                // 任务执行完毕后保存最终的数据下标
                saveLastIndex(lastIndex, lastCount);
            }

            stopWatch.stop();
            log.info("共更新驾驶证数据：" + lastCount + "条");
            log.info("========== 根据IRS更新驾驶证数据==========任务结束 {}s", stopWatch.getTotalTimeSeconds());
        }

    }

    private void executeTask(String[] idCards) {
        for (int i = lastIndex.intValue(); i < idCards.length; i++) {
            // 执行任务代码
            String idCard = idCards[i];
            String dataJsonStr = driverService.vehicleLicenseQuery(idCard);
            lastIndex++;
            lastCount++;
            log.info("已访问驾驶证查询IRS接口 {} 次", lastCount);
            log.info("此次访问的身份证号为 {}", idCard);
            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::getIdcard));
            
            for (JSONObject jsonObject : array) {
                if (Objects.nonNull(jsonObject)) {
                    // 获取发证日期，判断是否重复
                    Timestamp fZRQ = jsonObject.getTimestamp("fZRQ");

                    List<DriversLicenseRaw> driversLicenseRaws = vehicleLicenseMap.get(idCard);
                    List<DriversLicenseRaw> licenseRaws = driversLicenseRaws.stream().filter(d -> {
                        String detail = d.getDriverLicenseDetail();
                        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.isNotEmpty(licenseRaws)) {
                        DriversLicenseRaw driversLicenseRaw = new DriversLicenseRaw();
                        driversLicenseRaw.setIdcard(idCard);
                        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 {
            // 创建Scanner对象并指定文件路径
            Scanner scanner = new Scanner(file);

            // 读取下标数据
            while (scanner.hasNextLong()) {
                long num = scanner.nextLong();
                lastIndex = num;
            }

            // 读取字符串数据
            scanner = new Scanner(file);
            while (scanner.hasNextInt()) {
                int cnt = scanner.nextInt();
                lastCount = cnt;
            }
            // 关闭Scanner对象
            scanner.close();
        } catch (FileNotFoundException e) {
            log.info("读取下标和车牌号失败!");
            e.printStackTrace();
        }
    }
}
