package com.zt.plat.module.base.service.doctemplate;

import cn.hutool.core.util.StrUtil;
import com.zt.plat.module.base.dal.dataobject.doctemplate.DocTemplateDO;
import com.zt.plat.module.base.dal.dataobject.doctemplate.DocTemplateInstanceDO;
import com.zt.plat.module.base.dal.dao.doctemplate.DocTemplateMapper;
import com.zt.plat.module.base.dal.dao.doctemplate.DocTemplateInstanceMapper;
import lombok.extern.slf4j.Slf4j;
import org.docx4j.Docx4J;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.util.Map;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.base.enums.ErrorCodeConstants.*;

/**
 * 文档渲染API服务实现类
 * 使用 docx4j 库处理 Word 导出，支持多种渲染方式
 *
 * @author system
 */
@Service
@Slf4j
public class DocumentRenderApiServiceImpl implements DocumentRenderApiService {

    @Resource
    private DocTemplateRenderService templateRenderService;

    @Resource
    private DocTemplateMapper templateMapper;

    @Resource
    private DocTemplateInstanceMapper instanceMapper;

    @Override
    public String renderByTemplate(Long templateId, Map<String, Object> dataMap) {
        if (templateId == null) {
            throw new IllegalArgumentException("模板ID不能为空");
        }
        DocTemplateDO template = templateMapper.selectById(templateId);
        if (template == null) {
            throw exception(TEMPLATE_NOT_EXISTS);
        }
        return templateRenderService.render(templateId, null, null, dataMap);
    }

    @Override
    public String renderByInstance(Long instanceId, Map<String, Object> dataMap) {
        if (instanceId == null) {
            throw new IllegalArgumentException("实例ID不能为空");
        }
        DocTemplateInstanceDO instance = instanceMapper.selectById(instanceId);
        if (instance == null) {
            throw exception(TEMPLATE_INSTANCE_NOT_EXISTS);
        }
        return templateRenderService.render(null, instanceId, null, dataMap);
    }

    @Override
    public String renderByBusinessType(Long instanceId, String businessType, Map<String, Object> businessDataMap) {
        if (instanceId == null) {
            throw new IllegalArgumentException("实例ID不能为空");
        }
        if (StrUtil.isBlank(businessType)) {
            throw new IllegalArgumentException("业务类型不能为空");
        }

        // 获取实例信息
        DocTemplateInstanceDO instance = instanceMapper.selectById(instanceId);
        if (instance == null) {
            throw exception(TEMPLATE_INSTANCE_NOT_EXISTS);
        }

        // 业务系统自己组织的dataMap，可以包含SQL查询结果、业务数据等
        // 直接使用该dataMap进行渲染
        if (businessDataMap == null || businessDataMap.isEmpty()) {
            log.warn("业务数据集为空，instanceId: {}, businessType: {}", instanceId, businessType);
            businessDataMap = Map.of();
        }

        return templateRenderService.render(null, instanceId, null, businessDataMap);
    }

    @Override
    public String renderByContent(String content, Map<String, Object> dataMap) {
        if (StrUtil.isBlank(content)) {
            throw new IllegalArgumentException("模板内容不能为空");
        }
        return templateRenderService.render(null, null, content, dataMap);
    }

    @Override
    public byte[] exportToWord(String html, String fileName) {
        if (StrUtil.isBlank(html)) {
            throw new IllegalArgumentException("HTML内容不能为空");
        }
        if (StrUtil.isBlank(fileName)) {
            fileName = "document";
        }

        try {
            // 创建 Word 文档
            WordprocessingMLPackage wordPackage = WordprocessingMLPackage.createPackage();
            MainDocumentPart mainDocumentPart = wordPackage.getMainDocumentPart();

            // 解析 HTML
            Document htmlDoc = Jsoup.parse(html);

            // 处理 HTML 内容并添加到 Word 文档
            processHtmlToWord(mainDocumentPart, htmlDoc.body());

            // 转换为字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            wordPackage.save(baos);

            log.info("Word导出成功，文件名: {}.docx, 大小: {} bytes", fileName, baos.size());
            return baos.toByteArray();

        } catch (Exception e) {
            log.error("Word导出失败，fileName: {}", fileName, e);
            throw new RuntimeException("Word导出失败: " + e.getMessage(), e);
        }
    }

