package com.njcn.gather.plan.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.gather.detection.pojo.po.AdPair;
import com.njcn.gather.detection.service.IAdPariService;
import com.njcn.gather.device.pojo.enums.CheckStateEnum;
import com.njcn.gather.device.pojo.po.PqDev;
import com.njcn.gather.device.pojo.po.PqDevSub;
import com.njcn.gather.device.service.IPqDevService;
import com.njcn.gather.device.service.IPqDevSubService;
import com.njcn.gather.monitor.pojo.po.PqMonitor;
import com.njcn.gather.monitor.service.IPqMonitorService;
import com.njcn.gather.plan.pojo.po.AdPlan;
import com.njcn.gather.plan.pojo.vo.AdPlanCheckDataVO;
import com.njcn.gather.plan.service.util.BatchFileReader;
import com.njcn.gather.system.config.PathConfig;
import com.njcn.gather.system.config.handler.NonWebAutoFillValueHandler;
import com.njcn.gather.tools.report.model.constant.ReportConstant;
import com.njcn.gather.type.pojo.po.DevType;
import com.njcn.gather.type.service.IDevTypeService;
import com.njcn.web.utils.HttpResultUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Slf4j
@EnableAsync
@RequiredArgsConstructor
@Component
public class AsyncPlanHandler {

    private final SseClient sseClient;
    private final IAdPlanService adPlanService;
    private final IPqDevService pqDevService;
    private final IDevTypeService devTypeService;
    private final IPqDevSubService pqDevSubService;
    private final IPqMonitorService pqMonitorService;

    private final IAdPariService adPairService;

    private final JdbcTemplate jdbcTemplate;

    private final PathConfig pathConfig;
//    @Value("${report.reportDir}")
//    private String reportPath;
//    @Value("${data.homeDir}")
//    private String dataPath;

    private static final int BATCH_SIZE = 10000;
    private static final int FINAL_STEP = 85;
    private static final String TEST_DATA_DIR = "plan_test_data";


