package org.jeecg.modules.stm.baosong.controller;

import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.stm.baosong.entity.BaosongTask;
import org.jeecg.modules.stm.baosong.entity.BaosongTpl;
import org.jeecg.modules.stm.baosong.entity.TaskRecordVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;

public class CreateXmlFile {
    private static final Logger logger = LoggerFactory.getLogger(CreateXmlFile.class);

    // 常量定义
    private static final String DEFAULT_ENCODING = "UTF-8";
    private static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd";
    private static final String INDENT_AMOUNT_KEY = "{http://xml.apache.org/xslt}indent-amount";
    private static final int DEFAULT_RIND_VALUE = 1;

    private final BaosongTpl baosongTpl;
    private final BaosongTask baosongTask;
    private final String fillUserNames;

    public CreateXmlFile(BaosongTpl baosongTpl, BaosongTask baosongTask, String fillUserNames) {
        this.baosongTpl = Objects.requireNonNull(baosongTpl, "baosongTpl cannot be null");
        this.baosongTask = Objects.requireNonNull(baosongTask, "baosongTask cannot be null");
        this.fillUserNames = fillUserNames != null ? fillUserNames : "";
    }

    /**
     * 创建XML文件
     */
    public boolean createXml(List<TaskRecordVo> dataList, String filePath) {

        if (dataList == null || dataList.isEmpty()) {
            logger.warn("数据列表为空，无法生成XML文件");
            return false;
        }

        if (filePath == null || filePath.trim().isEmpty()) {
            logger.error("文件路径不能为空");
            return false;
        }

        try {
            // 创建Document
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
            Document doc = docBuilder.newDocument();

            // 创建根元素
            Comment rootComment = doc.createComment(baosongTpl.getNm());
            doc.appendChild(rootComment);

            String rootElementName = normalizeElementName(this.baosongTpl.getCode());
            Element rootElement = doc.createElement(rootElementName);
            doc.appendChild(rootElement);

            // 添加固定信息节点
            createFixedInfoNodes(doc, rootElement);

            // 重新组织数据结构 - 按层级关系构建树形结构
            Map<String, TaskRecordVo> codeToItemMap = new HashMap<>();
            Map<String, List<TaskRecordVo>> pcodeToChildrenMap = new HashMap<>();
            Set<String> allCodes = new HashSet<>();

            // 第一步：构建映射关系
            for (TaskRecordVo item : dataList) {
                String code = item.getCode();
                String pcode = item.getPcode();

                if (code != null) {
                    codeToItemMap.put(code, item);
                    allCodes.add(code);
                }

                if (pcode != null && !pcode.trim().isEmpty()) {
                    pcodeToChildrenMap.computeIfAbsent(pcode, k -> new ArrayList<>()).add(item);
                }
            }

            // 第二步：找出顶级节点（根节点的直接子节点）
            // 从目标XML可以看到，顶级节点是像TB1001、TB1012等
            // 我们需要根据数据推断哪些是顶级节点
            List<String> topLevelNodes = findTopLevelNodes(dataList, allCodes, codeToItemMap);

            logger.debug("找到的顶级节点: {}", topLevelNodes);

            // 第三步：为每个顶级节点创建XML结构
            for (String topNodeCode : topLevelNodes) {
                createNodeStructure(doc, rootElement, topNodeCode,
                        codeToItemMap, pcodeToChildrenMap, new HashSet<>());
            }

            // 保存XML
            return saveXmlToFile(doc, filePath);

        } catch (Exception e) {
            logger.error("创建XML文件时发生错误", e);
            return false;
        }
    }

    /**
     * 找出顶级节点
     */
    private List<String> findTopLevelNodes(List<TaskRecordVo> dataList, Set<String> allCodes,
                                           Map<String, TaskRecordVo> codeToItemMap) {
        List<String> topNodes = new ArrayList<>();

        // 收集所有可能的节点代码
        Set<String> allPcodes = new HashSet<>();
        for (TaskRecordVo item : dataList) {
            String pcode = item.getPcode();
            if (pcode != null && !pcode.trim().isEmpty()) {
                allPcodes.add(pcode);
            }
        }

        // 顶级节点特征：
        // 1. 是一个pcode（有数据以此pcode为父节点）
        // 2. 但不是其他节点的子节点（即这个pcode不作为code出现在数据中）
        // 3. 或者这个pcode虽然有对应的item，但它的pcode是T_B_1或空
        for (String pcode : allPcodes) {
            if (!allCodes.contains(pcode)) {
                // 这个pcode没有对应的item，说明它是顶级节点
                topNodes.add(pcode);
            } else {
                // 这个pcode有对应的item，检查它的父节点
                TaskRecordVo item = codeToItemMap.get(pcode);
                if (item != null) {
                    String parentPcode = item.getPcode();
                    if (parentPcode == null || parentPcode.trim().isEmpty() ||
                            "T_B_1".equals(parentPcode)) {
                        topNodes.add(pcode);
                    }
                }
            }
        }

        return topNodes;
    }

