package com.yunyan.business.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yunyan.business.constant.FinalDataStatus;
import com.yunyan.business.constant.TemplateEpType;
import com.yunyan.business.document.y22.FinalY22Utils;
import com.yunyan.business.document.y22.ReadFileNoFIllDeptUtils;
import com.yunyan.business.document.y22.UpdateReportFinalData;
import com.yunyan.business.document.y22.pojo.finalExcelY22.FinalExcelDataVo;
import com.yunyan.business.document.y22.pojo.finalExcelY22.FinalP1Vo;
import com.yunyan.business.document.y22.pojo.finalExcelY22.FinalP3T8NoFillDeptVo;
import com.yunyan.business.document.y23.budget.BudgetExcelY23ForFinalUtils;
import com.yunyan.business.document.y23.budget.ReadBudT5T8ExcelY23Utils;
import com.yunyan.business.document.y23.budget.ReadBudgetExcelT6Y22Utils;
import com.yunyan.business.document.y23.budget.pojo.budgetY23.BudgetDataVo;
import com.yunyan.business.document.y23.budget.pojo.budgetY23.BudgetP3p5SubDeptVo;
import com.yunyan.business.document.y23.budget.pojo.budgetY23.BudgetP3p8DeptVo;
import com.yunyan.business.document.y23.budget.pojo.budgetY23.BudgetT6DeptVo;
import com.yunyan.business.document.y23.finalData.FinalY23BudgetCompareUtils;
import com.yunyan.business.document.y23.finalData.FinalY23CompareLastUtils;
import com.yunyan.business.document.y23.finalData.ReadFinalExcelY23Utils;
import com.yunyan.business.domain.CourseCode;
import com.yunyan.business.domain.FinalData;
import com.yunyan.business.domain.ReportExplain;
import com.yunyan.business.mapper.FinalDataMapper;
import com.yunyan.business.pojo.admin.dto.FinalImportExcelDto;
import com.yunyan.business.service.*;
import com.yunyan.common.config.YunYanConfig;
import com.yunyan.common.constant.Constants;
import com.yunyan.common.core.domain.AjaxResultVo;
import com.yunyan.common.core.domain.entity.SysDept;
import com.yunyan.common.utils.DateUtils;
import com.yunyan.common.utils.StringUtils;
import com.yunyan.common.utils.spring.SpringUtils;
import com.yunyan.system.service.ISysDeptService;
import com.yunyan.system.service.ISysOperLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;

/**
 * 报告数据Service业务层处理
 *
 * @author yunyan
 * @date 2023-07-27
 */
@Slf4j
@Service
public class FinalImport2023ServiceImpl extends ServiceImpl<FinalDataMapper, FinalData> implements IFinalImport2023Service
{
    @Autowired
    private FinalDataMapper finalDataMapper;

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private ICourseCodeService courseCodeService;

    @Autowired
    private ISysOperLogService sysOperLogService;

    @Autowired
    private IReportExplainService reportExplainService;

    @Autowired
    private IFinalDataService finalDataService;

    @Autowired
    private IReportFillService reportFillService;

    //    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResultVo finalImportExcel(FinalImportExcelDto dto) {