    @Async
    public void exportPlanCheckDataZip(String uid, String planId, List<PqDev> devList, Integer report) {
        NonWebAutoFillValueHandler.setCurrentUserId(uid);
        LocalDateTime startTime = LocalDateTime.now();
        AdPlanCheckDataVO planCheckDataVO = new AdPlanCheckDataVO();
        AtomicInteger progress = new AtomicInteger(0);
        AtomicInteger currentProgress = new AtomicInteger(0);
        sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, "开始导出文件"));

        // 获取检测计划基本数据
        AdPlan plan = adPlanService.getById(planId);
        planCheckDataVO.setPlan(plan);
        planCheckDataVO.setDevList(devList);
        List<String> devIdList = devList.stream().map(PqDev::getId).collect(Collectors.toList());
        // 被检设备状态统计
        List<PqDevSub> devSubList = pqDevSubService.list(new LambdaQueryWrapper<PqDevSub>().in(PqDevSub::getDevId, devIdList));
        for (PqDevSub devSub : devSubList) {
            // 不导出报告，设置报告状态为未生成
            if (ObjectUtil.isNull(report) || report.equals(DataStateEnum.DELETED.getCode())) {
                devSub.setReportState(DataStateEnum.DELETED.getCode());
            }
        }
        planCheckDataVO.setDevSubList(devSubList);
        // 被检设备监测点信息
        List<PqMonitor> monitorList = pqMonitorService.list(new LambdaQueryWrapper<PqMonitor>().in(PqMonitor::getDevId, devIdList));
        planCheckDataVO.setMonitorList(monitorList);
        // devMonitorId = 被检设备ID+通道号
        List<String> devMonitorIds = new ArrayList<>();
        for (PqDev dev : devList) {
            List<String> channelNoList = StrUtil.split(dev.getInspectChannel(), StrUtil.COMMA);
            for (String channelNo : channelNoList) {
                devMonitorIds.add(dev.getId() + StrUtil.UNDERLINE + channelNo);
            }
        }
        planCheckDataVO.setDevMonitorIds(devMonitorIds);

        // 设备通道匹对关系
        List<AdPair> pairList = adPairService.list(new LambdaQueryWrapper<AdPair>().eq(AdPair::getPlanId, planId).in(AdPair::getDevMonitorId, devMonitorIds));
        planCheckDataVO.setPairList(pairList);
        progress.addAndGet(1);
        sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, "生成检测计划基本信息数据文件中，请耐心等待..."));

        // 获取计划检测结果数据表以及数据
        Integer code = plan.getCode();
        List<String> dataTableNames = CollUtil.newArrayList("ad_harmonic_" + code, "ad_non_harmonic_" + code, "ad_harmonic_result_" + code, "ad_non_harmonic_result_" + code);

        // 创建临时目录用于存储文件
        File tempDataDir = FileUtil.mkdir(FileUtil.getTmpDirPath() + "plan_test_data_" + System.currentTimeMillis() + "/");
        int dataBatch = 0;
        int current = 0;
        if (CollUtil.isNotEmpty(pairList)) {
            for (String dataTableName : dataTableNames) {
                // 创建数据文件
                String fileName = dataTableName.replace("_" + code, "") + ".txt";
                File dataFile = FileUtil.file(tempDataDir, fileName);
                // 确保文件存在
                FileUtil.touch(dataFile);

                // 初始化写入标志，用于判断是否已写入字段名
                boolean isFirstWrite = true;

                // 分页查询，避免一次性加载大量数据
                int pageSize = BATCH_SIZE; // 每页查询10000条记录
                int offset = 0;
                List<Map<String, Object>> pageData;
                do {
                    dataBatch += 1;
                    if (current < FINAL_STEP + 5) {
                        current = Math.min(current + 1, FINAL_STEP + 5);
                    }
                    currentProgress.set(current);
                    sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress.get() + currentProgress.get(), "生成检测结果数据文件中，请耐心等待..."));

                    String paginatedSql = buildPaginatedQuery(dataTableName, devMonitorIds, pageSize, offset);
                    pageData = jdbcTemplate.queryForList(paginatedSql);

                    // 将当前页数据追加到文件中
                    if (CollUtil.isNotEmpty(pageData)) {
                        StringBuilder content = new StringBuilder();

                        // 如果是第一次写入，先写入字段名
                        if (isFirstWrite) {
                            // 获取字段名
                            Map<String, Object> firstRow = pageData.get(0);
                            List<String> fieldNames = new ArrayList<>(firstRow.keySet());

                            // 写入字段名作为第一行
                            content.append(StrUtil.join("\t", fieldNames)).append(System.lineSeparator());
                            isFirstWrite = false;
                        }

                        // 写入数据行
                        for (Map<String, Object> data : pageData) {
                            List<Object> values = new ArrayList<>(data.values());
                            content.append(StrUtil.join("\t", values)).append(System.lineSeparator());
                        }

                        // 追加内容到文件
                        FileUtil.appendUtf8String(content.toString(), dataFile);
                    }
                    offset += pageSize;

                } while (pageData.size() == pageSize); // 如果查询结果少于pageSize，说明已经查询完所有数据
            }
        }
        planCheckDataVO.setDataBatch(dataBatch);
        int currentVal = progress.get() + currentProgress.get();
        if (currentVal < FINAL_STEP + 5) {
            progress.addAndGet(FINAL_STEP + 5);
        } else {
            progress.set(currentVal);
        }
        sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, "压缩检测结果数据文件中，请耐心等待..."));

        // 导出数据.zip文件
        String jsonStr = JSONUtil.toJsonStr(planCheckDataVO, new JSONConfig().setIgnoreNullValue(false));
        try {
            // 创建 JSON 文件
            String jsonFileName = plan.getName() + ".json";
            File jsonFile = FileUtil.file(tempDataDir, jsonFileName);
            FileUtil.writeUtf8String(jsonStr, jsonFile);

            // 创建 ZIP 文件
            String zipFileName = plan.getName() + "_检测数据包.zip";
            File zipFile = FileUtil.file(pathConfig.getDataPath() + File.separator + TEST_DATA_DIR + File.separator, zipFileName);

            // 添加检测报告文件
            if (ObjectUtil.isNotNull(report) && report.equals(1)) {
                for (PqDev dev : devList) {
                    DevType devType = devTypeService.getById(dev.getDevType());
                    String dirPath = pathConfig.getReportPath().concat(File.separator).concat(devType.getName());
                    File reportFile = new File(dirPath.concat(File.separator).concat(dev.getCreateId()).concat(ReportConstant.DOCX));
                    // 如果reportFile存在，则将reportFile中的文件添加到已有的zip文件中
                    if (FileUtil.exist(reportFile)) {
                        // 复制reportFile到临时目录
                        FileUtil.copy(reportFile, tempDataDir, true);
                    }

                }
            }

            // 创建zip文件，包含所有文件
            ZipUtil.zip(tempDataDir.getAbsolutePath(), zipFile.getAbsolutePath());
            // 删除临时目录
            FileUtil.del(tempDataDir);
            LocalDateTime endTime = LocalDateTime.now();
            log.info("生成数据包完成，耗时: {}s", Duration.between(startTime, endTime).getSeconds());
            progress.set(100);
            sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, zipFile.getAbsolutePath()));
        } catch (Exception e) {
            log.error("生成数据包失败", e);
            sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.FAIL.getCode(), progress.get() + currentProgress.get(), "生成数据包失败"));
        } finally {
            NonWebAutoFillValueHandler.clearCurrentUserId();
        }

        sseClient.closeSse(uid);
    }


    @Async
    public void importAndMergePlanCheckData(String zipFilePath, String uid, String planId) {
        importAndMergePlanCheckDataLogic(zipFilePath, uid, planId);

    }

    @Transactional
    public void importAndMergePlanCheckDataLogic(String zipFilePath, String uid, String planId) {
        NonWebAutoFillValueHandler.setCurrentUserId(uid);
        LocalDateTime startTime = LocalDateTime.now();
        AtomicInteger progress = new AtomicInteger(0);
        AtomicInteger currentProgress = new AtomicInteger(0);
        AtomicInteger dataCount = new AtomicInteger(0);
        try {
            // 创建临时目录用于解压文件
            File tempDir = FileUtil.mkdir(FileUtil.getTmpDirPath() + "import_plan_check_data_" + System.currentTimeMillis() + "/");
            progress.addAndGet(1);
            sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, "开始解压文件，请耐心等待..."));

            // 解压zip文件
            File unzipDir = FileUtil.mkdir(FileUtil.file(tempDir, "unzip"));
            ZipUtil.unzip(zipFilePath, unzipDir.getAbsolutePath());

            // 查找解压目录中的json文件
            File[] files = unzipDir.listFiles();
            AdPlanCheckDataVO planCheckDataVO = null;
            List<File> dataFiles = new ArrayList<>();
            List<File> docxFiles = new ArrayList<>();
            if (files != null) {
                for (File f : files) {
                    if (f.isFile()) {
                        // 读取json文件内容
                        if (f.getName().endsWith(".json")) {
                            String jsonStr = FileUtil.readUtf8String(f);
                            planCheckDataVO = JSONUtil.toBean(jsonStr, AdPlanCheckDataVO.class);
                        } else if (f.getName().endsWith(".docx")) {
                            docxFiles.add(f);
                        } else if (f.getName().endsWith(".txt")) {
                            dataFiles.add(f);
                        }
                    }
                }
            }

            if (planCheckDataVO == null) {
                FileUtil.del(tempDir);
                sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.FAIL.getCode(), progress, "ZIP文件中未找到JSON数据文件"));
                return;
            }
            AdPlan checkPlan = planCheckDataVO.getPlan();
            if (checkPlan == null) {
                FileUtil.del(tempDir);
                sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.FAIL.getCode(), progress, "ZIP文件中未找到检测计划信息"));
                return;
            }

            List<PqDev> devList = planCheckDataVO.getDevList();
            if (CollUtil.isEmpty(devList)) {
                FileUtil.del(tempDir);
                sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.FAIL.getCode(), progress, "ZIP文件中未找到被检设备信息"));
                return;
            }

            AdPlan subPlan = adPlanService.getById(checkPlan.getId());
            if (subPlan == null) {
                FileUtil.del(tempDir);
                sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.FAIL.getCode(), progress, "该子计划不存在"));
                return;
            }
            if (!StrUtil.equals(planId, subPlan.getFatherPlanId())) {
                FileUtil.del(tempDir);
                sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.FAIL.getCode(), progress, "非当前检修计划的子计划"));
                return;
            }
            progress.addAndGet(1);
            sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, "开始同步计划基本信息，请耐心等待..."));
            // 更新检测计划几个状态字段
            subPlan.setTestState(checkPlan.getTestState());
            subPlan.setReportState(checkPlan.getReportState());
            subPlan.setResult(checkPlan.getResult());
            adPlanService.updateById(subPlan);
            progress.addAndGet(1);
            sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, "开始同步计划设备信息，请耐心等待..."));
            // 更新监测点数据
            List<PqMonitor> monitorList = planCheckDataVO.getMonitorList();
            pqMonitorService.updateBatchById(monitorList);
            // 批量更新被检设备信息，不需要更新
            // 不更新导入标志
            /*devList.forEach(dev -> dev.setImportFlag(null));
            pqDevService.updateBatchById(devList);*/

            List<PqDevSub> devSubList = planCheckDataVO.getDevSubList();
            for (PqDevSub devSub : devSubList) {
                pqDevSubService.update(devSub, new LambdaUpdateWrapper<PqDevSub>().eq(PqDevSub::getDevId, devSub.getDevId()));
            }
            progress.addAndGet(1);
            sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, "开始同步通道配对信息，请耐心等待..."));

            // 同步检测数据
            List<AdPair> pairList = planCheckDataVO.getPairList();
            adPairService.saveOrUpdateBatch(pairList);
            // 主计划
            AdPlan plan = adPlanService.getById(planId);
            if (CollUtil.isNotEmpty(docxFiles)) {
                progress.addAndGet(1);
                sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, "开始同步检测报告文件"));
                for (File docx : docxFiles) {
                    for (PqDev dev : devList) {
                        DevType devType = devTypeService.getById(dev.getDevType());
                        String dirPath = pathConfig.getReportPath().concat(File.separator).concat(devType.getName());
                        File reportFile = new File(dirPath.concat(File.separator).concat(dev.getCreateId()).concat(ReportConstant.DOCX));
                        // 文件名匹配，复制到对应目录下
                        if (docx.getName().equals(reportFile.getName())) {
                            File parentDir = FileUtil.mkParentDirs(reportFile);
                            FileUtil.copy(docx, parentDir, true);
                        }

                    }
                }
            }
            if (CollUtil.isNotEmpty(dataFiles)) {
                Integer planCode = plan.getCode();
                progress.addAndGet(1);
                sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, "开始同步检测数据信息，请耐心等待..."));
                // 合并前清除相关表数据
                String mainHarmonicTableName = "ad_harmonic_" + planCode;
                String mainNonHarmonicTableName = "ad_non_harmonic_" + planCode;
                String mainHarmonicResultTableName = "ad_harmonic_result_" + planCode;
                String mainNonHarmonicResultTableName = "ad_non_harmonic_result_" + planCode;
                List<String> devMonitorIds = planCheckDataVO.getDevMonitorIds();
                if (CollUtil.isNotEmpty(devMonitorIds)) {
                    // 使用 StringBuilder 构建带引号的ID列表，防止SQL注入
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < devMonitorIds.size(); i++) {
                        if (i > 0) sb.append(",");
                        sb.append("'").append(devMonitorIds.get(i)).append("'");
                    }
                    String devMonitorIdsStr = sb.toString();

                    jdbcTemplate.update("DELETE FROM " + mainHarmonicTableName + " WHERE dev_monitor_id IN (" + devMonitorIdsStr + ")");
                    jdbcTemplate.update("DELETE FROM " + mainNonHarmonicTableName + " WHERE dev_monitor_id IN (" + devMonitorIdsStr + ")");
                    jdbcTemplate.update("DELETE FROM " + mainHarmonicResultTableName + " WHERE dev_monitor_id IN (" + devMonitorIdsStr + ")");
                    jdbcTemplate.update("DELETE FROM " + mainNonHarmonicResultTableName + " WHERE dev_monitor_id IN (" + devMonitorIdsStr + ")");
                }
                int dataBatch = planCheckDataVO.getDataBatch();
                int stepCount = dataBatch * BATCH_SIZE / FINAL_STEP;

                for (File dataFile : dataFiles) {
                    // 直接插入主计划表中
                    String fileName = FileUtil.mainName(dataFile);

                    String tableName = fileName + StrUtil.UNDERLINE + planCode;

                    // 使用BatchFileReader分批处理文件
                    final boolean[] isFirstBatch = {true};
                    final String[] headers = {null};

                    BatchFileReader.readLinesInBatches(dataFile, BATCH_SIZE, lines -> {
                        dataCount.addAndGet(lines.size());
                        // 计算当前进度
                        int current = dataCount.get() / stepCount;

                        // 确保进度不超过finalStep
                        if (current > FINAL_STEP) {
                            current = FINAL_STEP;
                        }
                        currentProgress.set(current);
                        sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress.get() + currentProgress.get(), "同步检测数据信息中，请耐心等待..."));


                        if (CollUtil.isNotEmpty(lines)) {
                            if (isFirstBatch[0]) {
                                // 第一批次的第一行为字段名
                                headers[0] = lines.get(0);
                                // 处理剩余行作为数据
                                if (lines.size() > 1) {
                                    List<String> dataLines = lines.subList(1, lines.size());
                                    processBatchData(tableName, headers[0], dataLines);
                                }
                                isFirstBatch[0] = false;
                            } else {
                                // 后续批次全部为数据行
                                processBatchData(tableName, headers[0], lines);
                            }
                        }
                    });


                    progress.addAndGet(1);
                    sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress.get() + currentProgress.get(), "表 " + tableName + " 数据同步完成"));
                }
            }

            // 删除临时目录
            FileUtil.del(tempDir);
            // 更新主计划状态
            List<String> planIds = adPlanService.lambdaQuery().eq(AdPlan::getFatherPlanId, planId).list().stream().map(AdPlan::getId).collect(Collectors.toList());
            planIds.add(planId);
            List<String> devIds = pqDevService.lambdaQuery().in(PqDev::getPlanId, planIds).list().stream().map(PqDev::getId).collect(Collectors.toList());
            List<PqDevSub> devSubs = pqDevSubService.lambdaQuery().in(PqDevSub::getDevId, devIds).list();
            boolean allUnchecked = devSubs.stream().allMatch(sub -> CheckStateEnum.UNCHECKED.getValue().equals(sub.getCheckState()));
            boolean allArchived = devSubs.stream().allMatch(sub -> sub.getCheckState() != null && sub.getCheckState() >= CheckStateEnum.DOCUMENTED.getValue());
            if (allUnchecked) {
                plan.setTestState(CheckStateEnum.UNCHECKED.getValue());
            } else if (allArchived && !devSubs.isEmpty()) {
                plan.setTestState(CheckStateEnum.CHECKED.getValue());
            } else {
                plan.setTestState(CheckStateEnum.CHECKING.getValue());
            }
            adPlanService.updateById(plan);
            LocalDateTime endTime = LocalDateTime.now();
            log.info("数据合并完成，耗时：{}s", Duration.between(startTime, endTime).getSeconds());
            progress.set(100);
            sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.SUCCESS.getCode(), progress, "数据合并完成"));

        } catch (Exception e) {

            log.error("导入数据失败", e);
            sseClient.sendMessage(uid, planId, HttpResultUtil.assembleResult(CommonResponseEnum.FAIL.getCode(), progress.get() + currentProgress.get(), "导入失败"));
        } finally {
            NonWebAutoFillValueHandler.clearCurrentUserId();
        }
        FileUtil.del(zipFilePath);
        sseClient.closeSse(uid);
    }

    // 构建分页查询SQL
    private String buildPaginatedQuery(String tableName, List<String> devMonitorIds, int limit, int offset) {
        StringBuilder sql = new StringBuilder("SELECT * FROM " + tableName);

        sql.append(" WHERE Dev_Monitor_Id IN (");
        for (int i = 0; i < devMonitorIds.size(); i++) {
            sql.append("'").append(devMonitorIds.get(i)).append("'");
            if (i < devMonitorIds.size() - 1) {
                sql.append(",");
            }
        }
        sql.append(")");
        sql.append(" ORDER BY Id");

        // 添加分页限制
        sql.append(" LIMIT ").append(limit).append(" OFFSET ").append(offset);

        return sql.toString();
    }

    /**
     * 处理数据行
     *
     * @param tableName 表名
     * @param headers   表头
     * @param lines     数据行
     */
    private void processBatchData(String tableName, String headers, List<String> lines) {
        if (lines == null || lines.isEmpty()) {
            return;
        }
        // 构建INSERT语句
        String[] headerArray = headers.split("\t");
        String columnNames = String.join(",", headerArray);
        String placeholders = String.join(",", java.util.Collections.nCopies(headerArray.length, "?"));
        String sql = "INSERT INTO " + tableName + " (" + columnNames + ") VALUES (" + placeholders + ")";

        // 批量插入数据
        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(java.sql.PreparedStatement ps, int i) throws java.sql.SQLException {
                String line = lines.get(i);
                String[] fields = line.split("\t", -1); // 使用-1限制以保留空值

                for (int j = 0; j < fields.length && j < headerArray.length; j++) {
                    String value = fields[j];
                    if (StrUtil.isEmpty(value) || StrUtil.equals(value, StrUtil.NULL)) {
                        ps.setNull(j + 1, java.sql.Types.VARCHAR);
                    } else {
                        ps.setString(j + 1, value);
                    }
                }
            }

            @Override
            public int getBatchSize() {
                return lines.size();
            }
        });
    }
}