    @Override
    public byte[] renderAndExportToWord(Long instanceId, Map<String, Object> dataMap, String fileName) {
        // 先渲染获取HTML
        String html = renderByInstance(instanceId, dataMap);
        // 再导出为Word
        return exportToWord(html, fileName);
    }

    /**
     * 将 HTML 转换为 Word 文档内容
     * 递归处理 HTML 节点，使用 docx4j API 构建完整的 Word 文档
     * 增强版本：支持CSS样式保留（颜色、对齐、字体等）
     */
    private void processHtmlToWord(MainDocumentPart mainDocumentPart, Element element) throws Exception {
        for (Node node : element.childNodes()) {
            if (node instanceof TextNode) {
                String text = ((TextNode) node).getWholeText();
                if (StrUtil.isNotBlank(text.trim())) {
                    mainDocumentPart.addStyledParagraphOfText("Normal", text.trim());
                }
            } else if (node instanceof Element) {
                Element element1 = (Element) node;
                String tagName = element1.tagName().toLowerCase();

                switch (tagName) {
                    case "h1", "h2", "h3", "h4", "h5", "h6" -> {
                        // 使用带样式的段落处理，而不是使用预定义样式
                        addStyledParagraph(mainDocumentPart, element1, true);
                    }
                    case "p" -> {
                        addStyledParagraph(mainDocumentPart, element1, false);
                    }
                    case "br" -> {
                        mainDocumentPart.addParagraphOfText("");
                    }
                    case "table" -> {
                        processTable(mainDocumentPart, (Element) node);
                    }
                    case "ul", "ol" -> {
                        processHtmlToWord(mainDocumentPart, element1);
                    }
                    case "li" -> {
                        addStyledParagraph(mainDocumentPart, element1, false);
                    }
                    case "strong", "b" -> {
                        addStyledParagraph(mainDocumentPart, element1, false);
                    }
                    case "i", "em" -> {
                        addStyledParagraph(mainDocumentPart, element1, false);
                    }
                    case "div", "section", "article" -> {
                        processHtmlToWord(mainDocumentPart, element1);
                    }
                    default -> {
                        processHtmlToWord(mainDocumentPart, element1);
                    }
                }
            }
        }
    }

