package com.saye.hospitalgd.scheduler.jobMethod;

import cn.hutool.core.io.FileUtil;
import com.saye.hospitalgd.commons.date.DateDUtil;
import com.saye.hospitalgd.commons.getBean.GetBeanUtil;
import com.saye.hospitalgd.commons.log.LogUtil;
import com.saye.hospitalgd.commons.string.StringDUtil;
import com.saye.hospitalgd.entity.BankbillHistory;
import com.saye.hospitalgd.service.BankbillGetinfoService;
import com.saye.hospitalgd.service.BankbillHistoryService;
import com.saye.hospitalgd.service.ThirdSftpConfigService;
import com.saye.hospitalgd.service.impl.BankbillGetinfoServiceImpl;
import com.saye.hospitalgd.service.impl.BankbillHistoryServiceImpl;
import com.saye.hospitalgd.service.impl.ThirdSftpConfigServiceImpl;
import com.saye.hospitalgd.service.system.ServiceParamsService;
import com.saye.hospitalgd.service.system.impl.ServiceParamsServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @author thuang
 * @version 1.0
 * @description: 获取商户POS通对账单 调用dmz服务器部署的接口
 * @date 2021/9/13 14:46
 */
@Slf4j
public class BankGetDataMethodByJHLZF {

    public HashMap<Object, Object> getDate(String id, String name, String trade_date, HashMap<Object, Object> map) {
        HashMap<Object, Object> resultMap = new HashMap<>();
        String errCode = "0";
        String errMsg = "";

        BankbillHistoryService bankbillHistoryService = GetBeanUtil.getBean(BankbillHistoryServiceImpl.class);

        BankbillGetinfoService bankbillGetinfoService = GetBeanUtil.getBean(BankbillGetinfoServiceImpl.class);

        ServiceParamsService serviceParamsService = GetBeanUtil.getBean(ServiceParamsServiceImpl.class);
        ThirdSftpConfigService thirdSftpConfigService = GetBeanUtil.getBean(ThirdSftpConfigServiceImpl.class);

        boolean isOk = false;


        //重新执行最多10次 还没获取到肯定有问题 不执行了
        //如果有传入时间 那就只执行一次 获取不到就还是获取不到
        int num = "".equals(trade_date) ? 0 : 9;
        while (!isOk && num < 10) {
            num++;

            String dateStr = "";
            //如果有传入时间 那就使用传入时间
            if ("".equals(trade_date)) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                calendar.add(Calendar.DATE, -1);
                Date time = calendar.getTime();

                trade_date = DateDUtil.DateToStr(DateDUtil.yyyy_MM_dd, time);
                dateStr = DateDUtil.DateToStr(DateDUtil.yyyyMMdd, time);
            } else {
                Date date = DateDUtil.strToDate(DateDUtil.yyyy_MM_dd, trade_date);
                dateStr = DateDUtil.DateToStr(DateDUtil.yyyyMMdd, date);
            }


            //开始请求海南外联接口，生成账单文件

            String cust_id = StringDUtil.changeNullToEmpty(map.get("CUST_ID"));
            String user_id = StringDUtil.changeNullToEmpty(map.get("USER_ID"));
            String tx_code = StringDUtil.changeNullToEmpty(map.get("TX_CODE"));
            String password = StringDUtil.changeNullToEmpty(map.get("PASSWORD"));
            String language = StringDUtil.changeNullToEmpty(map.get("LANGUAGE"));
            String wlip = StringDUtil.changeNullToEmpty(map.get("WLIP"));
            String wlport = StringDUtil.changeNullToEmpty(map.get("WLPORT"));

            // 验证和清理XML字段，防止XML解析错误
            if (language == null || language.trim().isEmpty()) {
                language = "CN"; // 默认值
            } else {
                // 清理可能导致XML格式错误的字符
                language = language.replaceAll("[<>&\"']", "").trim();
                if (language.isEmpty()) {
                    language = "CN";
                }
            }

            // 清理其他可能包含特殊字符的字段
            cust_id = cust_id.replaceAll("[<>&\"']", "");
            user_id = user_id.replaceAll("[<>&\"']", "");
            tx_code = tx_code.replaceAll("[<>&\"']", "");
            password = password.replaceAll("[<>&\"']", "");

            String requset_sn_sc = String.valueOf(System.currentTimeMillis());

            log.info("传去的时间是dateStr：" + dateStr);
            String requestXml = "<?xml version=\"1.0\" encoding=\"GB2312\" standalone=\"yes\" ?>  \n" +
                    "<TX>   \n" +
                    "  <REQUEST_SN>" + requset_sn_sc + "</REQUEST_SN>  \n" +
                    "  <CUST_ID>" + cust_id + "</CUST_ID>  \n" +
                    "  <USER_ID>" + user_id + "</USER_ID>  \n" +
                    "  <PASSWORD>" + password + "</PASSWORD>  \n" +
                    "  <TX_CODE>" + tx_code + "</TX_CODE>  \n" +
                    "  <LANGUAGE>" + language + "</LANGUAGE>  \n" +
                    "  <TX_INFO>  \n" +
                    "    <DATE>" + dateStr + "</DATE>  \n" +
                    "    <KIND>1</KIND>  \n" +
                    "    <FILETYPE>1</FILETYPE>  \n" +
                    "    <TYPE></TYPE>  \n" +
                    "    <NORDERBY></NORDERBY>  \n" +
                    "    <POS_CODE></POS_CODE>  \n" +
                    "    <ORDER></ORDER>  \n" +
                    "    <STATUS></STATUS>  \n" +
                    "    <BILL_FLAG></BILL_FLAG>  \n" +
                    "    <Mrch_No></Mrch_No>  \n" +
                    "    <GROUP_FLAG></GROUP_FLAG>  \n" +
                    "    <TXN_TPCD></TXN_TPCD>  \n" +
                    "  </TX_INFO>  \n" +
                    "</TX> ";
            String params = "requestXml=" + requestXml;
            String ipAdress = wlip + ":" + wlport;
            log.info("拼接的ip是：" + ipAdress);
            String fileName = "";

            try {
                URI uri = new URI(ipAdress.trim());
                CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
                HttpPost httpPost = new HttpPost(uri);
                httpPost.setHeader("content-type", "application/x-www-form-urlencoded");
                httpPost.setHeader("Connection", "close");
                StringEntity entity = new StringEntity(params, "GB18030");
                log.info("发送的数据是entity：" + entity);
                httpPost.setEntity(entity);

                CloseableHttpResponse response = closeableHttpClient.execute(httpPost);

                // 增强响应读取，防止截断
                String s;
                try {
                    HttpEntity responseEntity = response.getEntity();
                    if (responseEntity != null) {
                        long contentLength = responseEntity.getContentLength();
                        log.info("主接口响应内容长度: " + contentLength);
                        
                        // 使用流式读取，避免截断
                        try (InputStream inputStream = responseEntity.getContent();
                             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                            
                            byte[] buffer = new byte[1024]; // 1KB缓冲区，更小更精确
                            int bytesRead;
                            int totalBytesRead = 0;
                            
                            while ((bytesRead = inputStream.read(buffer)) != -1) {
                                outputStream.write(buffer, 0, bytesRead);
                                totalBytesRead += bytesRead;
                            }
                            
                            // 获取原始字节数组
                            byte[] responseBytes = outputStream.toByteArray();
                            log.info("主接口流式读取完成，总字节数: " + totalBytesRead + ", 字节数组长度: " + responseBytes.length);
                            
                            // 使用ISO-8859-1编码确保字节数和字符数一致
                            s = new String(responseBytes, "ISO-8859-1");
                            log.info("主接口使用ISO-8859-1编码，字符串长度: " + s.length());
                            
                            // 检查是否可能被截断
                            if (contentLength > 0 && totalBytesRead < contentLength) {
                                log.warn("主接口响应可能被截断，期望长度: " + contentLength + ", 实际读取: " + totalBytesRead);
                            }
                        }
                    } else {
                        s = "";
                        log.warn("主接口响应实体为空");
                    }
                } finally {
                    // 确保响应被完全消费
                    EntityUtils.consumeQuietly(response.getEntity());
                }

                log.info("接受到的数据是s：" + s);

                // 增强XML格式修复和验证
                Document document;
                try {
                    // 首先清理响应数据，移除可能的非XML内容
                    s = cleanXmlResponse(s);

                    // 尝试解析XML
                    document = DocumentHelper.parseText(s);
                } catch (Exception e) {
                    log.error("XML解析错误，原始响应: " + s, e);
                    try {
                        // 尝试修复常见的XML格式问题
                        s = fixXmlFormat(s);
                        log.info("修复后的XML: " + s);
                    document = DocumentHelper.parseText(s);
                    } catch (Exception e2) {
                        log.error("XML修复后仍然解析失败", e2);
                        throw new RuntimeException("XML解析失败，无法处理响应数据: " + s, e2);
                    }
                }

                Iterator iterator = document.nodeIterator();


                Element tx = (Element) iterator.next();
                Element return_code_F = tx.element("RETURN_CODE");
                Element return_msg_F = tx.element("RETURN_MSG");
                if (return_code_F != null) {
                    if (!return_code_F.getText().equals("000000")) {
                        errCode = "999";
                        errMsg = return_msg_F.getText();
                        log.info("获取到的返回code是" + return_code_F);
                    } else {
                        Iterator tx_info = tx.elementIterator("TX_INFO");
                        Element txInfo = (Element) tx_info.next();

                        Element file_name = txInfo.element("FILE_NAME");
                        fileName = file_name.getText();

                        boolean exist = FileUtil.exist("C:" + File.separator + "CCB_EBSClient" + File.separator + "download" + File.separator + fileName);

                        Boolean fileIsExist = false;

                        if (!exist) { //文件不存在开始下载
                            log.info("文件不存在，开始下载: " + fileName);
                            HashMap<Object, Object> searchMap = new HashMap<>();
                            searchMap.put("FUBS", "2");
                            List<HashMap<Object, Object>> wlConfigList = thirdSftpConfigService.findWLIF(searchMap);
                            HashMap<Object, Object> configMap = wlConfigList.get(0);
                            String txCode = StringDUtil.changeNullToEmpty(configMap.get("TX_CODE"));
                            String filepath = StringDUtil.changeNullToEmpty(configMap.get("FILEPATH"));
                            String requset_sn_xz = String.valueOf(System.currentTimeMillis());
                            String re = "<?xml version=\"1.0\" encoding=\"GB2312\" standalone=\"yes\" ?> \n" +
                                    "<TX> \n" +
                                    "  <REQUEST_SN>" + requset_sn_xz + "</REQUEST_SN>  \n" +
                                    "  <CUST_ID>" + cust_id + "</CUST_ID>  \n" +
                                    "  <USER_ID>" + user_id + "</USER_ID>  \n" +
                                    "  <PASSWORD>" + password + "</PASSWORD>  \n" +
                                    "  <TX_CODE>" + txCode + "</TX_CODE>  \n" +
                                    "  <LANGUAGE>CN</LANGUAGE>  \n" +
                                    "  <TX_INFO> \n" +
                                    "    <SOURCE>" + fileName + "</SOURCE>  \n" +
                                    "    <FILEPATH>" + filepath + "</FILEPATH>  \n" +
                                    "    <LOCAL_REMOTE>0</LOCAL_REMOTE>  \n" +
                                    "  </TX_INFO> \n" +
                                    "</TX> \n";
                            String ps = "requestXml=" + re;

                            Element return_code = null;
                            Element return_msg = null;
                            URI uri_d = new URI(ipAdress.trim());
                            CloseableHttpClient closeableHttpClientD = HttpClients.createDefault();
                            HttpPost httpPostD = new HttpPost(uri_d);
                            httpPostD.setHeader("content-type", "application/x-www-form-urlencoded");
                            httpPostD.setHeader("Connection", "close");
                            StringEntity entityD = new StringEntity(ps, "GB18030");
                            httpPostD.setEntity(entityD);

                            CloseableHttpResponse responseD = closeableHttpClientD.execute(httpPostD);

                // 增强响应读取，防止截断
                String s_d;
                try {
                    HttpEntity responseEntityD = responseD.getEntity();
                    if (responseEntityD != null) {
                        long contentLength = responseEntityD.getContentLength();
                        log.info("下载接口响应内容长度: " + contentLength);
                        
                        // 使用流式读取，避免截断
                        try (InputStream inputStream = responseEntityD.getContent();
                             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                            
                            byte[] buffer = new byte[1024]; // 1KB缓冲区，更小更精确
                            int bytesRead;
                            int totalBytesRead = 0;
                            
                            while ((bytesRead = inputStream.read(buffer)) != -1) {
                                outputStream.write(buffer, 0, bytesRead);
                                totalBytesRead += bytesRead;
                                log.debug("读取了 " + bytesRead + " 字节，累计: " + totalBytesRead);
                            }
                            
                            // 获取原始字节数组
                            byte[] responseBytes = outputStream.toByteArray();
                            log.info("流式读取完成，总字节数: " + totalBytesRead + ", 字节数组长度: " + responseBytes.length);
                            
                            // 首先检查十六进制模式，确定是否需要字节级修复
                            StringBuilder hexCheck = new StringBuilder();
                            for (int i = Math.max(0, responseBytes.length - 20); i < responseBytes.length; i++) {
                                hexCheck.append(String.format("%02X ", responseBytes[i]));
                            }
                            String hexStr = hexCheck.toString();
                            log.info("响应尾部20字节(HEX): " + hexStr);
                            
                            // 检查是否存在LANGUAGE标签截断的十六进制模式
                            // </LANG = 3C 2F 4C 41 4E 47
                            // 完整的</LANGUAGE> = 3C 2F 4C 41 4E 47 55 41 47 45 3E
                            if (hexStr.contains("3C 2F 4C 41 4E 47") && !hexStr.contains("3C 2F 4C 41 4E 47 55 41 47 45 3E")) {
                                log.warn("通过十六进制检测到LANGUAGE标签截断，进行字节级修复");
                                s_d = fixLanguageTagFromBytes(responseBytes);
                                log.info("字节级修复完成，新字符串长度: " + s_d.length());
                            } else {
                                // 没有截断，直接使用ISO-8859-1编码（字节数和字符数一致）
                                s_d = new String(responseBytes, "ISO-8859-1");
                                log.info("使用ISO-8859-1编码，字符串长度: " + s_d.length());
                                
                                // 再次检查字符串内容是否有截断
                                if (s_d.contains("<LANGUAGE>CN</LANG") && !s_d.contains("</LANGUAGE>")) {
                                    log.warn("字符串检测到LANGUAGE标签截断，进行字节级修复");
                                    s_d = fixLanguageTagFromBytes(responseBytes);
                                    log.info("字符串检测修复完成，新字符串长度: " + s_d.length());
                                }
                            }
                            
                            log.info("最终字符串长度: " + s_d.length());
                            
                            // 验证修复结果
                            if (s_d.contains("<LANGUAGE>CN</LANGUAGE>") && s_d.contains("</TX>")) {
                                log.info("XML修复成功，包含完整的LANGUAGE标签和TX根元素");
                            } else if (s_d.contains("<LANGUAGE>CN</LANG") && !s_d.contains("</LANGUAGE>")) {
                                log.error("XML修复失败，LANGUAGE标签仍然截断");
                                // 最后尝试字符串级别的修复
                                s_d = s_d.replace("<LANGUAGE>CN</LANG", "<LANGUAGE>CN</LANGUAGE>");
                                if (!s_d.contains("</TX>")) {
                                    s_d = s_d + "</TX>";
                                }
                                log.info("应急字符串修复完成");
                            }
                            
                            // 检查是否可能被截断
                            if (contentLength > 0 && totalBytesRead < contentLength) {
                                log.warn("响应可能被截断，期望长度: " + contentLength + ", 实际读取: " + totalBytesRead);
                            }
                        }
                    } else {
                        s_d = "";
                        log.warn("下载接口响应实体为空");
                    }
                } finally {
                    // 确保响应被完全消费
                    EntityUtils.consumeQuietly(responseD.getEntity());
                }

                log.info("下载接口响应: " + s_d);
                            // 增强XML格式修复和验证
                            Document documentD;
                            try {
                                // 首先清理响应数据，移除可能的非XML内容
                                s_d = cleanXmlResponse(s_d);

                                // 尝试解析XML
                                documentD = DocumentHelper.parseText(s_d);
                            } catch (Exception e) {
                                log.error("下载XML解析错误，原始响应: " + s_d, e);
                                try {
                                    // 尝试修复常见的XML格式问题
                                    s_d = fixXmlFormat(s_d);
                                    log.info("修复后的下载XML: " + s_d);
                                documentD = DocumentHelper.parseText(s_d);
                                } catch (Exception e2) {
                                    log.error("下载XML修复后仍然解析失败", e2);
                                    throw new RuntimeException("下载XML解析失败，无法处理响应数据: " + s_d, e2);
                                }
                            }
                            Iterator iteratorD = documentD.nodeIterator();
                            Element txD = (Element) iteratorD.next();
                            return_code = txD.element("RETURN_CODE");
                            return_msg = txD.element("RETURN_MSG");
                            if (return_code != null) {
                                if (!return_code.getText().equals("000000")) {
                                    errCode = "999";
                                    errMsg = "文件下载失败: " + return_msg.getText();
                                    log.error("文件下载失败，返回码: " + return_code.getText() + ", 错误信息: " + return_msg.getText());
                                } else {
                                    log.info("下载接口返回成功，准备从中专服务器下载ZIP文件...");
                                    
                                    // 调用外联平台下载接口成功后，从中专服务器下载ZIP文件到本地
                                    try {
                                        log.info("准备调用中专服务器下载接口获取ZIP文件: " + fileName);
                                        boolean downloadSuccess = downloadZipFromIntermediaryServer(fileName, serviceParamsService);
                                        if (downloadSuccess) {
                                            log.info("从中专服务器下载ZIP文件成功: " + fileName);
                                            fileIsExist = true; // 标记文件已存在
                                        } else {
                                            log.warn("从中专服务器下载ZIP文件失败，等待本地文件生成: " + fileName);
                                            // 如果中专服务器下载失败，等待本地文件生成
                                            fileIsExist = waitForFileGeneration(fileName, 60);
                                            if (!fileIsExist) {
                                                errCode = "999";
                                                errMsg = "文件下载超时，文件未生成: " + fileName;
                                                log.error("文件下载超时: " + fileName);
                                            }
                                        }
                                    } catch (Exception downloadEx) {
                                        log.error("调用中专服务器下载接口异常，等待本地文件生成: " + fileName, downloadEx);
                                        // 如果中专服务器下载异常，等待本地文件生成
                                        fileIsExist = waitForFileGeneration(fileName, 60);
                                        if (!fileIsExist) {
                                            errCode = "999";
                                            errMsg = "文件下载超时，文件未生成: " + fileName;
                                            log.error("文件下载超时: " + fileName);
                                        }
                                    }
                                }
                            }
                        }
                        if (fileIsExist || exist) { //确定文件存在，开始读取数据
                            String filePath = "C:" + File.separator + "CCB_EBSClient" + File.separator + "download" + File.separator + fileName;
                            log.info("开始读取文件: " + filePath);

                            // 再次验证文件是否真实存在且可读
                            File file = new File(filePath);
                            if (!file.exists()) {
                                errCode = "999";
                                errMsg = "文件不存在: " + filePath;
                                log.error("文件不存在: " + filePath);
                                continue; // 继续下一次循环重试
                            }

                            if (!file.canRead()) {
                                errCode = "999";
                                errMsg = "文件无法读取: " + filePath;
                                log.error("文件无法读取: " + filePath);
                                continue; // 继续下一次循环重试
                            }

                            if (file.length() == 0) {
                                errCode = "999";
                                errMsg = "文件为空: " + filePath;
                                log.error("文件为空: " + filePath);
                                continue; // 继续下一次循环重试
                            }

                            log.info("文件验证通过，大小: " + file.length() + " 字节");

                            List<String> txtList = null;
                            FileInputStream stream = null;
                            ZipInputStream zipInputStream = null;
                            BufferedReader br = null;

                            try {
                                stream = new FileInputStream(filePath);
                                zipInputStream = new ZipInputStream(new BufferedInputStream(stream), Charset.forName("GBK"));

                            ZipEntry nextEntry = zipInputStream.getNextEntry();
                                if (nextEntry == null) {
                                    throw new RuntimeException("ZIP文件中没有找到任何条目");
                                }
                                
                                String entryName = nextEntry.getName();
                                log.info("读取的ZIP条目: " + entryName + ", 大小: " + nextEntry.getSize());

                                // 判断文件类型
                                if (entryName.toLowerCase().endsWith(".xlsx") || entryName.toLowerCase().endsWith(".xls")) {
                                    log.info("检测到Excel文件，使用POI解析: " + entryName);
                                    txtList = parseExcelFromZip(zipInputStream, entryName);
                                    log.info("成功从Excel解析 " + (txtList != null ? txtList.size() : 0) + " 行数据");
                                } else {
                                    // 原来的文本文件解析逻辑
                                    log.info("检测到文本文件，使用文本解析: " + entryName);
                                    br = new BufferedReader(new InputStreamReader(zipInputStream, StandardCharsets.UTF_8));

                            String line;
                            txtList = new ArrayList<>();
                                    int lineCount = 0;
                            //内容不为空，输出
                            while ((line = br.readLine()) != null) {
                                txtList.add(line);
                                        lineCount++;
                                    }
                                    log.info("成功读取 " + lineCount + " 行数据");
                                }

                            } catch (Exception e) {
                                log.error("文件读取失败: " + filePath, e);
                                errCode = "999";
                                errMsg = "文件读取失败: " + e.getMessage();
                                continue; // 继续下一次循环重试
                            } finally {
                                // 确保资源正确关闭
                                try {
                                    if (br != null) br.close();
                                    if (zipInputStream != null) zipInputStream.close();
                                    if (stream != null) stream.close();
                                } catch (Exception e) {
                                    log.warn("关闭文件流时出错", e);
                                }
                            }
                            log.info("继续执行程序3");
                            List<BankbillHistory> bankbillHistoryList = new ArrayList<>();
                            
                            int startIndex = -1;
                            for (int i = 0; i < txtList.size(); i++) {
                                String line = txtList.get(i);
                                if (line == null || line.trim().isEmpty()) {
                                    continue;
                                }
                                String[] cols = line.split("\t");
                                if (cols.length < 10) {
                                    continue;
                                }
                                 dateStr = cols.length > 13 ? cols[13].trim() : "";
                                if (dateStr == null || dateStr.isEmpty() || !dateStr.contains("-")) {
                                    continue;
                                }
                                String firstAmountStr = cols.length > 20 ? cols[20].trim() : "";
                                if (firstAmountStr.isEmpty() || firstAmountStr.equals("null") || firstAmountStr.equals("0") || firstAmountStr.equals("0.00")) {
                                    continue;
                                }
                                try {
                                    double firstAmount = Double.parseDouble(firstAmountStr);
                                    if (Math.abs(firstAmount) < 0.01) {
                                        continue;
                                    }
                                } catch (NumberFormatException e) {
                                    continue;
                                }
                                startIndex = i;
                                break;
                            }
                            if (startIndex == -1) {
                                startIndex = 24;
                            }
                            for (int i = startIndex; i < txtList.size(); i++) {
                                try {
                                    String d = txtList.get(i);
                                    
                                    if (d == null || d.trim().isEmpty()) {
                                        continue;
                                    }

                                    String[] s1 = d.split("\t");

                                    if (s1.length < 10) {
                                        log.debug("第 " + (i + 1) + " 行列数不足，跳过");
                                        continue;
                                    }
                                    
                                    String rowText = d.toLowerCase();
                                    if (rowText.contains("小计") || rowText.contains("合计") || 
                                        rowText.contains("终端小计") || rowText.contains("pos编号") ||
                                        rowText.contains("笔数") ||
                                        s1.length > 6 && (s1[6].contains("小计") || s1[6].contains("合计"))) {
                                        log.debug("第 " + (i + 1) + " 行是汇总行，跳过: " + (s1.length > 6 ? s1[6] : ""));
                                        continue;
                                    }
                                    
                                    if (s1.length <= 13 || s1[13] == null || s1[13].trim().isEmpty()) {
                                        log.debug("第 " + (i + 1) + " 行交易日期为空，跳过");
                                        continue;
                                    }
                                    
                                    String jyrq = s1[13].trim();
                                    
                                    if (!jyrq.contains("-")) {
                                        log.debug("第 " + (i + 1) + " 行交易日期不包含日期分隔符，跳过");
                                        continue;
                                    }
                                    
                                    String amountStr = s1.length > 20 ? s1[20].trim() : "";
                                    if (amountStr.isEmpty() || amountStr.equals("null") || amountStr.equals("0") || amountStr.equals("0.00")) {
                                        log.debug("第 " + (i + 1) + " 行交易金额无效: [" + amountStr + "]，跳过");
                                        continue;
                                    }
                                    
                                    try {
                                        double amount = Double.parseDouble(amountStr);
                                        if (Math.abs(amount) < 0.01) {
                                            log.debug("第 " + (i + 1) + " 行交易金额太小: " + amount + "，跳过");
                                            continue;
                                        }
                                    } catch (NumberFormatException e) {
                                        log.debug("第 " + (i + 1) + " 行交易金额不是有效数字: [" + amountStr + "]，跳过");
                                        continue;
                                    }
                                    
                                    log.info("正在处理第 " + (i + 1) + " 行数据");

                                    BankbillHistory bankbillHistory = new BankbillHistory();

                                    // 根据实际Excel列位置映射（从日志分析得出）：
                                    // 终端号: C列(索引2), 发卡行: E列(索引4), 卡种: I列(索引8), 
                                    // 卡号: K列(索引10), 交易日期: N列(索引13), 交易时间: O列(索引14)⭐,
                                    // 交易类型: Q列(索引16), 授权号: S列(索引18), 交易金额: U列(索引20)⭐,
                                    // 小费: VW列(索引21-22), 分期期数: X列(索引23), 银行手续费: Y列(索引24),
                                    // DCC返还手续费: Z列(索引25), 划账金额: AA列(索引26), 凭证号: AB列(索引27),
                                    // 批次号: AC列(索引28), POS交易序号: AD列(索引29)⭐, 结算账号: AE列(索引30),
                                    // 订单号: AF列(索引31), 柜台编号: AG列(索引32), 系统参考号: AH列(索引33),
                                    // 持卡人姓名: AI列(索引34), 付款凭证号: AJ列(索引35), 备注1: AK列(索引36), 备注2: AL列(索引37)
                                    
                                    // 获取终端号（C列，索引2）用于判断是否为住院订单
                                    String zdh = s1.length > 2 ? s1[2].trim() : "";
                                    
                                    // 交易日期和时间
                                    jyrq = s1.length > 13 ? s1[13] : "";
                                    String jysj = s1.length > 14 ? s1[14] : "";  // 交易时间在第14列（索引14）
                                    
                                    // 如果交易时间为空，尝试从交易日期中提取时间部分
                                    if (jysj == null || jysj.trim().isEmpty()) {
                                        // 检查交易日期是否包含时间（格式如：2025-10-23 14:30:15）
                                        if (jyrq != null && jyrq.contains(" ")) {
                                            String[] dateTimeParts = jyrq.split(" ", 2);
                                            if (dateTimeParts.length == 2) {
                                                jyrq = dateTimeParts[0];  // 日期部分
                                                jysj = dateTimeParts[1];  // 时间部分
                                            }
                                        } else {
                                            // 如果还是空，设置默认值
                                            jysj = "00:00:00";
                                        }
                                    }
                                    
                                    bankbillHistory.setCJyrq(jyrq);                               // N列(索引13): 交易日期
                                    bankbillHistory.setCJysj(jysj);                               // P列(索引15): 交易时间
                                    bankbillHistory.setCJyje(s1.length > 20 ? s1[20] : "0");     // U列(索引20): 交易金额
                                    bankbillHistory.setCZdh(zdh);                                 // C列(索引2): 终端号
                                    
                                    // QR列(索引16): 支付方式（Excel中就是微信支付、支付宝等）
                                    String zffs = s1.length > 16 ? s1[16].trim() : "建行龙支付";
                                    if (zffs.isEmpty()) {
                                        zffs = "建行龙支付";  // 默认值
                                    }
                                    bankbillHistory.setCZffs(zffs);                               // 支付方式（直接从Excel读取）
                                    
                                    // 交易类型：根据交易金额正负判断
                                    String jylx = "消费";  // 默认交易类型
                                    try {
                                        double amount = Double.parseDouble(s1.length > 20 ? s1[20] : "0");
                                        if (amount < 0) {
                                            jylx = "退款";
                                        }
                                    } catch (Exception e) {
                                        // 解析失败，使用默认值
                                    }
                                    bankbillHistory.setCJylx(jylx);                               // 交易类型（根据金额正负判断）
                                    
                                    // AD列(索引29): POS交易序号 (作为流水号和银商订单号)
                                    bankbillHistory.setCLsh(s1.length > 29 ? s1[29] : "");       // 流水号
                                    bankbillHistory.setCYsddh(s1.length > 29 ? s1[29] : "");     // 银商订单号
                                    
                                    // AF列(索引31): 订单号 (作为商户订单号)
                                    bankbillHistory.setCShddh(s1.length > 31 ? s1[31] : "");     // 商户订单号
                                    
                                    // AH列(索引33): 系统参考号
                                    bankbillHistory.setCCkh(s1.length > 33 ? s1[33] : "");       // 参考号
                                    
                                    // KLM列(索引10): 卡号-序列号
                                    bankbillHistory.setCCard(s1.length > 10 ? s1[10] : "");      // 卡号
                                    
                                    // IJ列(索引8): 卡种
                                    bankbillHistory.setCKlx(s1.length > 8 ? s1[8] : "");         // 卡类型
                                    
                                    // EFGH列(索引4): 发卡行
                                    bankbillHistory.setCFkh(s1.length > 4 ? s1[4] : "");         // 发卡行
                                    
                                    // 支付方式已经在前面设置（从第16列读取），这里不再覆盖
                                    
                                    // VW列(索引21): 小费
                                    bankbillHistory.setCSxf(s1.length > 21 ? s1[21] : "0");      // 小费
                                    
                                    // X列(索引23): 分期期数
                                    bankbillHistory.setCFqqs(s1.length > 23 ? s1[23] : "");      // 分期期数
                                    
                                    // Y列(索引24): 银行手续费
                                    bankbillHistory.setCFqsxf(s1.length > 24 ? s1[24] : "0");    // 分期手续费
                                    
                                    // AA列(索引26): 划账金额 (作为清算金额和实际支付金额)
                                    String haje = s1.length > 26 ? s1[26] : (s1.length > 20 ? s1[20] : "0");
                                    bankbillHistory.setCQsje(haje);                               // 清算金额
                                    bankbillHistory.setCSjzfje(haje);                             // 实际支付金额
                                    
                                    // 清算日期 = 交易日期
                                    bankbillHistory.setCQsrq(s1.length > 13 ? s1[13] : "");      // 清算日期
                                    
                                    // 备注字段 (AK列:备注1, AL列:备注2)
                                    String bz = "";
                                    if (s1.length > 36 && s1[36] != null && !s1[36].trim().isEmpty()) {
                                        bz = s1[36];
                                    }
                                    if (s1.length > 37 && s1[37] != null && !s1[37].trim().isEmpty()) {
                                        bz += (bz.isEmpty() ? "" : ";") + s1[37];
                                    }
                                    bankbillHistory.setCBzzd(bz);                                 // 备注字段
                                    
                                    // 其他固定字段
                                    bankbillHistory.setCQbyhje("0");                              // 钱包优惠金额
                                    bankbillHistory.setCShyhje("0");                              // 商户优惠金额
                                    bankbillHistory.setCYjylsh("");                               // 原交易流水号（空）
                                    bankbillHistory.setCFqfwf("");                                // 分期服务方（空）
                                    bankbillHistory.setCFqfxf("");                                // 分期付息方（空）
                                    bankbillHistory.setCQtyhje("0");                              // 其他优惠金额
                                    bankbillHistory.setCThddh("");                                // 退货订单号（空）
                                    bankbillHistory.setCFkfy("");                                 // 付款附言（空）
                                    bankbillHistory.setCFdjc("");                                 // 分店简称（空）
                                    bankbillHistory.setCZddh("");                                 // 子订单号（空）
                                    bankbillHistory.setBillTableName("建行龙支付对账单");          // 对账表名
                                    
                                    String shddh = bankbillHistory.getCShddh();
                                    if ("10091548".equals(zdh)
                                            || "10091549".equals(zdh)
                                            || "10091546".equals(zdh)
                                            || "10091547".equals(zdh)
                                            || "10091544".equals(zdh)
                                            || "10091545".equals(zdh)
                                            || (shddh != null && shddh.endsWith("ZZJZY"))) {
                                        bankbillHistory.setIsInpatient("1");
                                        log.info("标记为住院订单: 终端号=" + zdh + ", 订单号=" + shddh);
                                    } else {
                                        bankbillHistory.setIsInpatient("0");
                                    }

                                bankbillHistoryList.add(bankbillHistory);
                                    log.info("成功解析第 " + (i + 1) + " 行数据");
                                    
                                } catch (Exception e) {
                                    log.error("处理第 " + (i + 1) + " 行数据时出错，跳过该行", e);
                                    continue;
                                }
                            }
                            if (!CollectionUtils.isEmpty(bankbillHistoryList)) {
                                log.info("成功解析 " + bankbillHistoryList.size() + " 条建行龙支付对账数据");
                                // 先存一份原始的 这份只是留底查询
                                bankbillHistoryService.insertBankBillOriginal(bankbillHistoryList, trade_date, "建行龙支付对账单");
                                log.info("已保存原始对账数据到数据库");
                                // 再存一份修改的用于对账
                                bankbillHistoryService.insertAllBankHistory(bankbillHistoryList, trade_date, "建行龙支付对账单");
                                log.info("已保存对账数据到对账表");
                                isOk = true;
                            } else {
                                errCode = "999";
                                errMsg = "未查询到有效数据（可能是文件格式不正确）";
                                log.error("解析建行龙支付对账单失败: " + errMsg);
                                isOk = false;
                            }
                        }
                    }
                }
            } catch (Exception e) {
                errCode = "999";
                if (StringUtils.isEmpty(errMsg)) {
                    errMsg = "外联平台接口调用失败！！！";
                }
                e.printStackTrace();
            }
            //海南外联接口调用成功后会生成账单文件，在请求一次外联接口下载到服务器。
            log.info("继续执行程序4");
            //记录数据获取记录
            HashMap<Object, Object> addMap = new HashMap<>();
            addMap.put("trade_date", trade_date);
            addMap.put("quartz_id", id);
            addMap.put("quartz_name", name);
            addMap.put("bill_table_name", "建行龙支付对账单");
            addMap.put("thirdConfigId", "999");

            if (isOk) {
                addMap.put("is_ok", "1");
            } else {
                addMap.put("is_ok", "0");
            }
            addMap.put("modify_time", DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss));
            bankbillGetinfoService.insertBankbillGetinfo(addMap);