    /**
     * 创建节点结构
     */
    /**
     * 创建节点结构
     */
    private void createNodeStructure(Document doc, Element parentElement, String nodeCode,
                                     Map<String, TaskRecordVo> codeToItemMap,
                                     Map<String, List<TaskRecordVo>> pcodeToChildrenMap,
                                     Set<String> processedNodes) {

        if (processedNodes.contains(nodeCode)) {
            return; // 防止循环
        }
        processedNodes.add(nodeCode);

        // 检查是否有子节点
        boolean hasChildren = pcodeToChildrenMap.containsKey(nodeCode);

        if (hasChildren) {
            // 创建外层节点
            Element outerElement = doc.createElement(nodeCode);
            parentElement.appendChild(outerElement);

            // 获取子节点并按rind分组
            List<TaskRecordVo> children = pcodeToChildrenMap.get(nodeCode);
            Map<Integer, List<TaskRecordVo>> childrenByRind = groupByRind(children, nodeCode);

            // 检查分组数量
            if (childrenByRind.size() == 1) {
                // 只有一个分组，直接将节点添加到outerElement
                for (Map.Entry<Integer, List<TaskRecordVo>> rindEntry : childrenByRind.entrySet()) {
                    List<TaskRecordVo> rindGroup = rindEntry.getValue();

                    // 处理这个分组中的每个子项
                    for (TaskRecordVo child : rindGroup) {
                        // 检查这个子项是否本身还有子项
                        String childCode = child.getCode();

                        if (pcodeToChildrenMap.containsKey(childCode)) {
                            // 这个子项还有子项，递归处理
                            createNodeStructure(doc, outerElement, childCode,
                                    codeToItemMap, pcodeToChildrenMap, processedNodes);
                        } else {
                            // 这个子项是叶子节点，直接添加到outerElement
                            addDataItem(doc, outerElement, child);
                        }
                    }
                }
            } else {
                // 多个分组，创建内层节点
                for (Map.Entry<Integer, List<TaskRecordVo>> rindEntry : childrenByRind.entrySet()) {
                    List<TaskRecordVo> rindGroup = rindEntry.getValue();

                    // 创建内层节点
                    Element innerElement = doc.createElement(nodeCode);
                    outerElement.appendChild(innerElement);

                    // 处理这个分组中的每个子项
                    for (TaskRecordVo child : rindGroup) {
                        // 检查这个子项是否本身还有子项
                        String childCode = child.getCode();

                        if (pcodeToChildrenMap.containsKey(childCode)) {
                            // 这个子项还有子项，递归处理
                            createNodeStructure(doc, innerElement, childCode,
                                    codeToItemMap, pcodeToChildrenMap, processedNodes);
                        } else {
                            // 这个子项是叶子节点，直接添加
                            addDataItem(doc, innerElement, child);
                        }
                    }
                }
            }
        } else {
            // 没有子节点，可能是数据项或空节点
            TaskRecordVo item = codeToItemMap.get(nodeCode);
            if (item != null) {
                addDataItem(doc, parentElement, item);
            }
        }
    }

    /**
     * 按rind分组
     */
    private Map<Integer, List<TaskRecordVo>> groupByRind(List<TaskRecordVo> items, String pcode) {
        Map<Integer, List<TaskRecordVo>> groups = new HashMap<>();

        for (TaskRecordVo item : items) {
            if (pcode.equals(item.getPcode())) {
                int rind = getIntValue(item, DEFAULT_RIND_VALUE);
                groups.computeIfAbsent(rind, k -> new ArrayList<>()).add(item);
            }
        }

        return groups;
    }