    /**
     * 添加带样式的段落（支持CSS样式解析）
     * @param mainDocumentPart Word文档主体部分
     * @param element HTML元素
     * @param isHeading 是否是标题
     */
    private void addStyledParagraph(MainDocumentPart mainDocumentPart, Element element, boolean isHeading) throws Exception {
        ObjectFactory factory = new ObjectFactory();
        P paragraph = factory.createP();

        // 创建段落属性
        PPr pPr = factory.createPPr();
        paragraph.setPPr(pPr);

        // 解析并应用段落级样式（对齐方式）
        String styleAttr = element.attr("style");
        if (StrUtil.isNotBlank(styleAttr)) {
            // 解析对齐方式
            String textAlign = extractCssProperty(styleAttr, "text-align");
            if (StrUtil.isNotBlank(textAlign)) {
                Jc jc = factory.createJc();
                switch (textAlign.toLowerCase()) {
                    case "center" -> jc.setVal(JcEnumeration.CENTER);
                    case "right" -> jc.setVal(JcEnumeration.RIGHT);
                    case "justify" -> jc.setVal(JcEnumeration.BOTH);
                    default -> jc.setVal(JcEnumeration.LEFT);
                }
                pPr.setJc(jc);
            }
        }

        // 创建文本运行
        R run = factory.createR();
        Text text = factory.createText();
        text.setValue(element.text());
        run.getContent().add(text);

        // 创建文本运行属性
        RPr rPr = factory.createRPr();
        run.setRPr(rPr);

        // 应用字体样式
        if (StrUtil.isNotBlank(styleAttr)) {
            // 解析颜色
            String color = extractCssProperty(styleAttr, "color");
            if (StrUtil.isNotBlank(color)) {
                Color colorObj = factory.createColor();
                String hexColor = convertColorToHex(color);
                if (hexColor != null) {
                    colorObj.setVal(hexColor);
                    rPr.setColor(colorObj);
                }
            }

            // 解析字体大小
            String fontSize = extractCssProperty(styleAttr, "font-size");
            if (StrUtil.isNotBlank(fontSize)) {
                HpsMeasure hpsMeasure = factory.createHpsMeasure();
                // 将px转换为half-points (1px ≈ 1.5半点)
                try {
                    int pxValue = Integer.parseInt(fontSize.replaceAll("[^0-9]", ""));
                    int halfPoints = pxValue * 2; // 简化转换
                    hpsMeasure.setVal(java.math.BigInteger.valueOf(halfPoints));
                    rPr.setSz(hpsMeasure);
                    rPr.setSzCs(hpsMeasure); // 复杂脚本字体大小
                } catch (NumberFormatException e) {
                    log.warn("无法解析字体大小: {}", fontSize);
                }
            }

            // 解析字体
            String fontFamily = extractCssProperty(styleAttr, "font-family");
            if (StrUtil.isNotBlank(fontFamily)) {
                RFonts rFonts = factory.createRFonts();
                fontFamily = fontFamily.replaceAll("['\"]", "").split(",")[0].trim();
                rFonts.setAscii(fontFamily);
                rFonts.setHAnsi(fontFamily);
                rFonts.setCs(fontFamily);
                rFonts.setEastAsia(fontFamily);
                rPr.setRFonts(rFonts);
            }

            // 解析粗体
            String fontWeight = extractCssProperty(styleAttr, "font-weight");
            if ("bold".equalsIgnoreCase(fontWeight) || "700".equals(fontWeight) || "800".equals(fontWeight) || "900".equals(fontWeight)) {
                BooleanDefaultTrue bold = factory.createBooleanDefaultTrue();
                bold.setVal(true);
                rPr.setB(bold);
                rPr.setBCs(bold);
            }

            // 解析斜体
            String fontStyle = extractCssProperty(styleAttr, "font-style");
            if ("italic".equalsIgnoreCase(fontStyle) || "oblique".equalsIgnoreCase(fontStyle)) {
                BooleanDefaultTrue italic = factory.createBooleanDefaultTrue();
                italic.setVal(true);
                rPr.setI(italic);
                rPr.setICs(italic);
            }

            // 背景色支持 - 暂时注释掉因为 docx4j API 兼容性问题
            // 如果需要可以后续使用 CTShd 重新实现
        }

        // 处理标签自身的样式（strong, b, i, em）
        String tagName = element.tagName().toLowerCase();
        if ("strong".equals(tagName) || "b".equals(tagName)) {
            BooleanDefaultTrue bold = factory.createBooleanDefaultTrue();
            bold.setVal(true);
            rPr.setB(bold);
            rPr.setBCs(bold);
        }
        if ("i".equals(tagName) || "em".equals(tagName)) {
            BooleanDefaultTrue italic = factory.createBooleanDefaultTrue();
            italic.setVal(true);
            rPr.setI(italic);
            rPr.setICs(italic);
        }

        // 标题默认加粗且增大字号
        if (isHeading) {
            BooleanDefaultTrue bold = factory.createBooleanDefaultTrue();
            bold.setVal(true);
            rPr.setB(bold);
            rPr.setBCs(bold);

            // 根据标题级别设置字号（如果没有显式指定）
            if (rPr.getSz() == null) {
                HpsMeasure hpsMeasure = factory.createHpsMeasure();
                String tag = element.tagName().toLowerCase();
                int size = switch (tag) {
                    case "h1" -> 32; // 16pt
                    case "h2" -> 28; // 14pt
                    case "h3" -> 24; // 12pt
                    case "h4" -> 22; // 11pt
                    case "h5" -> 20; // 10pt
                    case "h6" -> 18; // 9pt
                    default -> 22;
                };
                hpsMeasure.setVal(java.math.BigInteger.valueOf(size));
                rPr.setSz(hpsMeasure);
                rPr.setSzCs(hpsMeasure);
            }
        }

        paragraph.getContent().add(run);
        mainDocumentPart.getContent().add(paragraph);
    }

