package com.njcn.gather.icd.mapping.component;


import com.njcn.gather.icd.mapping.pojo.bo.icd.*;
import com.njcn.gather.icd.mapping.utils.XmlTemplateParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.njcn.gather.icd.mapping.pojo.dto.*;
import com.njcn.gather.icd.mapping.pojo.bo.*;
import com.njcn.gather.icd.mapping.pojo.param.*;
import com.njcn.gather.icd.mapping.pojo.vo.*;
import com.njcn.gather.icd.mapping.pojo.enums.GenerateStatus;
import com.njcn.gather.icd.mapping.utils.GeneratedFileNameUtil;
@Component
public class RuleBasedXmlMappingService {
    
    @Autowired
    private IcdParserService icdParserService;
    
    private static final Pattern VALUE_RULE_PATTERN = Pattern.compile(
            "<Value\\s+" +
            "name=\"([^\"]+)\"\\s+" +
            "desc=\"([^\"]+)\"\\s+" +
            "type=\"([^\"]+)\"\\s+" +
            "(?:DO=\"([^\"]*)\")?\\s*" +
            "(?:DA=\"([^\"]*)\")?\\s*" +
            "(?:BaseFlag=\"([^\"]*)\")?\\s*" +
            "(?:LimitUp=\"([^\"]*)\")?\\s*" +
            "(?:LimitDown=\"([^\"]*)\")?\\s*" +
            "(?:Coefficient=\"([^\"]*)\")?\\s*" +
            "/>", Pattern.CASE_INSENSITIVE
    );
    
    private static final Pattern XML_VALUE_PATTERN = Pattern.compile(
            "<Value\\s+" +
            "name=\"([^\"]+)\"\\s+" +
            "desc=\"([^\"]+)\"\\s+" +
            "type=\"([^\"]+)\"\\s+" +
            "(?:DO=\"([^\"]*)\")?\\s*" +
            "(?:DA=\"([^\"]*)\")?\\s*" +
            "(?:BaseFlag=\"([^\"]*)\")?\\s*" +
            "(?:LimitUp=\"([^\"]*)\")?\\s*" +
            "(?:LimitDown=\"([^\"]*)\")?\\s*" +
            "(?:Coefficient=\"([^\"]*)\")?\\s*" +
            "/>", Pattern.CASE_INSENSITIVE
    );
    
    private static final Pattern DO_INDEX_PATTERN = Pattern.compile("(MMXU|MHAI|MSQI|MFLK|QVVR)(\\d+)");
    private static final Pattern DO_NO_INDEX_PATTERN = Pattern.compile("(MMXU|MHAI|MSQI|MFLK|QVVR)\\$");

    public InputStream loadDefaultXmlFile() throws Exception {
        return loadDefaultXmlFile(1);
    }

    public InputStream loadDefaultXmlFile(Integer configType) throws Exception {
        String fileName;
        if (configType != null && configType == 2) {
            fileName = "template/JiangSu_Config1.xml";
        } else {
            fileName = "template/JiangSu_Config2.xml";
        }

        ClassPathResource templateResource = new ClassPathResource(fileName);

        if (!templateResource.exists()) {
            return null;
        }

        return templateResource.getInputStream();
    }