        if(dto.getDataType().equals(0)) {
            //新数据的处理
            finalImportExcelNewYear(dto);
        } else if(dto.getDataType().equals(1)) {
            //对比上一年数据的处理
            finalImportExcelLastYear(dto);
        } else if(dto.getDataType().equals(3)) {
            //对比本年 预算数据的处理
            finalImportExcelYearBudget(dto);
        } else if(dto.getDataType().equals(50)) {
            //对比本年 预算表5的处理
            return finalImportExcelBudgetT5(dto);
        } else if(dto.getDataType().equals(60)) {
            //对比本年 预算表6的处理
            return finalImportExcelBudgetT6(dto);
        }
        return null;
    }

    /**
     * 新数据的决算(当年数据)
     * @param dto
     */
    private void finalImportExcelNewYear( FinalImportExcelDto dto) {
        //查询编码
        List<CourseCode> codeList = courseCodeService.getCodeListByType(1);

        try
        {
            //日志中 记录 导入的记录
            JSONObject jsonObject = new JSONObject();
            jsonObject.fluentPut("date", DateUtil.formatDateTime(new Date()));
            List<String> noInDeptList = new ArrayList<>();
            List<String> noInBudgetDataList = new ArrayList<>();
            List<String> exceptionList = new ArrayList<>();

            // 本机地址的文件路径
            String localPath = YunYanConfig.getProfile();
            ArrayList< String> fileNamesList = dto.getFileNamesList();
            ArrayList< String> originalFilenamesList = dto.getOriginalFilenamesList();

            //p3p8部分 不用填报的单位
            List<FinalP3T8NoFillDeptVo> p3T8NoFillDeptVoList = ReadFileNoFIllDeptUtils.readData();

            //多线程 处理
            //每个线程至少同步30条记录，计算线程数，不超过10个线程
            int threadSize = Math.min((int) Math.ceil(fileNamesList.size() / 30D), 10);
//            threadSize = 2;
            //计算平均每个任务数
            int taskNum = (int) Math.ceil(fileNamesList.size() / (float) threadSize);

            final Integer[] successNum = new Integer[]{0};

            List<Future> taskList = new ArrayList<>();
            ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
            for (int j = 0, size = threadSize - 1; j <= size; j++) {

                List<String> subFileNamesList= fileNamesList.subList(j * taskNum, j < size ? (j + 1) * taskNum : fileNamesList.size());
                List<String> subOriginalFilenamesList= originalFilenamesList.subList(j * taskNum, j < size ? (j + 1) * taskNum : originalFilenamesList.size());
                taskList.add(executor.submit(() -> {
                    //保存 excel的 决算的本年数据
                    saveExcelFinalNewData(subFileNamesList, localPath, subOriginalFilenamesList, codeList, dto, noInDeptList, noInBudgetDataList, exceptionList, successNum, p3T8NoFillDeptVoList);
                }));
            }
            for (Future f : taskList) {
                while (true) {
                    if (f.isDone() && !f.isCancelled()) {
                        //log.debug("导入的文件线程 结束");
                        break;
                    }
                }
            }

            jsonObject.putArray("noInBudgetDataList");
            jsonObject.putArray("noInDeptList");
            jsonObject.putArray("exceptionList");
            jsonObject.getJSONArray("noInBudgetDataList").fluentAddAll(noInBudgetDataList);
            jsonObject.getJSONArray("noInDeptList").fluentAddAll(noInDeptList);
            jsonObject.getJSONArray("exceptionList").fluentAddAll(exceptionList);
            //成功
            jsonObject.fluentPut("successNum", String.format("插入的数量: %s", successNum[0]));

            //记录日志 如果是 没有异常的, 返回 0
            Integer operStatus = noInBudgetDataList.isEmpty() && noInDeptList.isEmpty() && exceptionList.isEmpty() ? 0 : 1;
            sysOperLogService.insertOperlog(sysOperLogService.createSysOperLog("决算采集-本年", 1, "com.yunyan.web.controller.business.FinalDataController.finalImportExcel()",
                    "POST", operStatus, jsonObject.toJSONString()));
        }
        catch (Exception e)
        {
            log.error("决算导入出现异常: [{}] - [{}]", e.getMessage(), e);
        }
    }


    /**
     * 保存 excel的 决算的本年数据
     * @param subFileNamesList 文件名
     * @param localPath 本地位置
     * @param subOriginalFilenamesList 源文件名
     * @param codeList 编码列表
     * @param dto
     * @param noInDeptList 不在部门中的异常
     * @param noInBudgetDataList 没有预算数据的异常
     * @param exceptionList 导入异常的list
     * @param successNum
     * @param p3T8NoFillDeptVoList p3t8部分未填报的部门
     */
    private void saveExcelFinalNewData(List<String> subFileNamesList, String localPath, List<String> subOriginalFilenamesList, List<CourseCode> codeList,
                                      FinalImportExcelDto dto, List<String> noInDeptList, List<String> noInBudgetDataList, List<String> exceptionList, Integer[] successNum, List<FinalP3T8NoFillDeptVo> p3T8NoFillDeptVoList) {
        //读取 本地的本年的 预算
        //上次的区域
        String area = dto.getArea();
        int i = 0;
        //年份
        String year = dto.getYear();
        Integer deptNameBy = dto.getDeptNameBy();

        SysDept sysDeptArea = sysDeptService.getfinalExportTypeByArea(area);
        if(null == sysDeptArea || StringUtils.isBlank(sysDeptArea.getFinalExportType())) {
            exceptionList.add("区域还未设置模板类型~");
            return;
        }
        String templateExportType = sysDeptArea.getFinalExportType();

        //预算表8 的 主要用于更新p3p4部分的项
        List<BudgetP3p8DeptVo> p2p8DeptList = null;

        for (String fileName : subFileNamesList) {

            String absolutePathName = localPath + StringUtils.substringAfter(fileName, Constants.RESOURCE_PREFIX);
            String originalFilename = subOriginalFilenamesList.size() - 1 >= i ? subOriginalFilenamesList.get(i++) : "";
            try {
                FinalData finalData = new FinalData();
                //类型
                finalData.setType(1);

                //读取 excel中的编制单位名称
                String deptName = "";
                if(null != deptNameBy && 2 == deptNameBy) {
                    //田东 部分部门的取 文件名的 编制单位来匹配
                    deptName = originalFilename.substring(0, originalFilename.indexOf("."));
                }
                if(StringUtils.isBlank(deptName)) {
                    exceptionList.add("文件名未找到编制单位, 请检查文件名是否正确~");
                    continue;
                }

                //关联部门id
                SysDept sysDept=  sysDeptService.getDeptByName(deptName, "");

                //读取 excel
                FinalExcelDataVo finalExcelDataVo = ReadFinalExcelY23Utils.getFinalExcelDataVo(year, deptName, templateExportType);
                ReadFinalExcelY23Utils.getSheetInfos(null, absolutePathName, finalExcelDataVo, 0, templateExportType);

                //设置表6的编码 设置 p3p3部分的款级
                UpdateReportFinalData.updateCourseCode(finalExcelDataVo, codeList);

                //保存的excel数据
                finalData.setExcelTitle(originalFilename);
                finalData.setExcelUrl(fileName);
                finalData.setExcelDeptName(finalExcelDataVo.getDeptName());
                finalData.setTemplateExportType(templateExportType);

                FinalP1Vo finalP1Vo = new FinalP1Vo();
                if(null != sysDept) {
                    finalData.setDeptId(sysDept.getDeptId());
                    finalData.setParentDeptId(sysDept.getParentId());
                    finalExcelDataVo.setDeptCode(sysDept.getDeptCode());
                    //设置编制单位
                    finalData.setExcelDeptName(sysDept.getDeptName());

                    //区域 来查询  预算数据的文件
                    if(StringUtils.isNotBlank(area) ) {
                        p2p8DeptList = ReadBudgetExcelT6Y22Utils.readDataT8(area, year);
                    }

                    //取文件里的数据 预算
                    BudgetP3p5SubDeptVo p2p5SubDeptVo = ReadBudgetExcelT6Y22Utils.readDataP3t5(sysDept.getDeptCode(), sysDept.getArea(), year);
                    if(null == p2p5SubDeptVo) {
                        log.debug("没有p3t2部分的年初预算");
                        noInBudgetDataList.add(String.format("[%s] 没有第三部分第二小部分的年初预算", deptName));
                    }
                    FinalY23CompareLastUtils.compareDataBudget(finalExcelDataVo, p2p5SubDeptVo, sysDept.getArea(), year, templateExportType);
                    //设置p3p4的项
                    FinalY23CompareLastUtils.compareDataP3T4Budget(finalExcelDataVo, p2p8DeptList, sysDept.getDeptCode());
                } else {
                    finalData.setDeptId(0L);
                    finalData.setParentDeptId(0L);
                    finalP1Vo.setDuty("");
                    finalP1Vo.setSettings("");
                    finalP1Vo.setBudgetInfo("");
                    finalExcelDataVo.setDeptCode("");

                    finalExcelDataVo.setP1Vo(finalP1Vo);

                    noInDeptList.add(String.format("[%s] 决算单位没有在单位管理中", deptName));

                }
                finalData.setUserId(0L);

                //rowNo 排序
                FinalY22Utils.setListRowNo(finalExcelDataVo);

                //状态
                finalData.setStatus(FinalDataStatus.YEAR_DATA.getCode());
                //取传值的年份
                finalData.setYear(year);

                //保存 excel读取数据
                String jsonTableContent = JSONUtil.toJsonStr(finalExcelDataVo);
                boolean saveRes = finalDataService.saveFinalDataAndReportExplain(finalData, jsonTableContent, null);

                if(saveRes) {
                    successNum[0]++;
                }

            } catch (Exception e) {
                log.error("读取 决算以及保存的过程异常: [{}],  [{}]", e.getMessage(), e);
                exceptionList.add(String.format("[%s] 决算单位导入的出现异常：[%s]", originalFilename, e.getMessage()));
            }

        }
    }

    /**
     * 记录 决算导入的 日志到文件
     * @param errMsgDept
     * @param fileName
     */
    private void saveExcelImportLog(String errMsgDept, String fileName) {
        if(StringUtils.isBlank(errMsgDept)) {
            return;
        }

        String defaultBaseDir = YunYanConfig.getProfile();
        String errMsgFileName = StringUtils.format("{}/{}.{}", DateUtils.datePath(), FilenameUtils.getBaseName(fileName),  "txt");
        String errMsgFilePath = defaultBaseDir + File.separator + ".." + File.separator + "businessLog" + File.separator;
        String errMsgFilePathName = errMsgFilePath + errMsgFileName;
        File errMsgFile = new File(errMsgFilePathName);
        if (!errMsgFile.exists())
        {
            if (!errMsgFile.getParentFile().exists())
            {
                errMsgFile.getParentFile().mkdirs();
            }
            if(!errMsgFile.exists()) {
                try {
                    errMsgFile.createNewFile();
                } catch (IOException e) {
                    log.debug("创建文件失败");
                }
            }
        }

        if( errMsgFile!= null && errMsgFile.isFile() && errMsgFile.exists()) {
            //文件记录
            FileUtil.appendUtf8String(errMsgDept, errMsgFile);
        }
    }

    /**
     * 去年的数据(对比用)
     * 不用进行保存， 进行关联
     * @param
     * @param dto
     */
    private void finalImportExcelLastYear(FinalImportExcelDto dto) {
        try
        {
            JSONObject jsonObject = new JSONObject();
            jsonObject.fluentPut("date", DateUtil.formatDateTime(new Date()));
            List<String> noInYearList = new ArrayList<>();
            List<String> exceptionList = new ArrayList<>();

            // 本机地址的文件路径
            String localPath = YunYanConfig.getProfile();
            ArrayList< String> fileNamesList = dto.getFileNamesList();
            ArrayList< String> originalFilenamesList = dto.getOriginalFilenamesList();

            /*String[] fileNames = dto.getFileNames().split(FILE_DELIMETER);
            String[] newFileNames = dto.getNewFileNames().split(FILE_DELIMETER);
            String[] originalFilenames = dto.getOriginalFilenames().split(FILE_DELIMETER);

            //数组转 list
            ArrayList< String> fileNamesList = new ArrayList<>(fileNames.length);
            Collections.addAll(fileNamesList, fileNames);
            ArrayList< String> originalFilenamesList = new ArrayList<>(originalFilenames.length);
            Collections.addAll(originalFilenamesList, originalFilenames);*/

            //成功的数量
            final Integer[] successNum = new Integer[]{0};

            //多线程 处理
            //每个线程至少同步30条记录，计算线程数，不超过10个线程
            int threadSize = Math.min((int) Math.ceil(fileNamesList.size() / 30D), 10);
//            threadSize = 2;
            //计算平均每个任务数
            int taskNum = (int) Math.ceil(fileNamesList.size() / (float) threadSize);

            List<Future> taskList = new ArrayList<>();
            ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
            for (int j = 0, size = threadSize - 1; j <= size; j++) {

                List<String> subFileNamesList= fileNamesList.subList(j * taskNum, j < size ? (j + 1) * taskNum : fileNamesList.size());
                List<String> subOriginalFilenamesList= originalFilenamesList.subList(j * taskNum, j < size ? (j + 1) * taskNum : originalFilenamesList.size());
                taskList.add(executor.submit(() -> {

                    //保存 excel的 决算的去年数据
                    saveExcelFinalLastData(subFileNamesList, localPath,subOriginalFilenamesList, dto, noInYearList, exceptionList, successNum);
                }));
            }
            for (Future f : taskList) {
                while (true) {
                    if (f.isDone() && !f.isCancelled()) {
                        //log.debug("导入的文件线程 结束");
                        break;
                    }
                }
            }

            jsonObject.putArray("noInYearList");
            jsonObject.putArray("exceptionList");
            jsonObject.getJSONArray("noInYearList").fluentAddAll(noInYearList);
            jsonObject.getJSONArray("exceptionList").fluentAddAll(exceptionList);

            //成功
            jsonObject.fluentPut("successNum", String.format("插入的数量: %s", successNum[0]));

            //记录日志 如果是 没有异常的, 返回 0
            Integer operStatus =  noInYearList.isEmpty() && exceptionList.isEmpty() ? 0 : 1;
            sysOperLogService.insertOperlog(sysOperLogService.createSysOperLog("决算采集-去年", 2, "com.yunyan.web.controller.business.FinalDataController.finalImportExcel()",
                    "PUST", operStatus, jsonObject.toJSONString()));

        }
        catch (Exception e)
        {
            log.debug("导入决算的去年数据异常: [{}] [{}]", e.getMessage(), e);
//            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 保存 决算的 excel数据 前一年的
     * @param subFileNamesList
     * @param localPath
     * @param subOriginalFilenamesList
     * @param dto
     * @param noInYearList
     * @param exceptionList
     */
    private void saveExcelFinalLastData(List<String> subFileNamesList, String localPath, List<String> subOriginalFilenamesList,
                                       FinalImportExcelDto dto, List<String> noInYearList, List<String> exceptionList, Integer[] successNum) {

        //年份
        String year = dto.getYear();
        Integer deptNameBy = dto.getDeptNameBy();

        //上次的区域
        String area = dto.getArea();
        SysDept sysDeptArea = sysDeptService.getfinalExportTypeByArea(area);
        if(null == sysDeptArea || StringUtils.isBlank(sysDeptArea.getFinalExportType())) {
            exceptionList.add("区域还未设置模板类型~");
            return;
        }
        String templateExportType = sysDeptArea.getFinalExportType();

        int i = 0;
        for (String fileName : subFileNamesList ) {
            String absolutePathName = localPath + StringUtils.substringAfter(fileName, Constants.RESOURCE_PREFIX);
            String originalFilename = subOriginalFilenamesList.size() - 1 >= i ? subOriginalFilenamesList.get(i++) : "";
            try {
                //读取 excel中的编制单位名称
                String deptName = "";
                if(null != deptNameBy && 2 == deptNameBy) {
                    //田东 部分部门的取 文件名的 编制单位来匹配
                    deptName = originalFilename.substring(0, originalFilename.indexOf("."));
                }
                //替换 前2个字 为广西的 , 去掉首个
                //deptName = UpdateReportFinalData.replaceStartIndexStr(deptName, "广西", "");
                if(StringUtils.isBlank(deptName)) {
                    exceptionList.add("文件名未找到编制单位, 请检查文件名是否正确~");
                    continue;
                }

                //读取 excel
                FinalExcelDataVo finalExcelLastYearDataVo = ReadFinalExcelY23Utils.getFinalExcelDataVo(year, deptName, templateExportType);
                ReadFinalExcelY23Utils.getSheetInfos(null, absolutePathName, finalExcelLastYearDataVo, 1, templateExportType);

                List<FinalData> finalDataList = this.lambdaQuery().eq(FinalData::getExcelDeptName, deptName).eq(FinalData::getType, 1)
                        .eq(FinalData::getYear, year).eq(FinalData::getStatus, FinalDataStatus.YEAR_DATA.getCode())
                        .select(FinalData::getId, FinalData::getDeptId, FinalData::getYear).orderByDesc(FinalData::getId).list();

                FinalData finalData = null;
                if(!finalDataList.isEmpty()) {
                    finalData = finalDataList.get(0);
                }
                if(null == finalData) {
                    log.error("[{}] 未查到已导入的决算年份的数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);

                    noInYearList.add(String.format("[%s] 决算单位没有在已导入的本年数据中", deptName));
                    continue;
                }

                //查询 报告数据json
                ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
                String jsonContent = reportExplain.getJsonContent();
                if(null == reportExplain || StringUtils.isBlank(jsonContent)) {
                    log.error("[{}] 未查到已导入的决算年份的报告数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);

                    noInYearList.add(String.format("[%s] 决算单位没有在已导入的本年数据中", deptName));
                    continue;
                }

                //json数据
                FinalExcelDataVo dataVo = JSONUtil.toBean(jsonContent, FinalExcelDataVo.class);
                // 对比 本年的数据， 保存
                FinalY23CompareLastUtils.compareData(dataVo, finalExcelLastYearDataVo);

                //复制之前的旧的填写的
                Long reportId = finalDataService.getLastFillReportId(finalData.getDeptId(), Integer.valueOf(finalData.getYear()));
                if(!Objects.isNull(reportId)) {
                    String updateVoJson = reportFillService.getReportFillLast(reportId);
                    if(StringUtils.isNotBlank(updateVoJson)) {
                        //保存 填报的数据
                        FinalExcelDataVo updateVo = JSONUtil.toBean(updateVoJson, FinalExcelDataVo.class);
                        //更新 填报的信息
                        try {
                            UpdateReportFinalData.updateFillData(dataVo, updateVo);
                        } catch (Exception e) {
                            log.error("更新 填报的信息异常: [{}],  [{}]", e.getMessage(), e);
                        }

                    }
                }

                //json 转对象
                String jsonTableContent = JSONUtil.toJsonStr(dataVo);
                // 去年的 json对象  保存 excel读取数据, 去年
                //String jsonLastYearContent = JSONUtil.toJsonStr(finalExcelLastYearDataVo);

                //更新 保存 去年的 excel数据
                FinalData updateEntity = new FinalData();
                updateEntity.setId(finalData.getId());
                updateEntity.setStatus(FinalDataStatus.LAST_DATA.getCode());
                //保存 去年的 数据的 excel
                updateEntity.setExcelUrlLast(fileName);

                //保存 excel读取数据
                boolean updateRes = finalDataService.saveFinalDataAndReportExplain(updateEntity, jsonTableContent, reportExplain.getId());


                if(updateRes) {
                    successNum[0]++;
                }
            } catch (Exception e) {
                log.error("读取 预决算以及保存的过程异常: [{}],  [{}]", e.getMessage(), e);
                exceptionList.add(String.format("[%s] 决算单位导入的出现异常：[%s]", originalFilename, e.getMessage()));
            }
        }
    }

    private void finalImportExcelYearBudget(FinalImportExcelDto dto) {
        try
        {
            JSONObject jsonObject = new JSONObject();
            jsonObject.fluentPut("date", DateUtil.formatDateTime(new Date()));
            List<String> noInYearList = new ArrayList<>();
            List<String> exceptionList = new ArrayList<>();

            // 本机地址的文件路径
            String localPath = YunYanConfig.getProfile();
            ArrayList< String> fileNamesList = dto.getFileNamesList();
            ArrayList< String> originalFilenamesList = dto.getOriginalFilenamesList();

            /*String[] fileNames = dto.getFileNames().split(FILE_DELIMETER);
            String[] newFileNames = dto.getNewFileNames().split(FILE_DELIMETER);
            String[] originalFilenames = dto.getOriginalFilenames().split(FILE_DELIMETER);

            //数组转 list
            ArrayList< String> fileNamesList = new ArrayList<>(fileNames.length);
            Collections.addAll(fileNamesList, fileNames);
            ArrayList< String> originalFilenamesList = new ArrayList<>(originalFilenames.length);
            Collections.addAll(originalFilenamesList, originalFilenames);*/

            //成功的数量
            final Integer[] successNum = new Integer[]{0};

            //多线程 处理
            //每个线程至少同步30条记录，计算线程数，不超过10个线程
            int threadSize = Math.min((int) Math.ceil(fileNamesList.size() / 30D), 10);
//            threadSize = 2;
            //计算平均每个任务数
            int taskNum = (int) Math.ceil(fileNamesList.size() / (float) threadSize);

            List<Future> taskList = new ArrayList<>();
            ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
            for (int j = 0, size = threadSize - 1; j <= size; j++) {

                List<String> subFileNamesList= fileNamesList.subList(j * taskNum, j < size ? (j + 1) * taskNum : fileNamesList.size());
                List<String> subOriginalFilenamesList= originalFilenamesList.subList(j * taskNum, j < size ? (j + 1) * taskNum : originalFilenamesList.size());
                taskList.add(executor.submit(() -> {

                    //保存 excel的 决算的去年数据
                    saveExcelFinalYearBudget(subFileNamesList, localPath,subOriginalFilenamesList, dto, noInYearList, exceptionList, successNum);
                }));
            }
            for (Future f : taskList) {
                while (true) {
                    if (f.isDone() && !f.isCancelled()) {
                        //log.debug("导入的文件线程 结束");
                        break;
                    }
                }
            }

            jsonObject.putArray("noInYearList");
            jsonObject.putArray("exceptionList");
            jsonObject.getJSONArray("noInYearList").fluentAddAll(noInYearList);
            jsonObject.getJSONArray("exceptionList").fluentAddAll(exceptionList);

            //成功
            jsonObject.fluentPut("successNum", String.format("插入的数量: %s", successNum[0]));

            //记录日志 如果是 没有异常的, 返回 0
            Integer operStatus =  noInYearList.isEmpty() && exceptionList.isEmpty() ? 0 : 1;
            sysOperLogService.insertOperlog(sysOperLogService.createSysOperLog("决算采集-本年预算", 2, "com.yunyan.web.controller.business.FinalDataController.finalImportExcel()",
                    "PUST", operStatus, jsonObject.toJSONString()));

        }
        catch (Exception e)
        {
            log.debug("导入决算的决算采集-本年预算异常: [{}] [{}]", e.getMessage(), e);
        }
    }

    /**
     * 保存 决算的 excel数据 前一年的
     * @param subFileNamesList
     * @param localPath
     * @param subOriginalFilenamesList
     * @param dto
     * @param noInYearList
     * @param exceptionList
     */
    private void saveExcelFinalYearBudget(List<String> subFileNamesList, String localPath, List<String> subOriginalFilenamesList,
                                        FinalImportExcelDto dto, List<String> noInYearList, List<String> exceptionList, Integer[] successNum) {

        //年份
        String year = dto.getYear();
        Integer deptNameBy = dto.getDeptNameBy();

        //上次的区域
        String area = dto.getArea();
        SysDept sysDeptArea = sysDeptService.getfinalExportTypeByArea(area);
        if(null == sysDeptArea || StringUtils.isBlank(sysDeptArea.getFinalExportType())) {
            exceptionList.add("区域还未设置模板类型~");
            return;
        }
        String templateExportType = sysDeptArea.getFinalExportType();

        int i = 0;
        for (String fileName : subFileNamesList ) {
            String absolutePathName = localPath + StringUtils.substringAfter(fileName, Constants.RESOURCE_PREFIX);
            String originalFilename = subOriginalFilenamesList.size() - 1 >= i ? subOriginalFilenamesList.get(i++) : "";
            try {
                //读取 excel中的编制单位名称
                String deptName = originalFilename.substring(0, originalFilename.indexOf("."));
                if(StringUtils.isBlank(deptName)) {
                    exceptionList.add("文件名未找到编制单位, 请检查文件名是否正确~");
                    continue;
                }

                //读取 excel
                BudgetDataVo budgetDataVo = BudgetExcelY23ForFinalUtils.getSheetInfos(null, absolutePathName, 1, dto.getYear(), templateExportType);

                List<FinalData> finalDataList = this.lambdaQuery().eq(FinalData::getExcelDeptName, deptName).eq(FinalData::getType, 1)
                        .eq(FinalData::getYear, year)
                        .in(FinalData::getStatus, FinalDataStatus.YEAR_DATA.getCode(), FinalDataStatus.LAST_DATA.getCode(), FinalDataStatus.BUDGET_DATA.getCode(), FinalDataStatus.FILL_DATA.getCode(), FinalDataStatus.FILL_DATA_NO_APPLY.getCode())
                        .select(FinalData::getId, FinalData::getDeptId, FinalData::getStatus).orderByDesc(FinalData::getId).list();

                FinalData finalData = null;
                if(!finalDataList.isEmpty()) {
                    finalData = finalDataList.get(0);
                }
                if(null == finalData) {
                    log.error("[{}] 未查到已导入的决算年份的数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);

                    noInYearList.add(String.format("[%s] 决算单位没有在已导入的本年数据中", deptName));
                    continue;
                }

                //查询 报告数据json
                ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
                String jsonContent = reportExplain.getJsonContent();
                if(null == reportExplain || StringUtils.isBlank(jsonContent)) {
                    log.error("[{}] 未查到已导入的决算年份的报告数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);

                    noInYearList.add(String.format("[%s] 决算单位没有在已导入的本年数据中", deptName));
                    continue;
                }

                //json数据
                FinalExcelDataVo dataVo = JSONUtil.toBean(jsonContent, FinalExcelDataVo.class);
                // 对比 预算的数据， 保存
                FinalY23BudgetCompareUtils.setBudgetData(dataVo, budgetDataVo);

                //rowNo 排序
                FinalY22Utils.setListRowNo(dataVo);

                //json 转对象
                String jsonTableContent = JSONUtil.toJsonStr(dataVo);

                //更新 保存 去年的 excel数据
                FinalData updateEntity = new FinalData();
                updateEntity.setId(finalData.getId());
                if(FinalDataStatus.LAST_DATA.getCode().equals(finalData.getStatus())) {
                    updateEntity.setStatus(FinalDataStatus.BUDGET_DATA.getCode());
                } else {
                    updateEntity.setStatus(finalData.getStatus());
                }


                //保存 excel读取数据
                boolean updateRes = finalDataService.saveFinalDataAndReportExplain(updateEntity, jsonTableContent, reportExplain.getId());
                if(updateRes) {
                    successNum[0]++;
                }
            } catch (Exception e) {
                log.error("读取 预决算以及保存的过程异常: [{}],  [{}]", e.getMessage(), e);
                exceptionList.add(String.format("[%s] 决算单位导入的出现异常：[%s]", originalFilename, e.getMessage()));
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public AjaxResultVo finalImportExcelBudgetT5( FinalImportExcelDto dto) {
        //日志中 记录 导入的记录
        JSONObject jsonObject = new JSONObject();
        jsonObject.fluentPut("date", DateUtil.formatDateTime(new Date()));
        List<String> noInDeptList = new ArrayList<>();
        List<String> noInBudgetDataList = new ArrayList<>();
        List<String> exceptionList = new ArrayList<>();

        //成功的数量
        final Integer[] successNum = new Integer[]{0};

        // 本机地址的文件路径
        String localPath = YunYanConfig.getProfile();
        ArrayList<String> fileNamesList = dto.getFileNamesList();
        ArrayList<String> originalFilenamesList = dto.getOriginalFilenamesList();


        String area = dto.getArea();
        int i = 0;
        //年份
        String year = dto.getYear();
        Integer deptNameBy = dto.getDeptNameBy();

        SysDept sysDeptArea = sysDeptService.getfinalExportTypeByArea(area);
        if (null == sysDeptArea || StringUtils.isBlank(sysDeptArea.getFinalExportType())) {
            exceptionList.add("区域还未设置模板类型~");
            throw new RuntimeException("区域还未设置模板类型~");
        }
        String templateExportType = sysDeptArea.getFinalExportType();

        for (String fileName : fileNamesList) {
            String absolutePathName = localPath + StringUtils.substringAfter(fileName, Constants.RESOURCE_PREFIX);
            BudgetDataVo excelDataVo = null;
            try {
                excelDataVo = ReadBudT5T8ExcelY23Utils.getSheetT5OrT8Infos(null, absolutePathName, 0, 5);
            } catch (IOException e) {
                throw new RuntimeException("读取文件异常");
            }
            List<BudgetP3p5SubDeptVo> subDeptList = excelDataVo.getExplainVo().getP3p5Vo().getSubDeptList();
            for (BudgetP3p5SubDeptVo deptDataVo : subDeptList) {
                String deptName = deptDataVo.getDeptName();
                String deptCode = deptDataVo.getDeptCode();

                //关联部门id
                SysDept sysDept = sysDeptService.getDeptByDeptCode(deptCode, area);
                if (null == sysDept) {
                    throw new RuntimeException(String.format("[%s] - [%s] 在[%s]中未查到部门信息", deptName, deptCode, area));
                }

                List<FinalData> finalDataList = this.lambdaQuery().eq(FinalData::getDeptId, sysDept.getDeptId()).eq(FinalData::getType, 1)
                        .eq(FinalData::getYear, year)
                        .in(FinalData::getStatus, FinalDataStatus.YEAR_DATA.getCode(), FinalDataStatus.LAST_DATA.getCode(), FinalDataStatus.BUDGET_DATA.getCode(), FinalDataStatus.FILL_DATA.getCode(), FinalDataStatus.FILL_DATA_NO_APPLY.getCode())
                        .select(FinalData::getId, FinalData::getDeptId).orderByDesc(FinalData::getId).list();

                FinalData finalData = null;
                if (!finalDataList.isEmpty()) {
                    finalData = finalDataList.get(0);
                }
                if (null == finalData) {
                    log.error("[{}] 未查到已导入的决算年份的数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);
                    throw new RuntimeException(String.format("[%s] 未查到已导入的决算年份的数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName));
                }

                //查询 报告数据json
                ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
                String jsonContent = reportExplain.getJsonContent();
                if (null == reportExplain || StringUtils.isBlank(jsonContent)) {
                    log.error("[{}] 未查到已导入的决算年份的报告数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);
                    throw new RuntimeException(String.format("[%s] 决算单位没有在已导入的本年数据中", deptName));
                }

                //json数据
                FinalExcelDataVo dataVo = JSONUtil.toBean(jsonContent, FinalExcelDataVo.class);

                // 对比 预算的数据， 保存
                FinalY23CompareLastUtils.compareDataP3T2Budget(dataVo, deptDataVo);

                //json 转对象
                String jsonTableContent = JSONUtil.toJsonStr(dataVo);

                //更新 保存 去年的 excel数据
                FinalData updateEntity = new FinalData();
                updateEntity.setId(finalData.getId());
                if (FinalDataStatus.LAST_DATA.getCode().equals(finalData.getStatus())) {
                    updateEntity.setStatus(FinalDataStatus.BUDGET_DATA.getCode());
                } else {
                    updateEntity.setStatus(finalData.getStatus());
                }

                //保存 excel读取数据
                boolean updateRes = finalDataService.saveFinalDataAndReportExplain(updateEntity, jsonTableContent, reportExplain.getId());
                if(updateRes) {
                    successNum[0]++;
                }
            }
        }

        //记录日志 如果是 没有异常的, 返回 0
        Integer operStatus = noInBudgetDataList.isEmpty() && noInDeptList.isEmpty() && exceptionList.isEmpty() ? 0 : 1;
        sysOperLogService.insertOperlog(sysOperLogService.createSysOperLog("决算采集-本年", 1, "com.yunyan.web.controller.business.FinalDataController.finalImportExcel()",
                "POST", operStatus, jsonObject.toJSONString()));

        return AjaxResultVo.success(successNum[0]);
    }

    @Transactional(rollbackFor = Exception.class)
    public AjaxResultVo finalImportExcelBudgetT6( FinalImportExcelDto dto) {
        //日志中 记录 导入的记录
        JSONObject jsonObject = new JSONObject();
        jsonObject.fluentPut("date", DateUtil.formatDateTime(new Date()));
        List<String> noInDeptList = new ArrayList<>();
        List<String> noInBudgetDataList = new ArrayList<>();
        List<String> exceptionList = new ArrayList<>();

        //成功的数量
        final Integer[] successNum = new Integer[]{0};

        // 本机地址的文件路径
        String localPath = YunYanConfig.getProfile();
        ArrayList<String> fileNamesList = dto.getFileNamesList();
        ArrayList<String> originalFilenamesList = dto.getOriginalFilenamesList();


        String area = dto.getArea();
        int i = 0;
        //年份
        String year = dto.getYear();
        Integer deptNameBy = dto.getDeptNameBy();

        SysDept sysDeptArea = sysDeptService.getfinalExportTypeByArea(area);
        if (null == sysDeptArea || StringUtils.isBlank(sysDeptArea.getFinalExportType())) {
            exceptionList.add("区域还未设置模板类型~");
            throw new RuntimeException("区域还未设置模板类型~");
        }
        String templateExportType = sysDeptArea.getFinalExportType();

        for (String fileName : fileNamesList) {
            String absolutePathName = localPath + StringUtils.substringAfter(fileName, Constants.RESOURCE_PREFIX);
            //BudgetDataVo excelDataVo = null;
            List<BudgetT6DeptVo> list = null;
            try {
                list = ReadBudgetExcelT6Y22Utils.getSheetInfos(null, absolutePathName);
            } catch (IOException e) {
                throw new RuntimeException("读取文件异常");
            }
            for (BudgetT6DeptVo deptDataVo : list) {
                String deptName = deptDataVo.getDeptName();
                String deptCode = deptDataVo.getDeptCode();

                //关联部门id
                SysDept sysDept = sysDeptService.getDeptByDeptCode(deptCode, area);
                if (null == sysDept) {
                    throw new RuntimeException(String.format("[%s] - [%s] 在[%s]中未查到部门信息", deptName, deptCode, area));
                }

                List<FinalData> finalDataList = this.lambdaQuery().eq(FinalData::getDeptId, sysDept.getDeptId()).eq(FinalData::getType, 1)
                        .eq(FinalData::getYear, year)
                        .in(FinalData::getStatus, FinalDataStatus.YEAR_DATA.getCode(), FinalDataStatus.LAST_DATA.getCode(), FinalDataStatus.BUDGET_DATA.getCode(), FinalDataStatus.FILL_DATA.getCode(), FinalDataStatus.FILL_DATA_NO_APPLY.getCode())
                        .select(FinalData::getId, FinalData::getDeptId, FinalData::getTemplateExportType).orderByDesc(FinalData::getId).list();

                FinalData finalData = null;
                if (!finalDataList.isEmpty()) {
                    finalData = finalDataList.get(0);
                }
                if (null == finalData) {
                    log.error("[{}] 未查到已导入的决算年份的数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);
                    throw new RuntimeException(String.format("[%s] 未查到已导入的决算年份的数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName));
                }

                //查询 报告数据json
                ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
                String jsonContent = reportExplain.getJsonContent();
                if (null == reportExplain || StringUtils.isBlank(jsonContent)) {
                    log.error("[{}] 未查到已导入的决算年份的报告数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);
                    throw new RuntimeException(String.format("[%s] 决算单位没有在已导入的本年数据中", deptName));
                }

                //json数据
                FinalExcelDataVo dataVo = JSONUtil.toBean(jsonContent, FinalExcelDataVo.class);

                // 对比 预算的数据， 保存
                FinalY23CompareLastUtils.compareDataP3T3Budget(dataVo, deptDataVo, templateExportType);

                //rowNo 排序
                FinalY22Utils.setListRowNo(dataVo);

                //json 转对象
                String jsonTableContent = JSONUtil.toJsonStr(dataVo);

                //更新 保存 去年的 excel数据
                FinalData updateEntity = new FinalData();
                updateEntity.setId(finalData.getId());
                if (FinalDataStatus.LAST_DATA.getCode().equals(finalData.getStatus())) {
                    updateEntity.setStatus(FinalDataStatus.BUDGET_DATA.getCode());
                } else {
                    updateEntity.setStatus(finalData.getStatus());
                }

                //保存 excel读取数据
                boolean updateRes = finalDataService.saveFinalDataAndReportExplain(updateEntity, jsonTableContent, reportExplain.getId());
                if(updateRes) {
                    successNum[0]++;
                }
            }
        }

        //记录日志 如果是 没有异常的, 返回 0
        Integer operStatus = noInBudgetDataList.isEmpty() && noInDeptList.isEmpty() && exceptionList.isEmpty() ? 0 : 1;
        sysOperLogService.insertOperlog(sysOperLogService.createSysOperLog("决算采集-本年", 1, "com.yunyan.web.controller.business.FinalDataController.finalImportExcel()",
                "POST", operStatus, jsonObject.toJSONString()));
        return AjaxResultVo.success(successNum[0]);
    }

    @Transactional(rollbackFor = Exception.class)
    public AjaxResultVo finalImportExcelBudgetT8( FinalImportExcelDto dto) {
        //日志中 记录 导入的记录
        JSONObject jsonObject = new JSONObject();
        jsonObject.fluentPut("date", DateUtil.formatDateTime(new Date()));
        List<String> noInDeptList = new ArrayList<>();
        List<String> noInBudgetDataList = new ArrayList<>();
        List<String> exceptionList = new ArrayList<>();

        //成功的数量
        final Integer[] successNum = new Integer[]{0};

        // 本机地址的文件路径
        String localPath = YunYanConfig.getProfile();
        ArrayList<String> fileNamesList = dto.getFileNamesList();
        ArrayList<String> originalFilenamesList = dto.getOriginalFilenamesList();


        String area = dto.getArea();
        int i = 0;
        //年份
        String year = dto.getYear();
        Integer deptNameBy = dto.getDeptNameBy();

        SysDept sysDeptArea = sysDeptService.getfinalExportTypeByArea(area);
        if (null == sysDeptArea || StringUtils.isBlank(sysDeptArea.getFinalExportType())) {
            exceptionList.add("区域还未设置模板类型~");
            throw new RuntimeException("区域还未设置模板类型~");
        }
        String templateExportType = sysDeptArea.getFinalExportType();

        for (String fileName : fileNamesList) {
            String absolutePathName = localPath + StringUtils.substringAfter(fileName, Constants.RESOURCE_PREFIX);
            BudgetDataVo excelDataVo = null;
            try {
                excelDataVo = ReadBudT5T8ExcelY23Utils.getSheetT5OrT8Infos(null, absolutePathName, 0, 8);
            } catch (IOException e) {
                throw new RuntimeException("读取文件异常");
            }
            List<BudgetP3p8DeptVo> subDeptList = excelDataVo.getExplainVo().getP3p8Vo().getDeptList();
            for (BudgetP3p8DeptVo deptDataVo : subDeptList) {
                String deptName = deptDataVo.getDeptName();
                String deptCode = deptDataVo.getDeptCode();

                //关联部门id
                SysDept sysDept = sysDeptService.getDeptByDeptCode(deptCode, area);
                if (null == sysDept) {
                    throw new RuntimeException(String.format("[%s] - [%s] 在[%s]中未查到部门信息", deptName, deptCode, area));
                }

                List<FinalData> finalDataList = this.lambdaQuery().eq(FinalData::getDeptId, sysDept.getDeptId()).eq(FinalData::getType, 1)
                        .eq(FinalData::getYear, year)
                        .in(FinalData::getStatus, FinalDataStatus.YEAR_DATA.getCode(), FinalDataStatus.LAST_DATA.getCode(), FinalDataStatus.BUDGET_DATA.getCode(), FinalDataStatus.FILL_DATA.getCode(), FinalDataStatus.FILL_DATA_NO_APPLY.getCode())
                        .select(FinalData::getId, FinalData::getDeptId).orderByDesc(FinalData::getId).list();

                FinalData finalData = null;
                if (!finalDataList.isEmpty()) {
                    finalData = finalDataList.get(0);
                }
                if (null == finalData) {
                    log.error("[{}] 未查到已导入的决算年份的数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);
                    throw new RuntimeException(String.format("[%s] 未查到已导入的决算年份的数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName));
                }

                //查询 报告数据json
                ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
                String jsonContent = reportExplain.getJsonContent();
                if (null == reportExplain || StringUtils.isBlank(jsonContent)) {
                    log.error("[{}] 未查到已导入的决算年份的报告数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);
                    throw new RuntimeException(String.format("[%s] 决算单位没有在已导入的本年数据中", deptName));
                }

                //json数据
                FinalExcelDataVo dataVo = JSONUtil.toBean(jsonContent, FinalExcelDataVo.class);

                // 对比 预算的数据， 保存
                FinalY23CompareLastUtils.compareDataP3T4Budget(dataVo, subDeptList, deptCode);

                //json 转对象
                String jsonTableContent = JSONUtil.toJsonStr(dataVo);

                //更新 保存 去年的 excel数据
                FinalData updateEntity = new FinalData();
                updateEntity.setId(finalData.getId());
                if (FinalDataStatus.LAST_DATA.getCode().equals(finalData.getStatus())) {
                    updateEntity.setStatus(FinalDataStatus.BUDGET_DATA.getCode());
                } else {
                    updateEntity.setStatus(finalData.getStatus());
                }

                //保存 excel读取数据
                boolean updateRes = finalDataService.saveFinalDataAndReportExplain(updateEntity, jsonTableContent, reportExplain.getId());
                if(updateRes) {
                    successNum[0]++;
                }
            }
        }

        //记录日志 如果是 没有异常的, 返回 0
        Integer operStatus = noInBudgetDataList.isEmpty() && noInDeptList.isEmpty() && exceptionList.isEmpty() ? 0 : 1;
        sysOperLogService.insertOperlog(sysOperLogService.createSysOperLog("决算采集-本年", 1, "com.yunyan.web.controller.business.FinalDataController.finalImportExcel()",
                "POST", operStatus, jsonObject.toJSONString()));

        return AjaxResultVo.success(successNum[0]);
    }

}