    /**
     * 从CSS样式字符串中提取指定属性的值
     * @param styleAttr CSS样式字符串，例如 "color: black; text-align: center;"
     * @param property 要提取的属性名，例如 "color"
     * @return 属性值，例如 "black"，如果不存在则返回null
     */
    private String extractCssProperty(String styleAttr, String property) {
        if (StrUtil.isBlank(styleAttr) || StrUtil.isBlank(property)) {
            return null;
        }

        // 分割样式声明
        String[] declarations = styleAttr.split(";");
        for (String declaration : declarations) {
            String[] parts = declaration.split(":", 2);
            if (parts.length == 2) {
                String key = parts[0].trim().toLowerCase();
                String value = parts[1].trim();
                if (key.equals(property.toLowerCase())) {
                    return value;
                }
            }
        }
        return null;
    }

    /**
     * 将CSS颜色值转换为十六进制格式（用于Word）
     * 支持：#rrggbb, rgb(r,g,b), 颜色名称
     * @param cssColor CSS颜色值
     * @return 十六进制颜色（不带#），例如 "000000"，如果无法解析则返回null
     */
    private String convertColorToHex(String cssColor) {
        if (StrUtil.isBlank(cssColor)) {
            return null;
        }

        cssColor = cssColor.trim().toLowerCase();

        // 已经是十六进制格式
        if (cssColor.startsWith("#")) {
            return cssColor.substring(1);
        }

        // rgb/rgba格式
        if (cssColor.startsWith("rgb")) {
            try {
                String rgbValues = cssColor.substring(cssColor.indexOf('(') + 1, cssColor.indexOf(')'));
                String[] parts = rgbValues.split(",");
                int r = Integer.parseInt(parts[0].trim());
                int g = Integer.parseInt(parts[1].trim());
                int b = Integer.parseInt(parts[2].trim());
                return String.format("%02X%02X%02X", r, g, b);
            } catch (Exception e) {
                log.warn("无法解析RGB颜色: {}", cssColor);
                return null;
            }
        }

        // 颜色名称映射
        return switch (cssColor) {
            case "black" -> "000000";
            case "white" -> "FFFFFF";
            case "red" -> "FF0000";
            case "green" -> "008000";
            case "blue" -> "0000FF";
            case "yellow" -> "FFFF00";
            case "cyan" -> "00FFFF";
            case "magenta" -> "FF00FF";
            case "gray", "grey" -> "808080";
            case "silver" -> "C0C0C0";
            case "maroon" -> "800000";
            case "olive" -> "808000";
            case "lime" -> "00FF00";
            case "aqua" -> "00FFFF";
            case "teal" -> "008080";
            case "navy" -> "000080";
            case "fuchsia" -> "FF00FF";
            case "purple" -> "800080";
            default -> null;
        };
    }

    /**
     * 处理表格
     * 使用 docx4j 的 Table 和 Tbl API 创建 Word 表格
     */
    private void processTable(MainDocumentPart mainDocumentPart, Element tableElement) throws Exception {
        Elements rows = tableElement.select("tr");
        if (rows.isEmpty()) {
            return;
        }

        try {
            ObjectFactory factory = new ObjectFactory();
            Tbl tbl = factory.createTbl();

            // 设置表格属性
            TblPr tblPr = factory.createTblPr();
            tbl.setTblPr(tblPr);

            // 处理每一行
            for (Element row : rows) {
                Elements cells = row.select("td, th");
                Tr tr = factory.createTr();

                for (Element cell : cells) {
                    Tc tc = factory.createTc();
                    TcPr tcPr = factory.createTcPr();
                    tc.setTcPr(tcPr);

                    // 添加单元格内容
                    P cellParagraph = factory.createP();
                    R cellRun = factory.createR();
                    Text cellText = factory.createText();
                    cellText.setValue(cell.text());
                    cellRun.getContent().add(cellText);
                    cellParagraph.getContent().add(cellRun);
                    tc.getContent().add(cellParagraph);

                    tr.getContent().add(tc);
                }

                tbl.getContent().add(tr);
            }

            // 将表格添加到文档
            mainDocumentPart.getContent().add(tbl);

        } catch (Exception e) {
            log.warn("表格处理失败，跳过表格内容", e);
            // 降级处理：将表格内容作为文本添加
            for (Element row : rows) {
                Elements cells = row.select("td, th");
                StringBuilder rowText = new StringBuilder();
                for (Element cell : cells) {
                    rowText.append(cell.text()).append(" | ");
                }
                mainDocumentPart.addParagraphOfText(rowText.toString());
            }
        }
    }

}
