package com.ruoyi.common.utils;

import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import org.docx4j.TraversalUtil;
import org.docx4j.XmlUtils;
import org.docx4j.dml.CTPositiveSize2D;
import org.docx4j.dml.Graphic;
import org.docx4j.dml.GraphicData;
import org.docx4j.dml.picture.Pic;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.finders.RangeFinder;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;

import javax.xml.bind.JAXBElement;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.*;

/**
 * 给word模板，在需要插入图片(签字)的地方，word中设则书签
 * wordFilePath word 文档路径
 * image 签名BASE64
 * @Author: tjf
 * @Date: 2024/5/15 10:25
 * @Describe:
 */
public class WordUtil {
    public static AjaxResult wordFilePath(String wordFilePath,String image) {
        try {
            // 上传文件路径
            String filePath = RuoYiConfig.getUploadPath();
            if (StringUtils.isNotEmpty(wordFilePath)){
                wordFilePath = wordFilePath.replace("/profile/upload",filePath);
            }
            WordprocessingMLPackage wordMLPackage = load(wordFilePath);

            // 提取正文
            MainDocumentPart main = wordMLPackage.getMainDocumentPart();
            Document doc = null;
            doc = main.getContents();
            Body body = doc.getBody();

            // 获取段落
            List<Object> paragraphs = body.getContent();

            // 提取书签并获取书签的游标
            RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange");
            new TraversalUtil(paragraphs, rt);

            // 遍历书签
            for (CTBookmark bm : rt.getStarts()) {
                System.out.println("name:" + bm.getName());
                // 替换image sign是书签名字
                if ("sign".equals(bm.getName())) {
                    addImage(wordMLPackage, bm, image);
                    break;
                }
            }
            save(wordMLPackage, wordFilePath);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return AjaxResult.success();
    }

    /**
     * @param wPackage 文档
     * @param bm       书签
     * @param base64String    签名图片base64
     * @throws Exception
     */
    public static void addImage(WordprocessingMLPackage wPackage, CTBookmark bm, String base64String) throws Exception {
        P p = (P) (bm.getParent());
        ObjectFactory factory = Context.getWmlObjectFactory();
        R run = factory.createR();

        // 读入图片并转化为字节数组，因为docx4j只能字节数组的方式插入图片
        // byte[] bytes = IOUtils.toByteArray(new FileInputStream("图片文件路径"));
        //byte[] bytes = getFileBytes(image);
        if (base64String.contains("data:")) {
            int start = base64String.indexOf(",");
            base64String = base64String.substring(start + 1);
        }
        base64String = base64String.replaceAll("\r|\n", "");
        base64String = base64String.trim();
        byte[] bytes = Base64.getDecoder().decode(base64String);
        // 开始创建一个行内图片
        BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wPackage, bytes);
        // 最后一个是限制图片的宽度，缩放的依据
        Inline newInline = imagePart.createImageInline(null, null, 0, 1, false, 0);
        // 构建绘图
        Drawing drawing = factory.createDrawing();
        // 加入图片段落
        drawing.getAnchorOrInline().add(newInline);
        run.getContent().add(drawing);
        // 清理书签所在数据
        // p.getContent().clear();
        // 加入图片信息
        p.getContent().add(run);
    }


    /**
     * 处理图片适应大小
     * @param cx
     * @param cy
     * @param newCx
     * @param newCy
     */
    public static Map<String, Long> dealCxy(Long cx, Long cy, Long newCx, Long newCy){
        Map<String, Long> map = new HashMap<>();
        Long setCx;
        Long setCy;

        if (newCx > cx){
            if (newCy <= cy){
                setCx = cx;
                setCy = newCy/(newCx/cx);
            } else {
                if ((newCx/cx) > (newCy/cy)){
                    setCx = cx;
                    setCy = newCy/(newCx/cx);
                } else {
                    setCy = cy;
                    setCx = newCx/(newCy/cy);
                }
            }
        } else {   // newCx < cx
            if (newCy > cy) {
                setCx = cx;
                setCy = newCy * (cx/newCx);
            } else {
                if ((cx/newCx) > (cy/newCy)) {
                    setCx = cx;
                    setCy = newCy *(cx/newCx);
                } else {
                    setCy = cy;
                    setCx = newCy * (cy/newCy);
                }
            }
        }
        map.put("setCx",setCx);
        map.put("setCy",setCy);
        return map;
    }

    /**
     * 得到指定类型的元素
     * @param obj
     * @param toSearch
     * @return
     */
    public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
        List<Object> result = new ArrayList<>();
        if (obj instanceof JAXBElement)
            obj = ((JAXBElement<?>) obj).getValue();
        if (obj.getClass().equals(toSearch))
            result.add(obj);
        else if (obj instanceof ContentAccessor) {
            List<?> children = ((ContentAccessor) obj).getContent();
            for (Object child : children) {
                result.addAll(getAllElementFromObject(child, toSearch));
            }
        }
        return result;
    }
    /**
     * 构建文件
     */
    public static WordprocessingMLPackage build() throws Exception {
        return WordprocessingMLPackage.createPackage();
    }

    /**
     * 读取存在的word文件
     *
     * @param wordFilePath word文件路径
     */
    public static WordprocessingMLPackage load(String wordFilePath) throws Exception {
        return WordprocessingMLPackage.load(new File(wordFilePath));
    }

    /**
     * 保存
     *
     * @param wordMLPackage word
     */
    public static void save(WordprocessingMLPackage wordMLPackage, String wordFilePath) throws Exception {
        wordMLPackage.save(new File(wordFilePath));
    }

    /**
     * 将图片转为Base64数组
     *
     * @param filePath
     * @return
     * @throws Exception
     */
    public static byte[] getFileBytes(String filePath) throws Exception {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new Exception("文件不存在!");
        }

        byte[] data = null;
        try (FileInputStream fis = new FileInputStream(file); ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            int len;
            byte[] buffer = new byte[1024];
            while ((len = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            data = baos.toByteArray();
        }
        return data;
    }
}
