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 INDENT_AMOUNT_KEY = "{http://xml.apache.org/xslt}indent-amount";

    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();

            // 创建根元素
            String rootElementName = this.baosongTpl.getCode();
            rootElementName =rootElementName.replaceAll("-","_");

            Element rootElement = doc.createElement(rootElementName);
            doc.appendChild(rootElement);

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

            // 构建完整的数据映射
            Map<String, TaskRecordVo> allItems = new HashMap<>();
            Map<String, List<TaskRecordVo>> childrenByParent = new HashMap<>();

            for (TaskRecordVo item : dataList) {
                String code = item.getCode();
                String pcode = item.getPcode();

                if (code != null) {
                    allItems.put(code, item);
                }

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


            List<TaskRecordVo> rootChildren = childrenByParent.getOrDefault(rootElementName, new ArrayList<>());
            // 按itemid排序
            rootChildren.sort(Comparator.comparingInt(TaskRecordVo::getItemid));

            // 处理根节点的每个子节点
            for (TaskRecordVo child : rootChildren) {
                processItem(doc, rootElement, child, childrenByParent, allItems, "");
            }

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

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

    /**
     * 处理数据项
     */
    private void processItem(Document doc, Element parentElement, TaskRecordVo item,
                             Map<String, List<TaskRecordVo>> childrenByParent,
                             Map<String, TaskRecordVo> allItems, String parentPath) {

        String code = item.getCode();
        String title = item.getTitle();
        String currentPath = buildPath(parentPath, title);

        // 检查是否是表格节点（有多个相同code但不同rind的子项）
        if (isTableNode(code, childrenByParent)) {
            createTableNode(doc, parentElement, item, childrenByParent, currentPath);
        } else if (code.startsWith("TB")) {
            // 普通TB节点
            createNormalNode(doc, parentElement, item, childrenByParent, allItems, currentPath);
        } else {
            // 普通数据字段
            addDataField(doc, parentElement, item, currentPath);
        }
    }

    /**
     * 判断是否是表格节点
     */
    private boolean isTableNode(String nodeCode, Map<String, List<TaskRecordVo>> childrenByParent) {
        List<TaskRecordVo> children = childrenByParent.get(nodeCode);
        if (children == null || children.isEmpty()) {
            return false;
        }

        // 检查是否有多个不同的rind值
        Set<Integer> rindValues = new HashSet<>();
        for (TaskRecordVo child : children) {
            if (nodeCode.equals(child.getPcode())) {
                Integer rind = getRindValue(child);
                rindValues.add(rind);
                if (rindValues.size() > 1) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 创建表格节点
     */
    private void createTableNode(Document doc, Element parentElement, TaskRecordVo tableNode,
                                 Map<String, List<TaskRecordVo>> childrenByParent, String parentPath) {

        String code = tableNode.getCode();
        String title = tableNode.getTitle();
        String currentPath = buildPath(parentPath, title);

        logger.debug("创建表格节点: {} - {}", code, title);

        // 添加表格节点的注释
        if (title != null && !title.trim().isEmpty()) {
            String commentText = convertTitleToComment(title);
            Comment comment = doc.createComment(commentText);
            parentElement.appendChild(comment);
        }

        // 获取表格的所有子项
        List<TaskRecordVo> tableChildren = childrenByParent.getOrDefault(code, new ArrayList<>());

        // 按rind分组
        Map<Integer, List<TaskRecordVo>> rowsByRind = new TreeMap<>();

        for (TaskRecordVo child : tableChildren) {
            if (code.equals(child.getPcode())) {
                Integer rind = getRindValue(child);
                rowsByRind.computeIfAbsent(rind, k -> new ArrayList<>()).add(child);
            }
        }

        logger.debug("表格节点{}有{}行数据", code, rowsByRind.size());

        // 为每一行创建独立的元素
        for (Map.Entry<Integer, List<TaskRecordVo>> rowEntry : rowsByRind.entrySet()) {
            List<TaskRecordVo> rowData = rowEntry.getValue();

            // 创建行元素（使用相同的code）
            Element rowElement = doc.createElement(code);
            parentElement.appendChild(rowElement);

            // 按itemid排序
            rowData.sort(Comparator.comparingInt(TaskRecordVo::getItemid));

            // 添加这一行的所有字段
            for (TaskRecordVo field : rowData) {
                addDataField(doc, rowElement, field, currentPath);
            }
        }
    }

    /**
     * 创建普通节点
     */
    private void createNormalNode(Document doc, Element parentElement, TaskRecordVo node,
                                  Map<String, List<TaskRecordVo>> childrenByParent,
                                  Map<String, TaskRecordVo> allItems, String currentPath) {

        String code = node.getCode();
        String title = node.getTitle();

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

        // 创建节点元素
        Element element = doc.createElement(code);
        parentElement.appendChild(element);

        // 获取子项
        List<TaskRecordVo> children = childrenByParent.getOrDefault(code, new ArrayList<>());

        // 按itemid排序
        children.sort(Comparator.comparingInt(TaskRecordVo::getItemid));

        // 处理每个子项
        for (TaskRecordVo child : children) {
            if (code.equals(child.getPcode())) {
                processItem(doc, element, child, childrenByParent, allItems, currentPath);
            }
        }
    }

    /**
     * 添加数据字段
     */
    private void addDataField(Document doc, Element parentElement, TaskRecordVo field, String parentPath) {
        String code = field.getCode();
        String title = field.getTitle();
        String content = field.getContent();

        // 创建注释
        if (title != null && !title.trim().isEmpty() && !isSystemField(code)) {
            String fullComment = buildFullComment(title, parentPath);
            Comment comment = doc.createComment(fullComment);
            parentElement.appendChild(comment);
        }

        // 创建元素
        Element element = doc.createElement(code);
        if (content != null && !content.trim().isEmpty()) {
            element.setTextContent(content);
        }
        parentElement.appendChild(element);
    }

    /**
     * 构建路径
     */
    private String buildPath(String parentPath, String currentTitle) {
        if (currentTitle == null || currentTitle.trim().isEmpty()) {
            return parentPath;
        }

        String converted = convertTitleToComment(currentTitle);

        if (parentPath == null || parentPath.isEmpty()) {
            return converted;
        } else {
            return parentPath + "-" + converted;
        }
    }

    /**
     * 构建完整注释
     */
    private String buildFullComment(String fieldTitle, String parentPath) {
        if (fieldTitle == null || fieldTitle.trim().isEmpty()) {
            return parentPath;
        }

        if (parentPath == null || parentPath.isEmpty()) {
            return fieldTitle;
        }

        return parentPath + "-" + fieldTitle;
    }

    /**
     * 转换title为注释格式
     */
    private String convertTitleToComment(String title) {
        if (title == null) {
            return "";
        }
        return title.replace("/", "-");
    }

    /**
     * 获取rind值
     */
    private Integer getRindValue(TaskRecordVo item) {
        try {
            if (item.getRind() == null) {
                return 1;
            }
            if (item.getRind() instanceof Integer) {
                return (Integer) item.getRind();
            }
            return Integer.parseInt(item.getRind().toString());
        } catch (Exception e) {
            return 1;
        }
    }

    /**
     * 判断是否为系统字段
     */
    private boolean isSystemField(String code) {
        return code.startsWith("FILLIN_") ||
                code.equals("TELEPHONE") ||
                code.equals("FILLE_USER") ||
                code.equals("RES_PERSON") ||
                code.equals("jiaoyanwei") ||
                code.equals("isempty") ||
                code.equals("itTitle") ||
                code.equals("itVersion");
    }

    /**
     * 创建固定信息节点
     */
    private void createFixedInfoNodes(Document doc, Element parentElement) {
        try {
            String respDepart = this.baosongTask.getRespDepart() != null ?
                    this.baosongTask.getRespDepart() : "";

            Date filleDate = this.baosongTask.getEndDate();

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String fillDate = DateUtils.date2Str(filleDate,sdf);

            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() : "";
            String fillUser = this.baosongTask.getFillUser();

            // 添加固定节点（不带注释）
            addFixedNodeNoComment(doc, parentElement, "FILLIN_DEPT", respDepart);
            addFixedNodeNoComment(doc, parentElement, "FILLIN_DATE", fillDate);
            addFixedNodeNoComment(doc, parentElement, "FILLIN_PERSON", fillUser);
            addFixedNodeNoComment(doc, parentElement, "TELEPHONE", enterTel);
            addFixedNodeNoComment(doc, parentElement, "RES_PERSON", respUser);
            addFixedNodeNoComment(doc, parentElement, "jiaoyanwei", "1");
            addFixedNodeNoComment(doc, parentElement, "isempty", "0");

            String title =  baosongTpl.getCode() + " " + baosongTpl.getNm();
            addFixedNodeNoComment(doc, parentElement, "itTitle", title);
            addFixedNodeNoComment(doc, parentElement, "itVersion", version);

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

    /**
     * 添加固定节点（不带注释）
     */
    private void addFixedNodeNoComment(Document doc, Element parentElement,
                                       String tagName, String textContent) {
        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, "no");
            transformer.setOutputProperty(INDENT_AMOUNT_KEY, "2");

            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;
        }
    }
}