package com.bcxin.backend.domain.utils;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
import com.spire.pdf.FileFormat;
import com.spire.pdf.PdfDocument;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.ofdrw.tool.merge.OFDMerger;
import org.springframework.util.StringUtils;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;


/**
 * PDF文件转OFD文件工具类
 *
 * @author
 * @date 2024/3/29 15:27
 * @describe
 */
public class PDFToOFDUtil {


    /**
     * 测试方法
     *
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {

        // 记录程序开始时间（以纳秒为单位）
        long startTime = System.nanoTime();


        //1.源pfd文件
        String inputFilePath = "D:\\data\\queueId_32.pdf";

        //2.源pfd文件分隔成按页文件合集
        List<String> listPfd = splitPDFByPageCount(inputFilePath, 3);

        //3.PDF文件合集转换为OFD文件合集
        List<String> listOfd = new ArrayList<>();
        for (String s : listPfd) {
            String replace = s.replace("pdf", "ofd");
            //用的冰蓝免费的jar包，pdf每次转换带图片可转前3页，纯文本可转前10页，所以我们每次转换按照情况实现最大化就行。
            transPdfToOfd(s, replace);
            listOfd.add(replace);
        }

        //4.OFD文件合集合并一个完整版ofd文件(最终实现源pfd转ofd)
        String outputFilePathOfd = inputFilePath.replace("pdf", "ofd");
        mergeOfdFiles(listOfd, outputFilePathOfd);
        System.out.println("完整版ofd文件路径：" + outputFilePathOfd);

        //5.删除多余文件
        listPfd.addAll(listOfd);
        for (String relFilePath : listPfd) {
            Files.deleteIfExists(Paths.get(relFilePath));
        }



        long endTime = System.nanoTime();
        double durationInSeconds = (endTime - startTime) / 1_000_000_000.0;
        // 输出运行时间
        System.out.println("程序运行时间: " + durationInSeconds + " 秒");

    }


    /**
     * @Description pdf文档 转 ofd文档
     * @date 2024/3/29 15:27
     * @Param pdfPath pdf文件全路径
     * @Param ofdPath ofd 输出全路径
     **/
    public static void transPdfToOfd(String pdfPath, String ofdPath) {
        if (StringUtils.isEmpty(ofdPath) || StringUtils.isEmpty(pdfPath)) {
            throw new RuntimeException("pdf或ofd文档地址不能为空");
        }

        byte[] bytes = getBytesFromFile(new File(pdfPath));
        transPdfToOfd(bytes, ofdPath);
    }

    /**
     * @Description pdf byte数组转ofd文档输出
     * @date 2024/3/29 15:27
     * @Param pdfBytes 字节数组
     * @Param ofdPath ofd文档输出全路径
     **/
    public static void transPdfToOfd(byte[] pdfBytes, String ofdPath) {
        if (pdfBytes == null || pdfBytes.length <= 0) {

            throw new RuntimeException("pdf转ofd转化失败，pdf文件错误，pdf文件内容不能为空");
        }

        if (StringUtils.isEmpty(ofdPath)) {
            throw new RuntimeException("ofd文档输出地址不能为空");
        }

        long startTime = LocalDateTime.now().atOffset(ZoneOffset.of("+8")).toInstant().toEpochMilli();
        //构建PDF内容
        PdfDocument pdf = new PdfDocument();
        pdf.loadFromBytes(pdfBytes);

        pdf.saveToFile(ofdPath, FileFormat.OFD);

        long endTime = LocalDateTime.now().atOffset(ZoneOffset.of("+8")).toInstant().toEpochMilli();
    }

    /**
     * @return byte[]
     * @Description 把一个文件转化为byte字节数组
     * @date 2024/3/29 15:27
     * @Param file 文件
     **/
    public static byte[] getBytesFromFile(File file) {
        byte[] data;
        try (InputStream inputStream = Files.newInputStream(file.toPath());
             BufferedInputStream bis = new BufferedInputStream(inputStream);
             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            int len;
            byte[] buffer = new byte[1024];
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }

            data = bos.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return data;
    }


    /**
     * 使用iTextPDF合并PDF文件
     *
     * @param pdfFiles  要合并的PDF文件路径
     * @param mergedPdf 合并后的PDF文件路径
     * @throws IOException
     * @throws DocumentException
     */
    public static void mergePdfFiles(List<String> pdfFiles, String mergedPdf) throws IOException, DocumentException {
        Document document = new Document();
        PdfCopy copy = new PdfCopy(document, new FileOutputStream(mergedPdf));
        document.open();
        PdfReader reader;
        for (String file : pdfFiles) {
            reader = new PdfReader(file);
            int n = reader.getNumberOfPages();
            for (int page = 0; page < n; ) {
                copy.addPage(copy.getImportedPage(reader, ++page));
            }
            copy.freeReader(reader);
            reader.close();
        }
        document.close();
    }


    /**
     * OFD合并
     *
     * @param ofdFiles
     * @param mergeOfd
     * @throws IOException
     * @throws DocumentException
     */
    public static void mergeOfdFiles(List<String> ofdFiles, String mergeOfd) {
        // 1. 提供合并文件输出位置。
        Path dst = Paths.get(mergeOfd);
        // 3. 创建合并对象
        try (OFDMerger ofdMerger = new OFDMerger(dst)) {
            for (String ofdFile : ofdFiles) {
                Path d1Path = Paths.get(ofdFile);
                // 4. 添加合并文档和页面。
                ofdMerger.add(d1Path);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 将 PDF 文件按指定页数分隔，并保存到与输入文件同级的输出目录中。
     *
     * @param inputFilePath 输入 PDF 文件的路径
     * @param pagesPerFile  每个 PDF 文件包含的页数比如3页为一个文件
     * @return 分隔后的 PDF 文件路径列表
     */
    public static List<String> splitPDFByPageCount(String inputFilePath, int pagesPerFile) {
        // PDF 文件路径列表
        List<String> listPdf = new ArrayList<>();
        try {
            // 加载 PDF 文件
            File inputFile = new File(inputFilePath);
            PDDocument document = PDDocument.load(inputFile);

            // 获取输入文件的父目录
            String outputDirPath = inputFile.getParent();

            // 创建输出目录
            File outputDir = new File(outputDirPath);
            if (!outputDir.exists()) {
                outputDir.mkdirs();
            }

            // 获取总页数
            int totalPages = document.getNumberOfPages();

            // 计算文件数量
            int numFiles = (int) Math.ceil((double) totalPages / pagesPerFile);

            // 遍历每个文件
            for (int fileIndex = 0; fileIndex < numFiles; fileIndex++) {
                PDDocument singleFileDoc = new PDDocument();

                // 计算每个文件的起始页和结束页
                int startPage = fileIndex * pagesPerFile;
                int endPage = Math.min(startPage + pagesPerFile, totalPages);

                // 添加页到当前文档
                for (int pageIndex = startPage; pageIndex < endPage; pageIndex++) {
                    PDPage page = document.getPage(pageIndex);
                    singleFileDoc.addPage(page);
                }

                // 保存分隔出的 PDF 文件
                String outputFileName = outputDirPath + "/output-part-" + (fileIndex + 1) + ".pdf";
                singleFileDoc.save(outputFileName);
                singleFileDoc.close();
                listPdf.add(outputFileName);
            }

            // 关闭原始文档
            document.close();

            System.out.println("PDF 按页数分隔完成，文件已保存到：" + outputDirPath);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return listPdf;
    }


}