    /**
     * 添加数据项（带注释）
     */
    private void addDataItem(Document doc, Element parentElement, TaskRecordVo item) {
        String title = item.getTitle();
        String code = item.getCode();
        String content = item.getContent();

        // 添加注释
        if (title != null && !title.trim().isEmpty()) {
            Comment comment = doc.createComment(title);
            parentElement.appendChild(comment);
        }

        // 创建元素
        Element element = doc.createElement(code);
        element.setTextContent(content != null ? content : "");
        parentElement.appendChild(element);
    }

    /**
     * 创建固定信息节点
     */
    private void createFixedInfoNodes(Document doc, Element parentElement) {
        try {
            String respDepart = this.baosongTask.getRespDepart() != null ?
                    this.baosongTask.getRespDepart() : "";
            String enterDate = this.baosongTask.getEnterDate();//formatDate(this.baosongTask.getEnterDate(), DATE_FORMAT_PATTERN);
            String enterTel = this.baosongTask.getEnterTel() != null ?
                    this.baosongTask.getEnterTel() : "";
            String respUser = this.baosongTask.getRespUser() != null ?
                    this.baosongTask.getRespUser() : "";
            String version = this.baosongTpl.getVersion() != null ?
                    this.baosongTpl.getVersion() : "";

            addFixedNode(doc, parentElement, "FILLIN_DEPT", respDepart, "填报部门");
            addFixedNode(doc, parentElement, "FILLIN_DATE", enterDate, "填报日期");
            addFixedNode(doc, parentElement, "FILLIN_PERSON", this.fillUserNames, "填报人");
            addFixedNode(doc, parentElement, "TELEPHONE", enterTel, "联系电话");
            addFixedNode(doc, parentElement, "RES_PERSON", respUser, "负责人");
            addFixedNode(doc, parentElement, "jiaoyanwei", "0", "校验位");
            addFixedNode(doc, parentElement, "isempty", "yes", "是否为空");

            String title = this.baosongTpl.getCode() + " " + this.baosongTpl.getNm();
            addFixedNode(doc, parentElement, "itTitle", title, "模板标题");
            addFixedNode(doc, parentElement, "itVersion", version, "模板版本");

        } catch (Exception e) {
            logger.error("创建固定信息节点时发生错误", e);
        }
    }

    /**
     * 添加固定节点
     */
    private void addFixedNode(Document doc, Element parentElement,
                              String tagName, String textContent, String comment) {
        if (comment != null && !comment.trim().isEmpty()) {
            Comment commentNode = doc.createComment(comment);
            parentElement.appendChild(commentNode);
        }

        Element element = doc.createElement(tagName);
        element.setTextContent(textContent != null ? textContent : "");
        parentElement.appendChild(element);
    }

    /**
     * 保存XML到文件
     */
    private boolean saveXmlToFile(Document doc, String filePath) {
        try {
            File file = new File(filePath);
            File parentDir = file.getParentFile();
            if (parentDir != null && !parentDir.exists() && !parentDir.mkdirs()) {
                logger.error("创建目录失败: {}", parentDir.getAbsolutePath());
                return false;
            }

            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.ENCODING, DEFAULT_ENCODING);
            transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
            transformer.setOutputProperty(INDENT_AMOUNT_KEY, "4");

            DOMSource source = new DOMSource(doc);
            StreamResult result = new StreamResult(file);
            transformer.transform(source, result);

            logger.info("XML文件生成成功: {}", filePath);
            return true;

        } catch (Exception e) {
            logger.error("保存XML文件时发生错误: {}", filePath, e);
            return false;
        }
    }

    /**
     * 规范化元素名称
     */
    private String normalizeElementName(String name) {
        return name != null ? name.replace("-", "_") : "";
    }

    /**
     * 格式化日期
     */
    private String formatDate(Date date, String pattern) {
        if (date == null) {
            return "";
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            return DateUtils.date2Str(date, sdf);
        } catch (Exception e) {
            logger.warn("日期格式化失败", e);
            return "";
        }
    }

    /**
     * 获取整数值
     */
    private int getIntValue(TaskRecordVo taskRecordVo, int defaultValue) {
        try {
            Object value = taskRecordVo.getRind();
            if (value == null) {
                return defaultValue;
            }
            if (value instanceof Number) {
                return ((Number) value).intValue();
            }
            return Integer.parseInt(value.toString());
        } catch (NumberFormatException e) {
            logger.warn("解析rind值失败，使用默认值: {}", defaultValue);
            return defaultValue;
        }
    }
}