package com.yaoyicloud.tools;

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import com.yaoyicloud.config.FilerepoProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.IBodyElement;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPicture;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture;

import com.deepoove.poi.xwpf.XWPFStructuredDocumentTag;
import org.springframework.stereotype.Component;

@Component
@Slf4j
@RequiredArgsConstructor
public final class DocxUtil {
    private final FilerepoProperties filerepoProperties;

    /**
     *
     * @return 获取图片文件夹路径
     */
    private String imagePath() {
        return filerepoProperties.getReportImagePath();
    }

    /**
     *
     * @return 获取文档转换时所需字体列表
     */
    private List<String> getFontPaths() {
        return Arrays.asList(
            filerepoProperties.getSourceHanSansCnFontMediumPath());
    }

    private String getReportImagePath() {
        return filerepoProperties.getReportImagePath();
    }

    /**
     * 将Word文件转换为PDF文件
     * 
     * @param reportTempWordFile 待转换的Word文件路径（.docx格式）
     * @return 转换后最终的PDF文件路径
     * @throws Exception 转换过程中发生的异常（如文件操作、格式转换错误等）
     */
    public String wordToPdf(String reportTempWordFile) throws Exception {
        String imagePath = this.imagePath();
        String reportImagePath = this.getReportImagePath();
        // 第一步：将Word文件转换为HTML字符串，同时提取图片到reportImagePath
        // （OfficeUtil.convert内部实现Word到HTML的转换，包含文本、图片等元素的解析）
        String html = OfficeUtil.convert(reportTempWordFile, reportImagePath);
        try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("1.html"))) {
            writer2.write(html);
        } catch (IOException e) {
            System.err.println("写入 1.html 文件时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
        // 第二步：对原始HTML进行格式化处理（如修复标签、调整样式等，确保后续PDF转换兼容）
        String html1 = OfficeUtil.formatHtml(html);
        try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("2.html"))) {
            writer2.write(html1);
        } catch (IOException e) {
            System.err.println("写入 2.html 文件时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
        // 生成PDF文件路径：与原Word文件同目录、同名，仅替换扩展名为.pdf
        String reportBastPath = reportTempWordFile.replace(".docx", ".pdf");

        // 第三步：使用格式化后的html1生成PDF（可能是带水印或中间状态的PDF）
        // （getFontPaths()获取字体路径列表，确保PDF中文字正常显示；flag为true表示首次转换，处理目录）
        OfficeUtil.convertHtmlToPdf(html1, reportBastPath, getFontPaths(), imagePath, true);

        // 再次对原始HTML进行格式化
        String html2 = OfficeUtil.formatHtml(html);
        try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("3.html"))) {
            writer2.write(html2);
        } catch (IOException e) {
            System.err.println("写入 3.html 文件时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
        // 第四步：使用第二次格式化后的html2生成最终PDF（flag为false可能表示最终转换，
        String pdfPath = OfficeUtil.convertHtmlToPdf(html2, reportBastPath, getFontPaths(), imagePath, false);
        log.info("文档转换成功，文档路径为：" + pdfPath);
        return pdfPath;
    }

    public static void mergeDocx(XWPFDocument target, List<XWPFDocument> sources, String outputPath, Long relationId)
        throws InvalidFormatException, FileNotFoundException, IOException {
        mergeDocx(target, sources, outputPath, false);

    }

    public static void mergeDocx(XWPFDocument target, List<XWPFDocument> sources, String outputPath,
        boolean clearTargetBody) throws InvalidFormatException, FileNotFoundException, IOException {
        if (clearTargetBody) {
            target.getDocument().unsetBody();
            target.getDocument().addNewBody();
        }

        // 2. 处理每个源文档的样式并合并
        for (int i = 0; i < sources.size(); i++) {
            XWPFDocument source = sources.get(i);

            // 合并内容
            appendSourceContent(target, source);
        }
        try (FileOutputStream out = new FileOutputStream(outputPath)) {
            target.write(out);
            target.close();
        }
        log.info("文档合并成功，文档路径为：{}", outputPath);
    }

    private static void appendSourceContent(XWPFDocument target, XWPFDocument source) throws InvalidFormatException {
        if (!target.getBodyElements().isEmpty()) {
            insertPageBreak(target);
        }
        for (IBodyElement element : source.getBodyElements()) {
            if (element instanceof XWPFParagraph) {
                appendParagraph(target, (XWPFParagraph) element);
            } else if (element instanceof XWPFTable) {
                appendTable(target, (XWPFTable) element);
            } else if (element instanceof XWPFStructuredDocumentTag) {
                // todo: 目录，自定义标签等
                continue;
            }
        }

    }

    private static void appendTable(XWPFDocument target, XWPFTable oldTable) {
        XWPFTable newTable = target.createTable();
        newTable.getCTTbl().set(oldTable.getCTTbl().copy());
        // 更新表格样式引用
        String styleId = oldTable.getStyleID();
        if (styleId != null) {
            newTable.setStyleID(styleId);
        }
    }

    private static void appendParagraph(XWPFDocument target, XWPFParagraph oldParagraph) throws InvalidFormatException {
        // Remove additional blank page
        // if (i == doc1.getBodyElements().size() - 1
        // && oldParagraph.isPageBreak()
        // && StrUtil.isBlank(oldParagraph.getText())) {
        // continue;
        // }

        // Copy Picture
        for (int i = 0; i < oldParagraph.getRuns().size(); i++) {
            XWPFRun oldRun = oldParagraph.getRuns().get(i);

            // Check if the run has embedded images
            List<XWPFPicture> pictures = oldRun.getEmbeddedPictures();
            for (int j = 0; j < pictures.size(); j++) {
                XWPFPictureData picData = pictures.get(j).getPictureData();

                // copy picture
                // String fileName = picData.getFileName();
                String newRelationId = target.addPictureData(picData.getData(), picData.getPictureType());

                // update image rId to the new run
                // 注意这里用新文件的rId更新了旧文件的Run，然后复制旧文件的XML到新文件
                // 如果直接编辑新文件需要在复制XML后重新生成XWPFParagraph对象，才能正确反映更新的XML数据
                CTPicture ctPic = pictures.get(j).getCTPicture();
                CTBlipFillProperties bill = ctPic.getBlipFill();
                CTBlip blip = bill.getBlip();
                blip.setEmbed(newRelationId);
            }
        }
        // Copy Xml content
        XWPFParagraph newParagraph = target.createParagraph();
        newParagraph.getCTP().set(oldParagraph.getCTP().copy());
        // 更新段落样式引用
        String styleId = oldParagraph.getStyleID();
        if (styleId != null) {
            newParagraph.setStyle(styleId);
        }
    }

    // 新增：插入分页符的方法
    private static void insertPageBreak(XWPFDocument target) {
        XWPFParagraph paragraph = target.createParagraph();
        XWPFRun run = paragraph.createRun();
        run.addBreak(org.apache.poi.xwpf.usermodel.BreakType.PAGE); // 添加分页符
    }
}
