package com.bcxin.autodownloadupload.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bcxin.autodownloadupload.common.utils.DatabaseUtil;
import com.bcxin.autodownloadupload.common.utils.DateUtil;
import com.bcxin.autodownloadupload.common.utils.FileUtils;
import com.bcxin.autodownloadupload.common.utils.HttpUtil;
import com.bcxin.autodownloadupload.configs.PullConfig;
import com.bcxin.autodownloadupload.configs.PushConfig;
import com.bcxin.autodownloadupload.dtos.ChangeLogsRequestDto;
import com.bcxin.autodownloadupload.dtos.FerryTaskPullResult;
import com.bcxin.autodownloadupload.entity.FileDownloadLog;
import com.bcxin.autodownloadupload.entity.PullRecord;
import com.bcxin.autodownloadupload.service.FileDownloadLogService;
import com.bcxin.autodownloadupload.service.PullDataService;
import com.bcxin.autodownloadupload.service.PullRecordService;
import com.bcxin.autodownloadupload.service.RetryableService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.LineIterator;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileFilter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * description: 拉取数据服务
 * author: linchunpeng
 * date:  2023-04-19 9:26
 */
@Slf4j
@Service
public class PullDataServiceImpl implements PullDataService {

    @Autowired
    private PullConfig pullConfig;

    @Autowired
    private PushConfig pushConfig;

    @Autowired
    private RetryableService retryableService;

    @Autowired
    private FileDownloadLogService fileDownloadLogService;

    @Autowired
    private PullRecordService pullRecordService;

    @Value("${spring.profiles.active}")
    private String activeFile;

    @Resource(name = "taskExecutor")
    private TaskExecutor taskExecutor;

    private final static String DOWNLOAD_PULL_ZIP_URL = "/download/%s";

    /**
     * description：拉取数据-异步调用
     * author：linchunpeng
     * date：2024/3/11
     */
    @Override
//    @Async(value = "taskExecutor")
    public ChangeLogsRequestDto pullDataAsync(ChangeLogsRequestDto requestDto, int pullType) {
        return this.pullData(requestDto, pullType);
    }

