package com.wmyun.farmwork.word.core;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.FileNameUtil;
import com.wmyun.farmwork.word.core.enums.BookmarkType;
import com.wmyun.farmwork.word.core.enums.PictureProvideNameType;
import com.wmyun.farmwork.word.core.model.AbstractExData;
import com.wmyun.farmwork.word.core.model.BookmarkReplaceDataModel;
import com.wmyun.farmwork.word.core.model.ext.PictureExData;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark;
import org.springframework.stereotype.Component;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description: TODO
 * @Date: 2025/3/3 10:10
 * @Created: by ZZSLL
 */

@Component
@Slf4j
public class BookmarkExec {

    public final static String tmpDir = System.getProperty("java.io.tmpdir") + File.separator;

    public static File replace(List<BookmarkReplaceDataModel> data, byte[] word, File file) {
        Map<String, BookmarkReplaceDataModel> dataMap = data.stream()
                .collect(Collectors.toMap(BookmarkReplaceDataModel::getName, b -> b));
        try (XWPFDocument doc = new XWPFDocument(IoUtil.toStream(word))) {
            // 收集所有段落

            // 1. 正文中的段落
            List<XWPFParagraph> allParagraphs = new ArrayList<>(doc.getParagraphs());

            // 2. 正文中表格内的段落
            for (XWPFTable table : doc.getTables()) {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        allParagraphs.addAll(cell.getParagraphs());
                    }
                }
            }

            // 3. 页眉中的段落及页眉内表格中的段落
            for (XWPFHeader header : doc.getHeaderList()) {
                allParagraphs.addAll(header.getParagraphs());
                for (XWPFTable table : header.getTables()) {
                    for (XWPFTableRow row : table.getRows()) {
                        for (XWPFTableCell cell : row.getTableCells()) {
                            allParagraphs.addAll(cell.getParagraphs());
                        }
                    }
                }
            }

            // 4. 页脚中的段落及页脚内表格中的段落
            for (XWPFFooter footer : doc.getFooterList()) {
                allParagraphs.addAll(footer.getParagraphs());
                for (XWPFTable table : footer.getTables()) {
                    for (XWPFTableRow row : table.getRows()) {
                        for (XWPFTableCell cell : row.getTableCells()) {
                            allParagraphs.addAll(cell.getParagraphs());
                        }
                    }
                }
            }

            for (XWPFParagraph paragraph : allParagraphs) {
                List<XWPFRun> runs = paragraph.getRuns();
                List<CTBookmark> bookmarkStartList = paragraph.getCTP().getBookmarkStartList();
                for (CTBookmark bookmark : bookmarkStartList) {
                    String name = bookmark.getName();
                    if (!dataMap.containsKey(name)) {
                        continue;
                    }
                    XWPFRun run = null;
                    int idx = 0;
                    boolean doR = false;
                    for (int i = 0; i < runs.size(); i++) {
                        Node previousSibling = runs.get(i).getCTR().getDomNode().getPreviousSibling();
                        if (previousSibling != null) {
                            String nodeName = previousSibling.getNodeName();
                            if ("w:bookmarkEnd".equals(nodeName)) {
                                // end前一个是start
                                Node bookmarkStartNode = previousSibling.getPreviousSibling();
                                if (bookmarkStartNode != null) {
                                    Node nameAttribute = bookmarkStartNode.getAttributes().getNamedItem("w:name");
                                    // 获取书签名称，确保同一行内多个书签情况能正确处理
                                    if (nameAttribute != null && name.equals(nameAttribute.getNodeValue())) {
                                        idx = i - 1;
                                        doR = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    if (idx < runs.size() && doR) {
                        if (idx < 0) {// 如果是-1，说明这一段的开头有书签
                            // 在本段开头位置插入新的run
                            run = paragraph.insertNewRun(0);
                            // 并复制原有开头的run的所有内容，后续只修改文本内容，不改变样式
                            run.getCTR().set(runs.get(0).getCTR().copy());
                        } else {
                            run = runs.get(idx);
                        }
                    } else if (!runs.isEmpty()){
                        // 处理一段末尾的书签（一般不存在这种情况）
                        run = runs.get(runs.size() - 1);
                    } else {
                        run = paragraph.createRun();
                    }
                    if (run == null) {
                        continue;
                    }
                    BookmarkReplaceDataModel model = dataMap.get(name);
                    BookmarkType type = model.getType();
                    // 处理文本
                    if (BookmarkType.TEXT.equals(type)) {
                        run.setText(model.getValue());
                    }
                    // 处理图片，以嵌入式插入图片
                    if (BookmarkType.PICTURE.equals(type)) {
                        AbstractExData extData = model.getExtData();
                        if (extData instanceof PictureExData picture && PictureProvideNameType.BOOKMARK.equals(picture.getNameType())) {
                            try {
                                run.addPicture(new ByteArrayInputStream(picture.readAsByteArray()), XWPFDocument.PICTURE_TYPE_PNG, picture.getPictureName(), Units.toEMU(picture.getWidth()), Units.toEMU(picture.getHeight()));
                            } catch (InvalidFormatException e) {
                                log.error(e.getMessage(), e);
                                throw new RuntimeException(e);
                            }
                        }
                    }
                }

                for (XWPFRun run : runs) {
                    List<XWPFPicture> pictures = run.getEmbeddedPictures();
                    for (XWPFPicture picture : pictures) {
                        String description = picture.getDescription();
                        if (dataMap.containsKey(description)) {
                            BookmarkReplaceDataModel model = dataMap.get(description);
                            if (model.getExtData() instanceof PictureExData pic) {
                                String picId = doc.addPictureData(pic.readAsByteArray(), pic.readPictureType());
                                picture.getCTPicture().getBlipFill().getBlip().setEmbed(picId);
                            }
                        }
                    }
                }
            }

            File outFile = FileUtil.newFile(tmpDir + "gen/" + FileNameUtil.getName(file));
            File parentDir = outFile.getParentFile();
            if (!parentDir.exists()) {
                parentDir.mkdirs();
            }
            try (FileOutputStream out = new FileOutputStream(outFile)) {
                doc.write(out);
            }
            return outFile;
        } catch (IOException | InvalidFormatException e) {
            throw new RuntimeException(e);
        }
    }
}