    public List<InputStream> loadDefaultRuleFile( ) throws Exception {

        ClassPathResource ruleResource = new ClassPathResource("template/DefaultRule.txt");
        if ( !ruleResource.exists()) {
            return null;
        }

        InputStream ruleStream = ruleResource.getInputStream();
        List<InputStream> ruleStreams = new ArrayList<>();
        ruleStreams.add(ruleStream);
        return ruleStreams;
    }



    
    public String generateWithRuleFiles(IcdDocument icdDocument,
                                        InputStream templateStream,
                                        List<InputStream> ruleStreams,
                                        IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {

        Map<String, List<ValueRule>> mergedRules = mergeAllRules(ruleStreams, indexMapping);
        
        Map<String, IcdMetricInfo> icdMetrics = extractIcdMetrics(icdDocument);
        
        Map<String, ValueRule> applicableRules = findApplicableRules(mergedRules, icdMetrics);
        
        XmlTemplateParser.ParseResult parseResult = new XmlTemplateParser().parse(templateStream);
        String xmlContent = parseResult.getTemplateContent();

        xmlContent = fillIedInfo(xmlContent, icdDocument);

        xmlContent = fillReportControls(xmlContent, icdDocument);

        xmlContent = applyRulesToXml(xmlContent, applicableRules);

        Path tempPath = Paths.get(System.getProperty("java.io.tmpdir"),
                GeneratedFileNameUtil.appendToday("rule_mapped_" + UUID.randomUUID().toString().replace("-", "") + ".xml"));
        Files.write(tempPath, xmlContent.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE_NEW);
        return tempPath.toString();
    }

    
    private Map<String, List<ValueRule>> mergeAllRules(List<InputStream> ruleStreams,
                                                       IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
        Map<String, List<ValueRule>> mergedRules = new LinkedHashMap<>();
        
        for (InputStream ruleStream : ruleStreams) {
            Map<String, List<ValueRule>> rules = parseRuleFile(ruleStream, indexMapping);
            for (Map.Entry<String, List<ValueRule>> entry : rules.entrySet()) {
                String key = entry.getKey();
                List<ValueRule> ruleList = entry.getValue();
                mergedRules.computeIfAbsent(key, k -> new ArrayList<>()).addAll(ruleList);
            }
        }
        
        return mergedRules;
    }

    
    private Map<String, List<ValueRule>> parseRuleFile(InputStream ruleStream,
                                                       IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
        Map<String, List<ValueRule>> rules = new HashMap<>();
        
        BufferedReader reader = new BufferedReader(new InputStreamReader(ruleStream, StandardCharsets.UTF_8));
        String line;
        String currentGroup = "";
        
        while ((line = reader.readLine()) != null) {
            line = line.trim();
            
            if (line.startsWith("<!--")) {
                if (line.contains("MMXU") || line.contains("基本数据")) {
                    currentGroup = "MMXU";
                } else if (line.contains("间谐波")) {
                    currentGroup = "INTER_HARMONIC";
                } else if (line.contains("MHAI") && line.contains("谐波数据")) {
                    currentGroup = "MHAI";
                } else if (line.contains("MSQI") || line.contains("序分量")) {
                    currentGroup = "MSQI";
                } else if (line.contains("短闪") || line.contains("短时闪变")) {
                    currentGroup = "MFLK_SHORT";
                } else if (line.contains("长闪") || line.contains("长时闪变")) {
                    currentGroup = "MFLK_LONG";
                } else if (line.contains("QVVR") || line.contains("电压变动")) {
                    currentGroup = "QVVR";
                }
                continue;
            }
            
            if (line.isEmpty() || !line.startsWith("<Value")) {
                continue;
            }
            
            Matcher matcher = VALUE_RULE_PATTERN.matcher(line);
            if (matcher.find()) {
                ValueRule rule = new ValueRule();
                rule.setName(matcher.group(1));
                rule.setDesc(matcher.group(2));
                rule.setType(matcher.group(3));
                String doPath = matcher.group(4) != null ? matcher.group(4) : "";
                String daPath = matcher.group(5) != null ? matcher.group(5) : "";
                
                if (indexMapping != null && !doPath.isEmpty()) {
                    doPath = applyIndexMapping(doPath, currentGroup, indexMapping, rule.getName(), rule.getDesc());
                }
                
                rule.setDoPath(doPath);
                rule.setDaPath(daPath);
                rule.setBaseFlag(matcher.group(6));
                rule.setLimitUp(matcher.group(7));
                rule.setLimitDown(matcher.group(8));
                rule.setCoefficient(matcher.group(9));
                
                String key = buildRuleKey(rule.getName(), rule.getDesc());
                if (!key.isEmpty() && hasValidDoOrDa(rule)) {
                    rules.computeIfAbsent(key.toLowerCase(), k -> new ArrayList<>()).add(rule);
                }
            }
        }
        
        reader.close();
        return rules;
    }
    
    private String applyIndexMapping(String doPath, String currentGroup,
                                     IcdToXmlMappingService.IndexMappingConfig indexMapping,
                                     String name, String desc) {
        if (indexMapping == null) {
            return doPath;
        }
        
        Matcher matcherWithIndex = DO_INDEX_PATTERN.matcher(doPath);
        if (matcherWithIndex.find()) {
            String lnClass = matcherWithIndex.group(1);
            int originalIndex = Integer.parseInt(matcherWithIndex.group(2));
            
            int newIndex = determineNewIndex(currentGroup, lnClass, originalIndex, indexMapping, name, desc);
            if(name.contains("fluc")){
                System.out.println("fluc");
            }
            if (newIndex >= 0) {
                return matcherWithIndex.replaceAll(lnClass + newIndex);
            }
            
            return doPath;
        }
        
        Matcher matcherNoIndex = DO_NO_INDEX_PATTERN.matcher(doPath);
        if (matcherNoIndex.find()) {
            String lnClass = matcherNoIndex.group(1);
            
            int newIndex = determineNewIndex(currentGroup, lnClass,0, indexMapping, name, desc);
            
            if (newIndex >= 0) {
                return matcherNoIndex.replaceAll(lnClass + newIndex + "\\$");
            }
        }
        
        return doPath;
    }
    
    private int determineNewIndexByName(String currentGroup, String lnClass,
                                        IcdToXmlMappingService.IndexMappingConfig indexMapping,
                                        String name, String desc) {
        if (indexMapping == null || name == null) {
            return -1;
        }
        
        String upperName = name.toUpperCase();
        String lowerDesc = (desc != null ? desc : "").toLowerCase();
        
        boolean isMaximum = upperName.startsWith("MAX_");
        boolean isMinimum = upperName.startsWith("MIN_");
        boolean is95Percentile = upperName.startsWith("G_");
        boolean isAverage = !isMaximum && !isMinimum && !is95Percentile;
        
        // 判断是否为间谐波指标:通过desc是否包含"间谐波"
        boolean isInterHarmonic = lowerDesc.contains("间谐波");
        
        if ("MMXU".equals(currentGroup) || "MMXU".equals(lnClass)) {
            IcdToXmlMappingService.IndexMappingConfig.StatIndex mmxu = indexMapping.getMmxu();
            if (mmxu != null) {
                if (isAverage && mmxu.getAverage() != null) return mmxu.getAverage();
                if (isMaximum && mmxu.getMaximum() != null) return mmxu.getMaximum();
                if (isMinimum && mmxu.getMinimum() != null) return mmxu.getMinimum();
                if (is95Percentile && mmxu.getPercentile95() != null) return mmxu.getPercentile95();
            }
        }
        
        if ("INTER_HARMONIC".equals(currentGroup) || isInterHarmonic) {
            IcdToXmlMappingService.IndexMappingConfig.StatIndex interHarmonic = indexMapping.getInterHarmonic();
            if (interHarmonic != null) {
                if (isAverage && interHarmonic.getAverage() != null) return interHarmonic.getAverage();
                if (isMaximum && interHarmonic.getMaximum() != null) return interHarmonic.getMaximum();
                if (isMinimum && interHarmonic.getMinimum() != null) return interHarmonic.getMinimum();
                if (is95Percentile && interHarmonic.getPercentile95() != null) return interHarmonic.getPercentile95();
            }
        }
        
        if ("MHAI".equals(currentGroup) && !isInterHarmonic) {
            IcdToXmlMappingService.IndexMappingConfig.StatIndex mhai = indexMapping.getMhai();
            if (mhai != null) {
                if (isAverage && mhai.getAverage() != null) return mhai.getAverage();
                if (isMaximum && mhai.getMaximum() != null) return mhai.getMaximum();
                if (isMinimum && mhai.getMinimum() != null) return mhai.getMinimum();
                if (is95Percentile && mhai.getPercentile95() != null) return mhai.getPercentile95();
            }
        }
        
        if ("MSQI".equals(currentGroup) || "MSQI".equals(lnClass)) {
            IcdToXmlMappingService.IndexMappingConfig.StatIndex msqi = indexMapping.getMsqi();
            if (msqi != null) {
                if (isAverage && msqi.getAverage() != null) return msqi.getAverage();
                if (isMaximum && msqi.getMaximum() != null) return msqi.getMaximum();
                if (isMinimum && msqi.getMinimum() != null) return msqi.getMinimum();
                if (is95Percentile && msqi.getPercentile95() != null) return msqi.getPercentile95();
            }
        }
        
        if ("MFLK_SHORT".equals(currentGroup) || "MFLK".equals(lnClass)) {
            if (indexMapping.getMflkShort() != null) {
                return indexMapping.getMflkShort();
            }
        }
        
        if ("MFLK_LONG".equals(currentGroup)) {
            if (indexMapping.getMflkLong() != null) {
                return indexMapping.getMflkLong();
            }
        }
        
        if ("QVVR".equals(currentGroup) || "QVVR".equals(lnClass)) {
            if (indexMapping.getQvvr() != null) {
                return indexMapping.getQvvr();
            }
        }
        
        return -1;
    }
    
    private int determineNewIndex(String currentGroup, String lnClass, int originalIndex,
                                  IcdToXmlMappingService.IndexMappingConfig indexMapping,
                                  String name, String desc) {
        if (indexMapping == null) {
            return originalIndex;
        }
        
        String lowerName = (name != null ? name : "").toLowerCase();
        String lowerDesc = (desc != null ? desc : "").toLowerCase();
        
        boolean isAverage = lowerName.contains("avg") || lowerDesc.contains("平均值");
        boolean isMaximum = lowerName.startsWith("max_") || lowerDesc.contains("最大值");
        boolean isMinimum = lowerName.startsWith("min_") || lowerDesc.contains("最小值");
        boolean is95Percentile = lowerName.startsWith("g_") || lowerDesc.contains("95值");
        
        // 判断是否为间谐波指标
        boolean isInterHarmonic = lowerDesc.contains("间谐波");
        
        if ("MMXU".equals(currentGroup) || "MMXU".equals(lnClass)) {
            IcdToXmlMappingService.IndexMappingConfig.StatIndex mmxu = indexMapping.getMmxu();
            if (mmxu != null) {
                if (isAverage && mmxu.getAverage() != null) return mmxu.getAverage();
                if (isMaximum && mmxu.getMaximum() != null) return mmxu.getMaximum();
                if (isMinimum && mmxu.getMinimum() != null) return mmxu.getMinimum();
                if (is95Percentile && mmxu.getPercentile95() != null) return mmxu.getPercentile95();
            }
        }
        
        if ("INTER_HARMONIC".equals(currentGroup) || isInterHarmonic) {
            IcdToXmlMappingService.IndexMappingConfig.StatIndex interHarmonic = indexMapping.getInterHarmonic();
            if (interHarmonic != null) {
                if (isAverage && interHarmonic.getAverage() != null) return interHarmonic.getAverage();
                if (isMaximum && interHarmonic.getMaximum() != null) return interHarmonic.getMaximum();
                if (isMinimum && interHarmonic.getMinimum() != null) return interHarmonic.getMinimum();
                if (is95Percentile && interHarmonic.getPercentile95() != null) return interHarmonic.getPercentile95();
            }
        }
        
        if ("MHAI".equals(currentGroup) && !isInterHarmonic) {
            IcdToXmlMappingService.IndexMappingConfig.StatIndex mhai = indexMapping.getMhai();
            if (mhai != null) {
                if (isAverage && mhai.getAverage() != null) return mhai.getAverage();
                if (isMaximum && mhai.getMaximum() != null) return mhai.getMaximum();
                if (isMinimum && mhai.getMinimum() != null) return mhai.getMinimum();
                if (is95Percentile && mhai.getPercentile95() != null) return mhai.getPercentile95();
            }
        }
        
        if ("MSQI".equals(currentGroup) || "MSQI".equals(lnClass)) {
            IcdToXmlMappingService.IndexMappingConfig.StatIndex msqi = indexMapping.getMsqi();
            if (msqi != null) {
                if (isAverage && msqi.getAverage() != null) return msqi.getAverage();
                if (isMaximum && msqi.getMaximum() != null) return msqi.getMaximum();
                if (isMinimum && msqi.getMinimum() != null) return msqi.getMinimum();
                if (is95Percentile && msqi.getPercentile95() != null) return msqi.getPercentile95();
            }
        }
        
        if ("MFLK_SHORT".equals(currentGroup)) {
            if (indexMapping.getMflkShort() != null) {
                return indexMapping.getMflkShort();
            }
        }
        
        if ("MFLK_LONG".equals(currentGroup)) {
            if (indexMapping.getMflkLong() != null) {
                return indexMapping.getMflkLong();
            }
        }
        
        if ("QVVR".equals(currentGroup) || "QVVR".equals(lnClass)) {
            if (indexMapping.getQvvr() != null) {
                return indexMapping.getQvvr();
            }
        }
        
        return originalIndex;
    }

    private Map<String, IcdMetricInfo> extractIcdMetrics(IcdDocument icdDocument) {
        Map<String, IcdMetricInfo> metrics = new HashMap<>();
        
        if (icdDocument == null || icdDocument.getLogicalNodes() == null) {
            return metrics;
        }
        
        for (LnNode lnNode : icdDocument.getLogicalNodes()) {
            if (lnNode.getDoiList() == null) continue;
            
            for (DoiNode doiNode : lnNode.getDoiList()) {
                String doPath = buildDoPath(lnNode, doiNode);
                
                List<String> daPaths = collectAllDaPaths(doiNode.getChildren(), new ArrayList<>());
                for (String daPath : daPaths) {
                    String fullKey = buildMetricKey(doPath, daPath);
                    
                    IcdMetricInfo info = new IcdMetricInfo();
                    info.setLnClass(lnNode.getLnClass());
                    info.setLnInst(lnNode.getLnInst());
                    info.setDoName(doiNode.getName());
                    info.setDoPath(doPath);
                    info.setDaPath(daPath);
                    info.setPhase(extractPhase(daPath));
                    info.setType(extractType(daPath));
                    
                    metrics.put(fullKey.toLowerCase(), info);
                }
            }
        }
        
        return metrics;
    }
    
    private List<String> collectAllDaPaths(List<DoiElementNode> nodes, List<String> currentPath) {
        List<String> results = new ArrayList<>();
        if (nodes == null) return results;
        
        for (DoiElementNode node : nodes) {
            List<String> newPath = new ArrayList<>(currentPath);
            
            if ("SDI".equalsIgnoreCase(node.getKind())) {
                if (node.getName() != null && !node.getName().isEmpty()) {
                    String name = node.getName();
                    if (name.startsWith("phs")) {
                        if (name.endsWith("Har")) {
                            newPath.add("phs*Har");
                        } else {
                            newPath.add("phs*");
                        }
                    }
                    else {
                        newPath.add(name);
                    }
                }

                
                if (node.getChildren() != null && !node.getChildren().isEmpty()) {
                    results.addAll(collectAllDaPaths(node.getChildren(), newPath));
                }
            } else if ("DAI".equalsIgnoreCase(node.getKind())) {
                if (node.getName() != null && !node.getName().isEmpty()) {
                    newPath.add(node.getName());
                }
                
                if (node.getValues() != null && !node.getValues().isEmpty()) {
                    for (String val : node.getValues()) {
                        if (val != null && !val.isEmpty()) {
                            newPath.add(val);
                        }
                    }
                }
                
                results.add(String.join("$", newPath));
                
                if (node.getChildren() != null && !node.getChildren().isEmpty()) {
                    results.addAll(collectAllDaPaths(node.getChildren(), newPath));
                }
            }
        }
        
        return results;
    }

    private String buildDoPath(LnNode lnNode, DoiNode doiNode) {
        StringBuilder sb = new StringBuilder();
        if (lnNode.getLnClass() != null) {
            sb.append(lnNode.getLnClass());
        }
        if (lnNode.getLnInst() != null) {
            sb.append(lnNode.getLnInst());
        }
        if (doiNode.getName() != null) {
            if (sb.length() > 0) {
                sb.append("$");
                sb.append("MX");
                sb.append("$");
            }
            sb.append(doiNode.getName());
        }
        return sb.toString();
    }
    
    private String buildMetricKey(String doPath, String daPath) {
        return doPath + "|" + daPath;
    }
    
    private Map<String, ValueRule> findApplicableRules(Map<String, List<ValueRule>> allRules, 
                                                        Map<String, IcdMetricInfo> icdMetrics) {
        Map<String, ValueRule> applicable = new HashMap<>();
        
        System.out.println("========== 开始匹配规则 ==========");
        System.out.println("规则总数: " + allRules.size());
        System.out.println("ICD指标总数: " + icdMetrics.size());
        
        int matchedCount = 0;
        int unmatchedCount = 0;
        
        for (Map.Entry<String, List<ValueRule>> entry : allRules.entrySet()) {
            String ruleKey = entry.getKey();
            List<ValueRule> ruleVariants = entry.getValue();
            
            boolean foundInIcd = false;
            ValueRule matchedRule = null;
            
            System.out.println("\n正在匹配规则: " + ruleKey + " (共" + ruleVariants.size() + "个候选)");
            
            for (int i = 0; i < ruleVariants.size(); i++) {
                ValueRule rule = ruleVariants.get(i);
                if (rule.getDoPath() == null || rule.getDoPath().isEmpty()) {
                    System.out.println("  候选[" + (i+1) + "] 跳过: DO为空");
                    continue;
                }
                
                String ruleDo = normalizePath(rule.getDoPath());
                String ruleDa = normalizePath(rule.getDaPath());
                
                System.out.println("  尝试候选[" + (i+1) + "]: DO=" + rule.getDoPath() + " DA=" + rule.getDaPath());
                
                for (Map.Entry<String, IcdMetricInfo> icdEntry : icdMetrics.entrySet()) {
                    String icdKey = icdEntry.getKey();
                    IcdMetricInfo icdMetric = icdEntry.getValue();
                    
                    String icdDo = normalizePath(icdMetric.getDoPath());
                    String icdDa = normalizePath(icdMetric.getDaPath());
                    
                    boolean doMatch = matchesPattern(ruleDo, icdDo);
                    boolean daMatch = matchesPattern(ruleDa, icdDa);
                    
                    if (doMatch && daMatch) {
                        System.out.println("    ✓ 匹配成功! ICD Key: " + icdKey);
                        System.out.println("    ICD DO=" + icdMetric.getDoPath() + " DA=" + icdMetric.getDaPath());
                        foundInIcd = true;
                        matchedRule = rule;
                        break;
                    }
                }
                
                if (foundInIcd) {
                    System.out.println("  >> 规则 " + ruleKey + " 匹配成功，使用候选[" + (i+1) + "]");
                    break;
                }
            }
            
            if (foundInIcd && matchedRule != null) {
                applicable.put(ruleKey, matchedRule);
                matchedCount++;
            } else {
                unmatchedCount++;
                if (unmatchedCount <= 15) {
                    System.out.println("✗ 未匹配: " + ruleKey + " (共" + ruleVariants.size() + "个候选)");
                    for (ValueRule rule : ruleVariants) {
                        System.out.println("  候选: DO=" + rule.getDoPath() + " DA=" + rule.getDaPath());
                    }
                }
            }
        }
        
        System.out.println("\n========== 规则匹配结束 ==========");
        System.out.println("匹配成功: " + matchedCount + " 条规则");
        System.out.println("未匹配: " + unmatchedCount + " 条规则");
        
        return applicable;
    }
    
    private String normalizePath(String path) {
        if (path == null) return "";
        return path.trim().toLowerCase();
    }

    private String fillIedInfo(String xmlContent, IcdDocument icdDocument) {
        if (icdDocument == null) {
            return xmlContent;
        }

        String iedName = icdDocument.getIedName();
        String ldPrefix = icdDocument.getLdPrefix();

        if (iedName != null && !iedName.isEmpty()) {
            // 替换 <IED name="..." .../>
            xmlContent = xmlContent.replaceAll(
                "<IED\\s+name=\"[^\"]*\"",
                "<IED name=\"" + escapeXml(iedName) + "\""
            );
        }

        if (ldPrefix != null && !ldPrefix.isEmpty()) {
            // 替换 <LDevice Prefix="..." .../>
            xmlContent = xmlContent.replaceAll(
                "<LDevice\\s+Prefix=\"[^\"]*\"",
                "<LDevice Prefix=\"" + escapeXml(ldPrefix) + "\""
            );
        }

        return xmlContent;
    }

    private String fillReportControls(String xmlContent, IcdDocument icdDocument) {
        if (icdDocument == null || icdDocument.getReportControls() == null || icdDocument.getReportControls().isEmpty()) {
            return xmlContent;
        }

        // 构建 ReportStat 内容
        StringBuilder reportStatBuilder = new StringBuilder();
        reportStatBuilder.append("\t\t<ReportStat>\n");

        for (ReportControlNode rc : icdDocument.getReportControls()) {
            if (rc.getName() != null && !rc.getName().isEmpty()) {
                String name = rc.getName();
                // 只处理特定的 ReportControl 名称
                if (name.contains("brcbFluc") ||
                    name.contains("brcbStHarm") ||
                    name.contains("brcbStIHarm") ||
                    name.contains("brcbStMMXU") ||
                    name.contains("brcbStMSQI") ||
                    name.contains("brcbPLT")||
                        name.contains("brcbPST")||
                        name.contains("brcbFlicker")||
                        name.contains("brcbStatistic") ){
                    // 构建 ReportControl 字符串格式：
                    // LLN0$BR$brcbFlickerData,600,0,0,1,0,0,yes,1,1,1,1,1,0,1,1,1,3,1
                    String reportControlStr = buildReportControlString(rc);
                    reportStatBuilder.append("\t\t\t<Report ReportControl=\"")
                        .append(escapeXml(reportControlStr))
                        .append("\" />\n");
                }
            }

        }

        reportStatBuilder.append("\t\t</ReportStat>");

        // 替换原有的 <ReportStat>...</ReportStat> 部分
        xmlContent = xmlContent.replaceAll(
            "<ReportStat>[\\s\\S]*?</ReportStat>",
            reportStatBuilder.toString().replace("$", "\\$").replace("[", "\\[").replace("]", "\\]")
        );

        return xmlContent;
    }

    private String buildReportControlString(ReportControlNode rc) {
        // 格式：LLN0$BR$brcbName,intgPd,dchg,qchg,dupd,period,gi,issuffixed,seqNum,timeStamp,reasonCode,dataSet,dataRef,bufOvfl,entryID,configRef,segmentation,FlickerFlag
        StringBuilder sb = new StringBuilder();

        // ReportControl 名称（需要根据实际情况调整前缀）
        sb.append("LLN0$").append(rc.getBuffered() != null && rc.getBuffered() ? "BR$" : "RP$").append(rc.getName());
        // 这里需要根据实际 ICD 中的配置来填充其他字段
        // 目前使用默认值，后续可以根据 ReportControlNode 的字段扩展
        if(rc.getName().contains("PLT") || rc.getName().contains("Flicker") || rc.getName().contains("PST") || rc.getName().contains("Fluc")){
            sb.append(",600");      // intgPd - 上送周期
        }else{
            sb.append(",60");      // intgPd - 上送周期
        }
        sb.append(",1");        // dchg - 数据变化触发
        sb.append(",0");        // qchg - 品质变化触发
        sb.append(",0");        // dupd - 数据更新触发
        sb.append(",0");        // period - 周期触发
        sb.append(",0");        // gi - 总召唤
        sb.append(",yes");      // issuffixed
        sb.append(",1");        // seqNum
        sb.append(",1");        // timeStamp
        sb.append(",1");        // reasonCode
        sb.append(",1");        // dataSet
        sb.append(",1");        // dataRef
        sb.append(",0");        // bufOvfl
        sb.append(",1");        // entryID
        sb.append(",1");        // configRef
        sb.append(",1");        // segmentation
        sb.append(",3");        // 保留字段
        if(rc.getName().contains("PLT") || rc.getName().contains("Flicker")){
            sb.append(",1");        // FlickerFlag
        }else if(rc.getName().contains("PST") || rc.getName().contains("Fluc")){
            sb.append(",2");        // FlickerFlag
        } else {
            sb.append(",0");        // FlickerFlag
        }


        return sb.toString();
    }

    private boolean matchesPattern(String pattern, String actual) {
        if (pattern == null || actual == null) {
            return pattern == null && actual == null;
        }
        
        String normalizedPattern = pattern.replaceAll("\\[[^\\]]*\\]", "");

        
        if (normalizedPattern.isEmpty() || actual.isEmpty()) {
            return normalizedPattern.isEmpty() && actual.isEmpty();
        }

        return actual.equals(normalizedPattern);
    }
    
    private String applyRulesToXml(String xmlContent, Map<String, ValueRule> applicableRules) {
        Matcher matcher = XML_VALUE_PATTERN.matcher(xmlContent);
        StringBuffer result = new StringBuffer();
        
        while (matcher.find()) {
            String name = matcher.group(1);
            String desc = matcher.group(2);
            String type = matcher.group(3);
            
            String key = buildRuleKey(name, desc);
            ValueRule matchedRule = applicableRules.get(key.toLowerCase());
            
            if (matchedRule != null) {
                StringBuilder valueNode = new StringBuilder("<Value ");
                valueNode.append("name=\"").append(escapeXml(name)).append("\" ");
                valueNode.append("desc=\"").append(escapeXml(desc)).append("\" ");
                valueNode.append("type=\"").append(type).append("\" ");
                
                if ((matchedRule.getDoPath() != null) && !matchedRule.getDoPath().isEmpty()) {
                    valueNode.append("DO=\"").append(escapeXml(matchedRule.getDoPath())).append("\" ");
                }
                if (matchedRule.getDaPath() != null && !matchedRule.getDaPath().isEmpty()) {
                    valueNode.append("DA=\"").append(escapeXml(matchedRule.getDaPath())).append("\" ");
                }
                if (matchedRule.getBaseFlag() != null && !matchedRule.getBaseFlag().isEmpty()) {
                    valueNode.append("BaseFlag=\"").append(escapeXml(matchedRule.getBaseFlag())).append("\" ");
                }
                if (matchedRule.getLimitUp() != null && !matchedRule.getLimitUp().isEmpty()) {
                    valueNode.append("LimitUp=\"").append(escapeXml(matchedRule.getLimitUp())).append("\" ");
                }
                if (matchedRule.getLimitDown() != null && !matchedRule.getLimitDown().isEmpty()) {
                    valueNode.append("LimitDown=\"").append(escapeXml(matchedRule.getLimitDown())).append("\" ");
                }
                if (matchedRule.getCoefficient() != null && !matchedRule.getCoefficient().isEmpty()) {
                    valueNode.append("Coefficient=\"").append(escapeXml(matchedRule.getCoefficient())).append("\" ");
                }
                
                valueNode.append("/>");
                matcher.appendReplacement(result, Matcher.quoteReplacement(valueNode.toString()));
            }
        }
        matcher.appendTail(result);
        
        return result.toString();
    }
    
    private String buildRuleKey(String name, String desc) {
        if (name != null && !name.isEmpty()) {
            return name;
        }
        return desc != null ? desc : "";
    }
    
    private boolean hasValidDoOrDa(ValueRule rule) {
        return (rule.getDoPath() != null && !rule.getDoPath().isEmpty()) ||
               (rule.getDaPath() != null && !rule.getDaPath().isEmpty());
    }
    
    private String extractPhase(String daPath) {
        if (daPath == null) return "";
        if (daPath.contains("phsA")) return "A";
        if (daPath.contains("phsB")) return "B";
        if (daPath.contains("phsC")) return "C";
        if (daPath.contains("c1")) return "正序";
        if (daPath.contains("c2")) return "负序";
        if (daPath.contains("c3")) return "零序";
        return "无相别";
    }
    
    private String extractType(String daPath) {
        if (daPath == null) return "";
        if (daPath.contains("mag")) return "mag";
        if (daPath.contains("ang")) return "ang";
        return "";
    }
    
    private String escapeXml(String text) {
        if (text == null) return "";
        return text.replace("&", "&amp;")
                   .replace("<", "&lt;")
                   .replace(">", "&gt;")
                   .replace("\"", "&quot;")
                   .replace("'", "&apos;");
    }
    

    

    

    static class ValueRule {
        private String name;
        private String desc;
        private String type;
        private String doPath;
        private String daPath;
        private String baseFlag;
        private String limitUp;
        private String limitDown;
        private String coefficient;
        private String offset;
        private String pltFlag;

        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getDesc() { return desc; }
        public void setDesc(String desc) { this.desc = desc; }
        public String getType() { return type; }
        public void setType(String type) { this.type = type; }
        public String getDoPath() { return doPath; }
        public void setDoPath(String doPath) { this.doPath = doPath; }
        public String getDaPath() { return daPath; }
        public void setDaPath(String daPath) { this.daPath = daPath; }
        public String getBaseFlag() { return baseFlag; }
        public void setBaseFlag(String baseFlag) { this.baseFlag = baseFlag; }
        public String getLimitUp() { return limitUp; }
        public void setLimitUp(String limitUp) { this.limitUp = limitUp; }
        public String getLimitDown() { return limitDown; }
        public void setLimitDown(String limitDown) { this.limitDown = limitDown; }
        public String getCoefficient() { return coefficient; }
        public void setCoefficient(String coefficient) { this.coefficient = coefficient; }
        public String getOffset() { return offset; }
        public void setOffset(String offset) { this.offset = offset; }
        public String getPltFlag() { return pltFlag; }
        public void setPltFlag(String pltFlag) { this.pltFlag = pltFlag; }
    }
    
    static class IcdMetricInfo {
        private String lnClass;
        private String lnInst;
        private String doName;
        private String doPath;
        private String daPath;
        private String phase;
        private String type;

        public String getLnClass() { return lnClass; }
        public void setLnClass(String lnClass) { this.lnClass = lnClass; }
        public String getLnInst() { return lnInst; }
        public void setLnInst(String lnInst) { this.lnInst = lnInst; }
        public String getDoName() { return doName; }
        public void setDoName(String doName) { this.doName = doName; }
        public String getDoPath() { return doPath; }
        public void setDoPath(String doPath) { this.doPath = doPath; }
        public String getDaPath() { return daPath; }
        public void setDaPath(String daPath) { this.daPath = daPath; }
        public String getPhase() { return phase; }
        public void setPhase(String phase) { this.phase = phase; }
        public String getType() { return type; }
        public void setType(String type) { this.type = type; }
    }
}