    /**
     * description: 拉取数据
     * author: linchunpeng
     * date:  2023-04-17 16:03
     */
    @Override
    public ChangeLogsRequestDto pullData(ChangeLogsRequestDto requestDto, int pullType) {
        log.info("===================================拉取数据===================================");
        if (requestDto != null && StringUtils.isNotBlank(pullConfig.getApi())) {
            //根据拉取区域，进行拉取
            String regionCodes = requestDto.getRegionCodes();
            log.info("===================================regionCodes：{}===================================", regionCodes);
            for (String regionCode : regionCodes.split(",")) {
                try {
                    log.info("==================================={}===================================", regionCode);
                    requestDto.setRegionCode(regionCode);
                    //创建拉取记录
                    if (requestDto.getAutoFerryTaskId() != null) {
                        pullType = 2;
                    }
                    PullRecord record = pullRecordService.createRecord(requestDto.getAutoFerryTaskId(), pullConfig, requestDto, pullType, regionCode);
                    int errorCount = 1;
                    String requestId = "";
                    String endTime = "";
                    String pullResultZipSavePath = "";

                    while (StringUtils.isBlank(pullResultZipSavePath) && errorCount <= 5) {
                        //1、请求拉取接口，生成sql文件和txt文件
                        String pullResult = getChangeLogPullResult(requestDto, regionCode);
                        if (StringUtils.isNotBlank(pullResult)) {
                            endTime = this.getRequestItems(pullResult);
                            if (StringUtils.isNotBlank(endTime)){
                                requestDto.setEndTime(new Date(Long.parseLong(endTime)));
                                log.info("请求拉取数据的接口成功，返回值：{}，请求endTime：{}", pullResult, endTime);
                                break;
                            }
                            requestId = this.getRequestId(pullResult);
                            log.info("请求拉取数据的接口成功，返回值：{}，请求id：{}，请求endTime：{}", pullResult, requestId, endTime);
                            //2、请求下载zip接口，需要一些时间，采用retry方式，直到下载成功，如果超过1小时，则放弃
                            log.info("===================================2、请求下载zip接口=======================================");
                            pullResultZipSavePath = retryableService.downloadPullResult(pullConfig.getApi().concat(String.format(DOWNLOAD_PULL_ZIP_URL, requestId)), pullConfig.getV5Path());

                            if (StringUtils.isNotBlank(pullResultZipSavePath)) {
                                log.info("拉取服务zip下载完成，判断是否有存在：v5部署过程中，数据源为空的情况，如果有，则重新请求");
                                String errorId = pullRecordService.selectErrorSyncChangeLogs(requestId);
                                if (StringUtils.isNotBlank(errorId)) {
                                    log.info("拉取服务存在v5部署过程中，数据源为空的情况，requestId：{}", errorId);
                                    log.info("请求拉取数据，v5在部署，等待3分钟后进行重试，当前重试次数：{}", errorCount);
                                    errorCount++;
                                    pullResultZipSavePath = "";
                                    requestId = "";
                                    try {
                                        Thread.sleep(180000);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                } else {
                                    log.info("拉取服务不存在v5部署过程中，数据源为空的情况，退出循环，requestId：{}", requestId);
                                    break;
                                }
                            } else {
                                log.info("拉取服务无zip包下载，退出循环");
                                break;
                            }
                        } else {
                            log.info("pullResult为空，退出循环");
                            break;
                        }
                    }
                    if (StringUtils.isNotBlank(endTime)) {
                        return requestDto;
                    }
                    if (StringUtils.isNotBlank(requestId)) {
                        record.setRequestId(requestId);
                    }
                    if (StringUtils.isNotBlank(pullResultZipSavePath)) {
                        //3、解压zip，并归类处理sql文件、txt文件
                        log.info("===================================3、解压zip，并归类处理sql文件、txt文件=======================================");
                        String rootPath = this.unzip(pullResultZipSavePath, getCompletedPath(pullConfig.getCompletedPath(), regionCode), requestId);
                        //4、扫描txt文件，判断是否下载过，没下载过则进行下载
                        log.info("===================================4、扫描txt文件，判断是否下载过，没下载过则进行下载=======================================");
                        this.downloadFiles(rootPath, requestDto.getIsRemoveRepeat(), record);
                        //5、下载完成，打包zip包
                        ZipUtil.zip(rootPath);
                        record.setCompleteZipPath(rootPath.concat(".zip"));
                        log.info("===================================zip压缩完成===================================");
                        if (requestDto.getAutoFerryTaskId() == null || "out-prod".equals(activeFile)) {
                            try {
                                FileUtil.del(rootPath);
                            } catch (Exception e) {
                                log.info("删除拉取文件夹出错，路径：{}", rootPath, e);
                            }
                            log.info("删除文件夹：{}", rootPath);
                        }
                    } else {
                        record.setPullErrorInfo("拉取服务无zip包下载");
                    }
                    pullRecordService.updateById(record);
                } catch (Exception e) {
                    log.error("拉取{}数据出错，{}，{}", regionCode, e.getMessage(), e);
                }
            }
        }
        log.info("===================================拉取数据结束===================================");
        return null;
    }

    private String getChangeLogPullResult(ChangeLogsRequestDto requestDto, String regionCode) {
        log.info("===================================1、请求拉取接口，地区：{}，生成sql文件和txt文件=======================================", regionCode);
        String pullResult = HttpUtil.post(pullConfig.getApi(), JSONObject.toJSONString(requestDto));
        int retryCount = 1;
        while ("fail".equals(pullResult) && retryCount <= 10) {
            //失败重试
            log.info("请求拉取数据的接口失败，等待3分钟进行重试，当前重试次数：{}", retryCount);
            try {
                Thread.sleep(180000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            pullResult = HttpUtil.post(pullConfig.getApi(), JSONObject.toJSONString(requestDto));
            retryCount++;
        }
        return pullResult;
    }

    /**
     * description: 区分地区存放拉取包
     * author: linchunpeng
     * date:  2023-05-26 9:29
     */
    private String getCompletedPath(String completePath, String regionCode) {
        return completePath.concat(File.separator).concat(regionCode);
    }


    /**
     * description: 根据拉取结果，获取requestId
     * author: linchunpeng
     * date:  2023-04-19 9:34
     */
    private String getRequestId(String pullResult) {
        String realPath = JSONObject.parseObject(pullResult).getString("realPath");
        return realPath.substring(realPath.indexOf("_cdc/") + 5, realPath.indexOf("/cdc_"));
    }

    /**
     * description: 根据拉取结果，获取items对象
     * author: hongyiwei
     * date:  2025-09-24 17:10
     */
    private String getRequestItems(String pullResult) {
        if (StringUtils.isBlank(pullResult)) {
            return null;
        }
        JSONObject resultObj;
        try {
            resultObj = JSONObject.parseObject(pullResult);
        } catch (Exception e) {
            log.info("pullResult转换json出错，pullResult：{}", pullResult);
            return null;
        }
        String items = resultObj.getString("items");
        if (StringUtils.isBlank(items)) {
            return null;
        }
        JSONObject itemsObj;
        try {
            itemsObj = JSONObject.parseObject(items);
        } catch (Exception e) {
            log.info("items转换json出错，items：{}", items);
            return null;
        }
        String request = itemsObj.getString("request");
        if (StringUtils.isBlank(request)) {
            return null;
        }
        JSONObject requestObj;
        try {
            requestObj = JSONObject.parseObject(request);
        } catch (Exception e) {
            log.info("request转换json出错，request：{}", request);
            return null;
        }
        return requestObj.getString("endTime");
    }



    /**
     * description: 解压拉取的zip文件，并把sql文件与txt文件归类
     * author: linchunpeng
     * date:  2023-04-18 17:21
     */
    private String unzip(String pullResultZipSavePath, String completedPath, String requestId) {
        //1、解压zip，路径：/data/baidu/pull/v5/xxxx.zip -> /data/baidu/pull/v5/xxxx
        File unzipDir = ZipUtil.unzip(pullResultZipSavePath);
        log.info("解压后路径为：{}", unzipDir.getPath());
        //2、创建完整包文件夹，路径：/data/baidu/pull/xxxx，/data/baidu/pull/xxxx/sql，/data/baidu/pull/xxxx/files，/data/baidu/pull/xxxx/files/uploads
        String rootPath = completedPath.concat(File.separator).concat(requestId);
        String sqlPath = rootPath.concat(File.separator).concat("sql");
        String filesPath = rootPath.concat(File.separator).concat("files");
        String uploadsPath = filesPath.concat(File.separator).concat("uploads");
        FileUtil.mkdir(rootPath);
        FileUtil.mkdir(sqlPath);
        FileUtil.mkdir(filesPath);
        FileUtil.mkdir(uploadsPath);
        //3、sql文件与txt文件归类
        List<File> fileList = FileUtil.loopFiles(unzipDir);
        if (fileList.size() > 0) {
            for (File file : fileList) {
                String suffix = FileUtil.getSuffix(file).toUpperCase(Locale.ROOT);
                switch (suffix) {
                    case "SQL":
                        //sql文件，复制到/data/baidu/pull/xxxx/sql
                        log.info("复制文件：{}，到sql目录", file.getPath());
                        FileUtil.copy(file, new File(sqlPath.concat(File.separator).concat(FileUtil.getName(file))), true);
                        break;
                    case "TXT":
                        //txt文件，复制到/data/baidu/pull/xxxx/files
                        log.info("复制文件：{}，到files目录", file.getPath());
                        FileUtil.copy(file, new File(filesPath.concat(File.separator).concat(FileUtil.getName(file))), true);
                        break;
                }
            }
        }
        //4、删除解压后的文件和zip
        log.info("复制结束");
        log.info("删除文件：{}", pullResultZipSavePath);
        FileUtil.del(pullResultZipSavePath);
        log.info("删除文件夹：{}", unzipDir.getPath());
        FileUtil.del(unzipDir);
        return rootPath;
    }


    /**
     * description: 下载文件，根据是否去重，进行相关下载日志记录
     * author: linchunpeng
     * date:  2023-04-20 15:56
     */
    private void downloadFiles(String rootPath, boolean isRemoveRepeat, PullRecord record) {
        Date now = new Date();
        String serverUrl = pushConfig.getInternet().getServerUrl();
        String filesPath = rootPath.concat(File.separator).concat("files");
        String downloadFile = filesPath.concat(File.separator).concat("pull-download.txt");
        String resultFile = filesPath.concat(File.separator).concat("pull-result.txt");
        String errorFile = filesPath.concat(File.separator).concat("pull-error.txt");
        log.info("txt文件夹路径：{}", filesPath);
        log.info("下载成功信息文件路径：{}", resultFile);
        log.info("下载错误信息文件路径：{}", errorFile);

        List<File> txtFileList = FileUtil.loopFiles(new File(filesPath), 1, new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.getName().toUpperCase(Locale.ROOT).endsWith(".TXT");
            }
        });
        if (CollectionUtils.isNotEmpty(txtFileList)) {
            //txt文件存在，才需要下载文件
            List<FileDownloadLog> saveFileLogList = new ArrayList<>();
            Set<String> md5Set = new HashSet<>();
            //循环得到需要下载的url列表
            for (File txtFile : txtFileList) {
                //读取txt文件列表
                readTxtFiles(isRemoveRepeat, now, saveFileLogList, md5Set, txtFile, resultFile, serverUrl, record);
            }
            log.info("总的需要下载的文件数量：{}", saveFileLogList.size());
            //进行下载与保存日志
            //先把下载列表进行分片
            AtomicInteger successAtomicCount = new AtomicInteger(0);
            if (CollectionUtils.isNotEmpty(saveFileLogList)) {
                List<FileDownloadLog> executeList = new ArrayList<>();
                List<List<FileDownloadLog>> saveListList = ListUtil.partition(saveFileLogList, 1000);
                //根据分配大小，创建线程池大小，最多开5个线程
                CountDownLatch countDownLatch = new CountDownLatch(saveListList.size());
                saveListList.forEach(logList -> {
                    taskExecutor.execute(() -> {
                        //执行下载，并且保存日志
                        log.info("开始执行当前分片下载文件线程");
                        for (FileDownloadLog fileDownloadLog : logList) {
                            try {
                                boolean isSuccess = true;
                                if (!FileUtils.downloadFile(fileDownloadLog.getFileUrl(), filesPath, serverUrl, pullConfig.getObsUrl())) {
                                    //下载失败
                                    if (StringUtils.isNotBlank(pullConfig.getObsUrl())
                                            && fileDownloadLog.getFileUrl().contains(pullConfig.getObsUrl())) {
                                        //如果下载路径是新的obs路径，并且下载不到文件，那就用旧的obs路径尝试下载
                                        fileDownloadLog.setFileUrl(fileDownloadLog.getFileUrl().replace(pullConfig.getObsUrl(), "https://bcxin-saas-prod.obs.cn-north-1.myhuaweicloud.com"));
                                        if (!FileUtils.downloadFile(fileDownloadLog.getFileUrl(), filesPath, serverUrl, pullConfig.getObsUrl())) {
                                            isSuccess = false;
                                        }
                                    } else {
                                        isSuccess = false;
                                    }
                                }
                                if (isSuccess) {
                                    if (isRemoveRepeat) {
                                        //需要保存下载日志
                                        executeList.add(fileDownloadLog);
                                    }
                                    successAtomicCount.incrementAndGet();
                                } else {
                                    //下载失败，追加失败记录
                                    FileUtil.appendUtf8Lines(Collections.singletonList(fileDownloadLog.getFileUrl()), errorFile);
                                }
                            } catch (Exception e) {
                                log.error("单个文件下载异常，url：{}，{}", fileDownloadLog.getFileUrl(), e.getMessage(), e);
                            }
                        }
                        countDownLatch.countDown();
                        log.info("当前分片下载文件完成");
                    });
                });

                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //批量保存
                fileDownloadLogService.saveBatch(executeList, 1000);
                //记录总数与成功数量
                FileUtil.appendUtf8Lines(Collections.singletonList(String.format("本次拉取总的需要下载文件数量：%s，下载成功数量：%s",
                        saveFileLogList.size(), successAtomicCount.get())), resultFile);
                FileUtil.appendUtf8Lines(saveFileLogList.stream().map(FileDownloadLog::getFileUrl).collect(Collectors.toList()), downloadFile);
                //结果存到拉取记录表
                if (FileUtil.exist(resultFile)) {
                    record.setPullResultInfo(FileUtil.readUtf8String(resultFile));
                }
                if (FileUtil.exist(errorFile)) {
                    record.setPullErrorInfo(FileUtil.readUtf8String(errorFile));
                }
            }
        } else {
            log.info("没有需要下载的文件");
        }
    }


    /**
     * description: 读取txt文件列表
     * author: linchunpeng
     * date:  2023-04-20 15:57
     */
    private void readTxtFiles(boolean isRemoveRepeat, Date now, List<FileDownloadLog> saveFileLogList, Set<String> md5Set,
                              File txtFile, String resultFile, String serverUrl, PullRecord record) {
        log.info("开始读取txt文件：{}", txtFile.getPath());
        LineIterator lineIterator = null;
        try {
            //是否自动摆渡
            int isAutoFerry = record.getPullType() == 2 ? 1 : 0;
            Date lastCheckTime = null;
            if (isAutoFerry == 0) {
                log.info("不是自动摆渡，需要兼容已下载附件下载");
                //不是自动摆渡的话，需要兼容已下载附件下载
                String week = DateUtil.getWeekEngStrOfDate(now);
                log.info("week：{}", week);
                if ("monday".equals(week)) {
                    log.info("周一判断重复2天20小时");
                    //周一判断重复2天20小时
                    lastCheckTime = DateUtil.getBeforeNumDayTime(now, 3, 4);
                } else {
                    log.info("周二到周五，判断重复20个小时");
                    //周二到周五，判断重复20个小时
                    lastCheckTime = DateUtil.getBeforeNumDayTime(now, 1, 4);
                }
                log.info("lastCheckTime：{}", cn.hutool.core.date.DateUtil.formatDateTime(lastCheckTime));
            } else {
                log.info("自动摆渡，需要兼容已下载附件但未生成包的记录");
                PullRecord lastSameTimeRecord = pullRecordService.getLastSameTimeRecord(record.getRegionCode(), record.getStartTime(), record.getId());
                if (lastSameTimeRecord != null) {
                    lastCheckTime = lastSameTimeRecord.getCreateTime();
                    log.info("lastCheckTime：{}", cn.hutool.core.date.DateUtil.formatDateTime(lastCheckTime));
                }
            }
            lineIterator = org.apache.commons.io.FileUtils.lineIterator(txtFile, "UTF-8");
            //所有下载链接列表
            int count = 0;
            int needDownload = 0;
            List<FileDownloadLog> fileLogList = new ArrayList<>();
            //所有md5列表
            List<String> md5List = new ArrayList<>();
            while (lineIterator.hasNext()) {
                String url = lineIterator.nextLine();
                if (url.startsWith("/upload")) {
                    if (serverUrl.contains("v5qy.baibaodun.cn")) {
                        //互联网，uploads是新的obs，要去掉uploads
                        if (url.startsWith("/uploads")) {
                            url = url.substring(8);
                        }
                        url = pullConfig.getObsUrl().concat(url);
                    } else {
                        url = serverUrl.concat(url);
                    }
                }
                if (!url.startsWith("http")) {
                    continue;
                }
                if (url.startsWith("https:/") && !url.startsWith("https://")) {
                    url = url.replace("https:/", "https://");
                }
                if (url.startsWith("http:/") && !url.startsWith("http://")) {
                    url = url.replace("http:/", "http://");
                }

                url = url.replace("%2F", "/");
                String md5 = MD5.create().digestHex(url, "UTF-8");
                FileDownloadLog fileDownloadLog = new FileDownloadLog();
                fileDownloadLog.setFileUrl(url);
                fileDownloadLog.setMd5(md5);
                fileDownloadLog.setCreateTime(now);

                fileLogList.add(fileDownloadLog);
                md5List.add(md5);
                count++;

                //每1000条进行一次验证md5
                if (isRemoveRepeat && count % 1000 == 0) {
                    log.info("每1000条进行一次验证md5存不存在");
                    //需要进行数据库去重
                    //查询数据库都存在哪些数据
                    QueryWrapper<FileDownloadLog> queryWrapper = new QueryWrapper<>();
                    queryWrapper.in("md5", md5List);
                    if (lastCheckTime != null) {
                        queryWrapper.le("createTime", lastCheckTime);
                    }
                    List<FileDownloadLog> dbLog = fileDownloadLogService.list(queryWrapper);
                    //比对所有列表与数据库列表，汇总数据库不存在的数据
                    List<FileDownloadLog> addLogList;
                    if (CollectionUtils.isNotEmpty(dbLog)) {
                        List<String> existMd5List = dbLog.stream().map(FileDownloadLog::getMd5).collect(Collectors.toList());
                        addLogList = fileLogList.stream().filter(fileLog -> !existMd5List.contains(fileLog.getMd5())).collect(Collectors.toList());
                    } else {
                        addLogList = new ArrayList<>(fileLogList);
                    }
                    if (CollectionUtils.isNotEmpty(addLogList)) {
                        for (FileDownloadLog downloadLog : addLogList) {
                            if (md5Set.add(downloadLog.getMd5())) {
                                saveFileLogList.add(downloadLog);
                            }
                        }
                    }
                    needDownload += addLogList.size();
                    log.info("这1000条需要下载{}条", addLogList.size());
                    fileLogList.clear();
                    md5List.clear();
                }
            }
            if (isRemoveRepeat) {
                //取模后剩下的列表
                if (fileLogList.size() > 0) {
                    //需要进行数据库去重
                    //查询数据库都存在哪些数据
                    QueryWrapper<FileDownloadLog> queryWrapper = new QueryWrapper<>();
                    queryWrapper.in("md5", md5List);
                    if (lastCheckTime != null) {
                        queryWrapper.le("createTime", lastCheckTime);
                    }
                    List<FileDownloadLog> dbLog = fileDownloadLogService.list(queryWrapper);
                    //比对所有列表与数据库列表，汇总数据库不存在的数据
                    List<FileDownloadLog> addLogList;
                    if (CollectionUtils.isNotEmpty(dbLog)) {
                        List<String> existMd5List = dbLog.stream().map(FileDownloadLog::getMd5).collect(Collectors.toList());
                        addLogList = fileLogList.stream().filter(fileLog -> !existMd5List.contains(fileLog.getMd5())).collect(Collectors.toList());
                    } else {
                        addLogList = new ArrayList<>(fileLogList);
                    }
                    if (CollectionUtils.isNotEmpty(addLogList)) {
                        for (FileDownloadLog downloadLog : addLogList) {
                            if (md5Set.add(downloadLog.getMd5())) {
                                saveFileLogList.add(downloadLog);
                            }
                        }
                    }
                    needDownload += addLogList.size();
                }
            } else {
                //不需要数据库去重
                if (CollectionUtils.isNotEmpty(fileLogList)) {
                    for (FileDownloadLog downloadLog : fileLogList) {
                        if (md5Set.add(downloadLog.getMd5())) {
                            saveFileLogList.add(downloadLog);
                        }
                    }
                }
                needDownload = fileLogList.size();
            }

            FileUtil.appendUtf8Lines(Collections.singletonList(FileUtil.getName(txtFile) + "，需要下载的文件数量:" + needDownload), resultFile);
        } catch (Exception e) {
            e.printStackTrace();
            String eMessage = e.getMessage();
            log.error("读取txt文件：{}，异常，{}", txtFile.getName(), eMessage, e);
        } finally {
            IOUtils.closeQuietly(lineIterator);
        }
    }

    /**
     * description: 旧数据迁移
     * author: linchunpeng
     * date:  2023-04-20 13:13
     */
    @Override
    public void oldDataProcessor(Long begin, Long end) {
        try {
            log.info("=======================================旧数据迁移=======================================");
            log.info("数据范围：{} 到 {}", begin, end);
            long beginTime = System.currentTimeMillis();
            Connection connection = DatabaseUtil.getConnection(pullConfig.getDatasource().getUrl(), pullConfig.getDatasource().getUsername(), pullConfig.getDatasource().getPassword());
            log.info("获取旧数据库连接成功，开始迁移");
            ResultSet rs = null;
            PreparedStatement psmnt = null;
            try {
                end += 100000;
                long limit = begin + 100000;
                while (limit <= end) {
                    long bt = System.currentTimeMillis();
                    long start = limit - 100000;
                    log.info("查询id >= {} and < {} 的数据", start, limit);
                    StringBuilder sql = new StringBuilder("select fileUrl, createTime from file_download_log_ex where id >= ");
                    sql.append(start).append(" and id < ").append(limit);
                    psmnt = connection.prepareStatement(sql.toString());
                    rs = psmnt.executeQuery();
                    List<FileDownloadLog> logList = new ArrayList<>();
                    log.info("查询成功");
                    while (rs.next()) {
                        String fileUrl = rs.getString(1);
                        Date createTime = rs.getDate(2);
                        String md5 = MD5.create().digestHex(fileUrl, "UTF-8");

                        FileDownloadLog fileLog = new FileDownloadLog();
                        fileLog.setFileUrl(fileUrl);
                        fileLog.setMd5(md5);
                        fileLog.setCreateTime(createTime);
                        logList.add(fileLog);
                    }
                    log.info("转对象成功，开始执行导入数据库");
                    if (logList.size() > 0) {
                        if (fileDownloadLogService.saveBatch(logList, 1000)) {
                            log.info("旧数据批量插入新数据库成功，start：{}，limit：{}，条数：{}", start, limit, logList.size());
                        } else {
                            log.info("旧数据批量插入新数据库失败，start：{}，limit：{}，条数：{}", start, limit, logList.size());
                        }
                    }
                    long et = System.currentTimeMillis();
                    log.info("id >= {} and < {} 的数据迁移结束，耗时：{}ms", start, limit, (et - bt));
                    limit += 100000;
                }
            } catch (Exception e) {
                log.error("旧数据迁移异常，{}", e.getMessage(), e);
            } finally {
                try {
                    if (rs != null) {
                        rs.close();
                    }
                    if (psmnt != null) {
                        psmnt.close();
                    }
                    if (connection != null) {
                        connection.close();
                    }
                } catch (SQLException e) {
                    log.error("旧数据迁移异常，{}", e.getMessage(), e);
                }
            }
            long endTime = System.currentTimeMillis();
            log.info("=======================================迁移结束，耗时：{}=======================================", (endTime - beginTime));
        } catch (Exception e) {
            log.error("旧数据迁移异常，{}", e.getMessage(), e);
        }
    }

    /**
     * description：查询自动摆渡结果
     * author：linchunpeng
     * date：2024/6/17
     */
    @Override
    public FerryTaskPullResult queryAutoFerryPullResult(Long id) {
        log.info("===================================查询自动摆渡拉取结果，查询id：{}=======================================", id);
        FerryTaskPullResult ferryTaskPullResult = new FerryTaskPullResult();
        if (id != null) {
            ferryTaskPullResult.setId(id);
            PullRecord record = pullRecordService.getById(id);
            if (record != null
                    && StringUtils.isNotBlank(record.getRequestId())
                    && (StringUtils.isNotBlank(record.getCompleteZipPath())
                    || StringUtils.isNotBlank(record.getPullErrorInfo()))) {
                ferryTaskPullResult.setRequestId(record.getRequestId());
                if (StringUtils.isNotBlank(record.getCompleteZipPath())) {
                    //正常下载摆渡包
                    ferryTaskPullResult.setPackageUrl(getCompletedPath(pullConfig.getCompletedPath(), record.getRegionCode()));
                    ferryTaskPullResult.setPullResult("拉取数据-下载完成");
                    ferryTaskPullResult.setTaskStatus(2);
                } else {
                    //拉取服务无zip包下载
                    ferryTaskPullResult.setPullResult("拉取服务无zip包下载");
                    ferryTaskPullResult.setTaskStatus(9);
                }
            } else {
                ferryTaskPullResult.setPullResult("还未拉取完成");
            }
        }
        return ferryTaskPullResult;
    }
}