            //判断是否成功 如果失败 执行休眠一小时
            if (!isOk && num < 10) {
                try {
                    //记录日志
                    LogUtil.error(this.getClass(), errMsg);

                    System.out.println("获取对账记录没有成功，1小时后重新执行");
                    Thread.sleep(1000 * 60 * 60);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        resultMap.put("errCode", errCode);
        resultMap.put("errMsg", errMsg);

        return resultMap;
    }

    /**
     * 清理XML响应数据，移除可能的非XML内容
     */
    private String cleanXmlResponse(String response) {
        if (response == null || response.trim().isEmpty()) {
            return response;
        }

        // 移除BOM标记
        if (response.startsWith("\uFEFF")) {
            response = response.substring(1);
        }

        // 查找XML声明的开始位置
        int xmlStart = response.indexOf("<?xml");
        if (xmlStart > 0) {
            response = response.substring(xmlStart);
        }

        // 如果没有XML声明，查找根元素开始位置
        if (xmlStart == -1) {
            int rootStart = response.indexOf("<TX>");
            if (rootStart > 0) {
                response = response.substring(rootStart);
            }
        }

        // 移除可能的尾部非XML内容
        int lastTagEnd = response.lastIndexOf(">");
        if (lastTagEnd > 0 && lastTagEnd < response.length() - 1) {
            String afterLastTag = response.substring(lastTagEnd + 1).trim();
            // 如果最后一个标签后还有非空白字符，可能是垃圾数据
            if (!afterLastTag.isEmpty() && !afterLastTag.matches("\\s*")) {
                response = response.substring(0, lastTagEnd + 1);
            }
        }

        return response.trim();
    }

    /**
     * 修复常见的XML格式问题
     */
    private String fixXmlFormat(String xml) {
        if (xml == null || xml.trim().isEmpty()) {
            return xml;
        }

        log.info("开始修复XML，原始长度: " + xml.length());

        // 确保有XML声明
        if (!xml.trim().startsWith("<?xml")) {
            xml = "<?xml version=\"1.0\" encoding=\"GB2312\"?>\n" + xml;
        }

        // 处理严重截断的情况 - 检查XML是否在标签中间被截断
        if (xml.endsWith("<") || xml.matches(".*<[^>]*$")) {
            log.warn("检测到XML在标签中被截断，尝试修复");
            // 移除最后一个不完整的标签
            int lastLessThan = xml.lastIndexOf('<');
            if (lastLessThan > 0) {
                xml = xml.substring(0, lastLessThan);
                log.info("移除不完整标签后的XML: " + xml);
            }
        }
        
        // 特殊处理：检测<LANGUAGE>CN</LANG这种特定截断模式
        if (xml.contains("<LANGUAGE>CN</LANG") && !xml.contains("</LANGUAGE>")) {
            log.warn("检测到LANGUAGE标签特定截断模式");
            // 直接替换为完整的标签
            xml = xml.replaceAll("<LANGUAGE>CN</LANG[^>]*$", "<LANGUAGE>CN</LANGUAGE>");
            xml = xml.replaceAll("<LANGUAGE>CN</LANG(?![A-Z])", "<LANGUAGE>CN</LANGUAGE>");
            log.info("修复LANGUAGE标签截断");
        }
        
        // 处理XML结尾被截断的情况
        if (xml.endsWith("<LANGUAGE>CN</LANG")) {
            log.warn("检测到XML结尾LANGUAGE标签截断");
            xml = xml.replace("<LANGUAGE>CN</LANG", "<LANGUAGE>CN</LANGUAGE>");
            log.info("修复XML结尾LANGUAGE标签");
        }
        
        // 处理XML在LANGUAGE标签中间被截断的情况
        if (xml.endsWith("<LANGUAGE>") || xml.endsWith("<LANGUAGE>CN") || xml.endsWith("<LANGUAGE>CN<")) {
            log.warn("检测到LANGUAGE标签内容截断");
            if (xml.endsWith("<LANGUAGE>")) {
                xml = xml.replace("<LANGUAGE>", "<LANGUAGE>CN</LANGUAGE>");
            } else if (xml.endsWith("<LANGUAGE>CN")) {
                xml = xml.replace("<LANGUAGE>CN", "<LANGUAGE>CN</LANGUAGE>");
            } else if (xml.endsWith("<LANGUAGE>CN<")) {
                xml = xml.replace("<LANGUAGE>CN<", "<LANGUAGE>CN</LANGUAGE>");
            }
            log.info("修复LANGUAGE标签内容截断");
        }

        // 处理标签名被截断的情况，如 </LANG 应该是 </LANGUAGE>
        xml = xml.replaceAll("</LANG(?!UAGE)", "</LANGUAGE>");
        xml = xml.replaceAll("<LANGUAGE([^>]*)>([^<]*)</LANG(?!UAGE)", "<LANGUAGE$1>$2</LANGUAGE>");

        // 修复LANGUAGE标签问题 - 处理各种截断情况
        // 特殊处理：如果发现CN</LANG模式，说明LANGUAGE标签被截断
        if (xml.contains("CN</LANG") && !xml.contains("CN</LANGUAGE>")) {
            xml = xml.replaceAll("CN</LANG[^>]*", "CN</LANGUAGE>");
            log.info("修复CN</LANG截断问题");
        }
        
        // 处理<LANGUAGE>CN</LANG这种截断
        xml = xml.replaceAll("<LANGUAGE([^>]*)>CN</LANG[^>]*", "<LANGUAGE$1>CN</LANGUAGE>");
        
        // 处理<LANGUAGE>...内容被截断的情况，保留已有内容
        xml = xml.replaceAll("<LANGUAGE([^>]*)>([^<]*?)(?=<(?!/LANGUAGE))", "<LANGUAGE$1>$2</LANGUAGE>");
        xml = xml.replaceAll("<LANGUAGE([^>]*)>([^<]*?)$", "<LANGUAGE$1>$2</LANGUAGE>");
        
        // 特殊处理：如果LANGUAGE标签内容为空但原始响应中有CN，尝试恢复
        if (xml.contains("<LANGUAGE></LANGUAGE>") && xml.contains("CN")) {
            // 查找CN在原始XML中的位置，如果在LANGUAGE标签附近，则恢复
            String originalPart = xml.substring(Math.max(0, xml.indexOf("<LANGUAGE>") - 50), 
                                              Math.min(xml.length(), xml.indexOf("</LANGUAGE>") + 20));
            if (originalPart.contains("CN")) {
                xml = xml.replace("<LANGUAGE></LANGUAGE>", "<LANGUAGE>CN</LANGUAGE>");
                log.info("恢复LANGUAGE标签中的CN内容");
            }
        }

        // 修复其他可能未关闭的标签
        String[] commonTags = {"REQUEST_SN", "CUST_ID", "USER_ID", "PASSWORD", "TX_CODE",
                              "RETURN_CODE", "RETURN_MSG", "FILE_NAME", "SOURCE", "FILEPATH", "TX_INFO"};

        for (String tag : commonTags) {
            // 修复未关闭的标签
            xml = xml.replaceAll("<" + tag + "([^>]*)>([^<]*?)(?=<(?!/" + tag + "))",
                               "<" + tag + "$1>$2</" + tag + ">");
            xml = xml.replaceAll("<" + tag + "([^>]*)>([^<]*?)$",
                               "<" + tag + "$1>$2</" + tag + ">");
        }

        // 移除重复的XML声明
        String[] parts = xml.split("\\<\\?xml[^\\>]*\\?\\>");
        if (parts.length > 2) {
            StringBuilder sb = new StringBuilder();
            sb.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>");
            for (int i = 1; i < parts.length; i++) {
                sb.append(parts[i]);
            }
            xml = sb.toString();
        }

        // 确保根元素完整
        if (!xml.contains("</TX>") && xml.contains("<TX>")) {
            xml = xml + "</TX>";
        }
        
        // 最后的激进修复：如果仍然有问题，尝试重构XML
        if (!xml.contains("</TX>") || xml.contains("<LANGUAGE>CN</LANG")) {
            log.warn("尝试激进修复：重构XML结构");
            xml = reconstructXml(xml);
        }

        // 最后检查：如果仍然有未关闭的标签，尝试智能修复
        if (xml.matches(".*<[^/>][^>]*$")) {
            log.warn("仍有未关闭的标签，进行最终修复");
            // 查找最后一个未关闭的标签
            int lastOpenTag = xml.lastIndexOf('<');
            if (lastOpenTag > 0) {
                String beforeTag = xml.substring(0, lastOpenTag);
                String tagPart = xml.substring(lastOpenTag);

                // 如果是开始标签但没有结束，尝试关闭它
                if (tagPart.matches("<[A-Z_]+[^>]*") && !tagPart.startsWith("</")) {
                    String tagName = tagPart.replaceAll("<([A-Z_]+).*", "$1");
                    xml = beforeTag + "<" + tagName + "></" + tagName + ">";
                    log.info("智能修复标签: " + tagName);
                }
            }
        }

        log.info("XML修复完成，修复后长度: " + xml.length());
        return xml;
    }

    /**
     * 重构XML结构 - 激进修复方法
     */
    private String reconstructXml(String xml) {
        log.info("开始重构XML结构");
        
        // 提取关键信息
        String requestSn = extractValue(xml, "REQUEST_SN");
        String custId = extractValue(xml, "CUST_ID");
        String txCode = extractValue(xml, "TX_CODE");
        String returnCode = extractValue(xml, "RETURN_CODE");
        String returnMsg = extractValue(xml, "RETURN_MSG");
        String language = "CN"; // 默认值
        
        // 如果能找到LANGUAGE标签的内容，使用它
        String langValue = extractValue(xml, "LANGUAGE");
        if (langValue != null && !langValue.isEmpty()) {
            language = langValue;
        }
        
        // 重构完整的XML
        StringBuilder reconstructed = new StringBuilder();
        reconstructed.append("<?xml version=\"1.0\" encoding=\"GB18030\"?>\n");
        reconstructed.append("<TX>");
        
        if (requestSn != null) reconstructed.append("<REQUEST_SN>").append(requestSn).append("</REQUEST_SN>");
        if (custId != null) reconstructed.append("<CUST_ID>").append(custId).append("</CUST_ID>");
        if (txCode != null) reconstructed.append("<TX_CODE>").append(txCode).append("</TX_CODE>");
        if (returnCode != null) reconstructed.append("<RETURN_CODE>").append(returnCode).append("</RETURN_CODE>");
        if (returnMsg != null) reconstructed.append("<RETURN_MSG>").append(returnMsg).append("</RETURN_MSG>");
        
        reconstructed.append("<LANGUAGE>").append(language).append("</LANGUAGE>");
        reconstructed.append("</TX>");
        
        String result = reconstructed.toString();
        log.info("重构完成，新XML长度: " + result.length());
        return result;
    }
    
    /**
     * 从XML中提取指定标签的值
     */
    private String extractValue(String xml, String tagName) {
        try {
            String pattern = "<" + tagName + "([^>]*)>([^<]*?)(?=<|$)";
            java.util.regex.Pattern p = java.util.regex.Pattern.compile(pattern);
            java.util.regex.Matcher m = p.matcher(xml);
            if (m.find()) {
                String value = m.group(2);
                log.debug("提取 " + tagName + ": " + value);
                return value;
            }
        } catch (Exception e) {
            log.warn("提取 " + tagName + " 失败: " + e.getMessage());
        }
        return null;
    }

    /**
     * 专门修复LANGUAGE标签截断的字节级方法
     */
    private String fixLanguageTagFromBytes(byte[] responseBytes) {
        log.info("开始字节级修复LANGUAGE标签，原始字节数: " + responseBytes.length);
        
        // 输出最后20个字节的十六进制用于调试
        StringBuilder debugHex = new StringBuilder();
        for (int i = Math.max(0, responseBytes.length - 20); i < responseBytes.length; i++) {
            debugHex.append(String.format("%02X ", responseBytes[i]));
        }
        log.info("待修复的尾部字节: " + debugHex.toString());
        
        // 查找 </LANG 的字节位置（从后往前找，更准确）
        // </LANG = 3C 2F 4C 41 4E 47
        byte[] langEndPattern = {0x3C, 0x2F, 0x4C, 0x41, 0x4E, 0x47};
        
        int langEndPos = -1;
        // 从后往前搜索，找到最后一个匹配位置
        for (int i = responseBytes.length - langEndPattern.length; i >= 0; i--) {
            boolean match = true;
            for (int j = 0; j < langEndPattern.length; j++) {
                if (responseBytes[i + j] != langEndPattern[j]) {
                    match = false;
                    break;
                }
            }
            if (match) {
                langEndPos = i;
                log.info("找到</LANG位置: " + langEndPos + " (从字节 " + i + " 开始)");
                break;
            }
        }
        
        if (langEndPos >= 0) {
            // 检查</LANG后面是否还有其他字节
            int afterLangPos = langEndPos + langEndPattern.length;
            log.info("</LANG后的位置: " + afterLangPos + ", 剩余字节数: " + (responseBytes.length - afterLangPos));
            
            // 创建新的字节数组，确保有足够空间
            byte[] newBytes = new byte[responseBytes.length + 10];
            
            // 复制到</LANG结束位置
            System.arraycopy(responseBytes, 0, newBytes, 0, afterLangPos);
            int pos = afterLangPos;
            
            // 插入缺失的UAGE>
            newBytes[pos++] = 0x55; // U
            newBytes[pos++] = 0x41; // A
            newBytes[pos++] = 0x47; // G
            newBytes[pos++] = 0x45; // E
            newBytes[pos++] = 0x3E; // >
            
            // 如果</LANG后面还有字节，复制它们
            if (afterLangPos < responseBytes.length) {
                System.arraycopy(responseBytes, afterLangPos, newBytes, pos, responseBytes.length - afterLangPos);
                pos += (responseBytes.length - afterLangPos);
                log.info("复制了 " + (responseBytes.length - afterLangPos) + " 个剩余字节");
            }
            
            // 检查是否需要添加</TX>
            String tempResult = new String(newBytes, 0, pos, java.nio.charset.StandardCharsets.ISO_8859_1);
            if (!tempResult.contains("</TX>")) {
                log.info("添加缺失的</TX>标签");
                newBytes[pos++] = 0x3C; // <
                newBytes[pos++] = 0x2F; // /
                newBytes[pos++] = 0x54; // T
                newBytes[pos++] = 0x58; // X
                newBytes[pos++] = 0x3E; // >
            }
            
            // 转换为字符串
            String result = new String(newBytes, 0, pos, java.nio.charset.StandardCharsets.ISO_8859_1);
            log.info("字节级修复成功，新长度: " + pos);
            log.info("修复后内容尾部: " + result.substring(Math.max(0, result.length() - 100)));
            
            return result;
        }
        
        log.warn("未找到</LANG模式，尝试应急修复");
        // 应急修复：直接在字符串级别处理
        String fallback = new String(responseBytes, java.nio.charset.StandardCharsets.ISO_8859_1);
        if (fallback.contains("<LANGUAGE>CN</LANG") && !fallback.contains("</LANGUAGE>")) {
            fallback = fallback.replace("<LANGUAGE>CN</LANG", "<LANGUAGE>CN</LANGUAGE>");
            if (!fallback.contains("</TX>")) {
                fallback = fallback + "</TX>";
            }
            log.info("应急修复完成");
        }
        return fallback;
    }

    /**
     * 从ZIP流中解析Excel文件
     * @param zipInputStream ZIP输入流
     * @param entryName 文件名
     * @return 解析后的文本行列表（每行使用制表符分隔各列）
     */
    private List<String> parseExcelFromZip(ZipInputStream zipInputStream, String entryName) throws IOException {
        List<String> result = new ArrayList<>();
        Workbook workbook = null;
        
        try {
            // 将ZipInputStream的内容读取到ByteArrayInputStream中
            // 因为POI需要支持随机访问的流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = zipInputStream.read(buffer)) > 0) {
                baos.write(buffer, 0, len);
            }
            
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            log.info("Excel文件字节数: " + baos.size());
            
            // 根据文件扩展名选择合适的Workbook类型
            if (entryName.toLowerCase().endsWith(".xlsx")) {
                workbook = new XSSFWorkbook(bais);
            } else {
                // 对于.xls文件，使用HSSFWorkbook（需要poi-ooxml依赖）
                workbook = WorkbookFactory.create(bais);
            }
            
            // 获取第一个工作表
            Sheet sheet = workbook.getSheetAt(0);
            log.info("Excel工作表名称: " + sheet.getSheetName() + ", 行数: " + sheet.getLastRowNum());
            
            // 输出Excel的基本信息
            log.info("Excel总行数: " + sheet.getLastRowNum());
            

            
            // 遍历所有行
            for (int rowIndex = 0; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                Row row = sheet.getRow(rowIndex);
                if (row == null) {
                    continue;
                }
                
                StringBuilder lineBuilder = new StringBuilder();
                int lastCellNum = row.getLastCellNum();
                
                // 遍历该行的所有列
                for (int cellIndex = 0; cellIndex < lastCellNum; cellIndex++) {
                    Cell cell = row.getCell(cellIndex);
                    String cellValue = "";
                    
                    if (cell != null) {
                        // 直接使用 toString() 获取单元格显示的文本值，这样可以获取格式化后的值
                        // 例如时间 "00:22:49"、日期 "2025-10-23" 等都会按显示格式返回
                        try {
                            cellValue = cell.toString();
                            // 如果是空白，设置为空字符串
                            if (cellValue == null) {
                                cellValue = "";
                            }
                        } catch (Exception e) {
                            // 如果 toString 失败，尝试根据类型获取
                            int cellType = cell.getCellType();
                            try {
                                if (cellType == Cell.CELL_TYPE_STRING) {
                                    cellValue = cell.getStringCellValue();
                                } else if (cellType == Cell.CELL_TYPE_NUMERIC) {
                                    cellValue = String.valueOf(cell.getNumericCellValue());
                                    if (cellValue.endsWith(".0")) {
                                        cellValue = cellValue.substring(0, cellValue.length() - 2);
                                    }
                                } else if (cellType == Cell.CELL_TYPE_BOOLEAN) {
                                    cellValue = String.valueOf(cell.getBooleanCellValue());
                                } else if (cellType == Cell.CELL_TYPE_BLANK) {
                                    cellValue = "";
                                } else {
                                    cellValue = "";
                                }
                            } catch (Exception e2) {
                                cellValue = "";
                            }
                        }
                    }
                    
                    // 添加制表符分隔
                    if (cellIndex > 0) {
                        lineBuilder.append("\t");
                    }
                    lineBuilder.append(cellValue);
                }
                
                result.add(lineBuilder.toString());
            }
            
            log.info("Excel解析完成，共 " + result.size() + " 行");
            
        } catch (Exception e) {
            log.error("解析Excel文件失败: " + entryName, e);
            throw new IOException("解析Excel文件失败", e);
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    log.warn("关闭Excel工作簿时出错", e);
                }
            }
        }
        
        return result;
    }

    /**
     * 等待文件生成
     * @param fileName 文件名
     * @param timeoutSeconds 超时时间（秒）
     * @return 文件是否生成成功
     */
    private boolean waitForFileGeneration(String fileName, int timeoutSeconds) {
        String filePath = "C:" + File.separator + "CCB_EBSClient" + File.separator + "download" + File.separator + fileName;
        File file = new File(filePath);

        int waitTime = 0;
        int checkInterval = 2; // 每2秒检查一次

        // 检查目录是否存在
        File downloadDir = new File("C:" + File.separator + "CCB_EBSClient" + File.separator + "download");
        if (!downloadDir.exists()) {
            log.error("下载目录不存在: " + downloadDir.getAbsolutePath());
            return false;
        }

        log.info("开始等待文件生成: " + fileName + ", 超时时间: " + timeoutSeconds + " 秒");
        log.info("文件完整路径: " + filePath);
        log.info("下载目录: " + downloadDir.getAbsolutePath() + ", 存在: " + downloadDir.exists());

        while (waitTime < timeoutSeconds) {
            // 刷新文件对象状态
            file = new File(filePath);

            if (file.exists()) {
                long fileSize = file.length();
                log.info("文件已存在: " + fileName + ", 当前大小: " + fileSize + " 字节");

                if (fileSize > 0) {
                    log.info("文件生成成功: " + filePath + ", 最终大小: " + fileSize + " 字节");

                    // 额外等待2秒确保文件写入完成
                    try {
                        Thread.sleep(2000);
                        // 再次检查文件大小是否稳定
                        long finalSize = file.length();
                        if (finalSize == fileSize) {
                            log.info("文件写入完成，大小稳定: " + finalSize + " 字节");
                            return true;
                        } else {
                            log.info("文件仍在写入中，大小变化: " + fileSize + " -> " + finalSize + " 字节");
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            } else {
                // 列出目录中的文件，帮助调试
                if (waitTime % 10 == 0) { // 每10秒打印一次目录内容
                    File[] files = downloadDir.listFiles();
                    if (files != null && files.length > 0) {
                        log.info("下载目录中的文件: ");
                        for (File f : files) {
                            log.info("  - " + f.getName() + " (大小: " + f.length() + " 字节)");
                        }
                    } else {
                        log.info("下载目录为空");
                    }
                }
            }

            try {
                log.info("等待文件生成: " + fileName + ", 已等待 " + waitTime + " 秒 / " + timeoutSeconds + " 秒");
                Thread.sleep(checkInterval * 1000);
                waitTime += checkInterval;
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("等待文件生成被中断", e);
                return false;
            }
        }

        log.error("文件生成超时: " + fileName + ", 等待了 " + timeoutSeconds + " 秒");

        // 超时后再次检查目录状态
        File[] files = downloadDir.listFiles();
        if (files != null && files.length > 0) {
            log.error("超时时下载目录中的文件: ");
            for (File f : files) {
                log.error("  - " + f.getName() + " (大小: " + f.length() + " 字节)");
            }
        } else {
            log.error("超时时下载目录为空");
        }

        return false;
    }

    /**
     * 从中专服务器下载ZIP文件到本地目录
     * @param fileName 文件名
     * @param serviceParamsService 服务参数服务
     * @return 下载是否成功
     */
    private boolean downloadZipFromIntermediaryServer(String fileName, ServiceParamsService serviceParamsService) {
        FileOutputStream fos = null;
        InputStream inputStream = null;
        CloseableHttpResponse response = null;
        
        try {
            // 1. 获取中专服务器地址
            List<HashMap<Object, Object>> serviceParams = serviceParamsService.findParamValByParamCode("hgd_dmz");
            if (serviceParams == null || serviceParams.isEmpty()) {
                log.error("未配置中转服务地址(hgd_dmz)");
                return false;
            }
            
            String dmzUrl = StringDUtil.changeNullToEmpty(serviceParams.get(0).get("PARAM_VAL"));
            if (dmzUrl.isEmpty()) {
                log.error("中转服务地址(hgd_dmz)为空");
                return false;
            }
            
            // 2. 构建下载接口URL
            String downloadUrl = dmzUrl + "/download/" + fileName;
            log.info("中专服务器下载接口URL: " + downloadUrl);
            
            // 3. 创建HTTP客户端并发送GET请求
            CloseableHttpClient httpClient = HttpClients.createDefault();
            org.apache.http.client.methods.HttpGet httpGet = new org.apache.http.client.methods.HttpGet(downloadUrl);
            httpGet.setHeader("Connection", "close");
            
            response = httpClient.execute(httpGet);
            
            // 4. 检查响应状态码
            int statusCode = response.getStatusLine().getStatusCode();
            log.info("中专服务器响应状态码: " + statusCode);
            
            if (statusCode != 200) {
                log.error("下载失败，HTTP状态码: " + statusCode + ", 原因: " + response.getStatusLine().getReasonPhrase());
                return false;
            }
            
            // 5. 获取响应实体
            HttpEntity entity = response.getEntity();
            if (entity == null) {
                log.error("响应实体为空");
                return false;
            }
            
            // 6. 确保目标目录存在
            String targetDir = "C:" + File.separator + "CCB_EBSClient" + File.separator + "download";
            File dir = new File(targetDir);
            if (!dir.exists()) {
                boolean created = dir.mkdirs();
                log.info("创建目标目录: " + targetDir + ", 结果: " + created);
            }
            
            // 7. 构建目标文件路径
            String targetFilePath = targetDir + File.separator + fileName;
            File targetFile = new File(targetFilePath);
            
            // 8. 如果文件已存在，先删除
            if (targetFile.exists()) {
                boolean deleted = targetFile.delete();
                log.info("删除已存在的文件: " + targetFilePath + ", 结果: " + deleted);
            }
            
            // 9. 将响应流写入本地文件
            inputStream = entity.getContent();
            fos = new FileOutputStream(targetFile);
            
            byte[] buffer = new byte[4096];
            int bytesRead;
            long totalBytesRead = 0;
            
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
                totalBytesRead += bytesRead;
            }
            
            fos.flush();
            
            log.info("文件下载完成: " + targetFilePath + ", 总大小: " + totalBytesRead + " 字节");
            
            // 10. 验证文件是否下载成功
            if (targetFile.exists() && targetFile.length() > 0) {
                log.info("文件验证成功，大小: " + targetFile.length() + " 字节");
                return true;
            } else {
                log.error("文件下载失败，文件不存在或大小为0");
                return false;
            }
            
        } catch (Exception e) {
            log.error("从中专服务器下载ZIP文件异常: " + fileName, e);
            return false;
        } finally {
            // 11. 关闭所有资源
            try {
                if (fos != null) {
                    fos.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
                if (response != null) {
                    EntityUtils.consumeQuietly(response.getEntity());
                    response.close();
                }
            } catch (IOException e) {
                log.warn("关闭资源时出错", e);
            }
        }
    }

}
