package com.qingyun.service.utils;

import cn.hutool.http.HttpUtil;
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import com.qingyun.common.config.QingYunConfig;
import com.qingyun.common.utils.file.FileUploadUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Component
public class PdfUtil {

    @Value("${server.port}")
    private String port;

    /**
     * @param source      原文件
     * @param desFilePath 生成图片的路径
     * @param desFileName 生成图片的名称（多页文档时会变成：名称+下划线+从1开始的数字）
     * @return
     */
    public Pair<Boolean, Object> pdfToImage(File source, String desFilePath, String desFileName) throws IOException {
        //通过给定的源路径名字符串创建一个File实例

        if (!source.exists()) {
            return Pair.of(false, "文件不存在，无法转化");
        }
        //目录不存在则创建目录
        File destination = new File(desFilePath);
        if (!destination.exists()) {
            boolean flag = destination.mkdirs();
            System.out.println("创建文件夹结果：" + flag);
        }
        PDDocument doc = null;
        try {
            //加载PDF文件
            doc = Loader.loadPDF(source);
            PDFRenderer renderer = new PDFRenderer(doc);
            //获取PDF文档的页数
            int pageCount = doc.getNumberOfPages();
            System.out.println("文档一共" + pageCount + "页");
            List<Object> fileList = new ArrayList<>();
            for (int i = 0; i < pageCount; i++) {
                // 只有一页的时候文件名为传入的文件名，大于一页的文件名为：文件名_自增加数字(从1开始)
                String realFileName = pageCount > 1 ? desFileName + "_" + (i + 1) : desFileName;
                // 每一页通过分辨率和颜色值进行转化
                BufferedImage bufferedImage = renderer.renderImageWithDPI(i, 150, ImageType.RGB);
                String relativePath = FileUploadUtils.getPathFileName(QingYunConfig.getUploadPath() + "/" + desFilePath, realFileName + "." + "png");
                String filePath = QingYunConfig.getUploadPath() + "/" + desFilePath + "/" + realFileName + "." + "png";
                // 确保目录存在
                File imageFile = new File(filePath);
                if (!imageFile.getParentFile().exists()) {
                    boolean mkdirs = imageFile.getParentFile().mkdirs(); // 创建父目录
                    if (!mkdirs) {
                        return Pair.of(false, "无法创建目录：" + imageFile.getParentFile().getAbsolutePath());
                    }
                }
                // 写入文件
                ImageIO.write(bufferedImage, "png", imageFile);

                // 文件名存入 list
                fileList.add(relativePath);
            }
            return Pair.of(true, fileList);
        } catch (IOException e) {
            e.printStackTrace();
            return Pair.of(false, "PDF转化图片异常");
        } finally {
            try {
                if (doc != null) {
                    doc.close();
                }
            } catch (IOException e) {
                System.out.println("关闭文档失败");
                e.printStackTrace();
            }
        }
    }

    public File downloadFile(String pdfUrl, String name) throws IOException {
        // name 去掉文件后缀
        String newName = name.substring(0, name.lastIndexOf("."));
        String projectUrl = QingYunConfig.getProjectUrl();
        File tempFile = File.createTempFile(newName + System.currentTimeMillis(), getFileExtension(name));
        long file = HttpUtil.downloadFile(projectUrl +  pdfUrl, tempFile);
        if (file <= 0) {
            throw new IOException("无法下载 PDF 文件");
        }
        return tempFile;
    }

    public File convertWordToPdf(File wordFile) throws IOException, InterruptedException {
        if (!wordFile.exists() || !wordFile.isFile()) {
            throw new IOException("Word文件不存在或无效: " + wordFile.getAbsolutePath());
        }

        String osName = System.getProperty("os.name").toLowerCase();

        if (osName.contains("win")) {
            // Windows 系统使用 Apache POI 实现 Word 转 PDF
            return convertWordToPdfWindows(wordFile);
        } else {
            // Linux 或其他系统使用 LibreOffice 实现 Word 转 PDF
            return convertWordToPdfLinux(wordFile);
        }
    }

    private File convertWordToPdfWindows(File wordFile) throws IOException {
        File outputFile = new File(wordFile.getParent(),
            FilenameUtils.getBaseName(wordFile.getName()) + ".pdf");

        try {
            IConverter converter = LocalConverter.builder().build();

            Future<Boolean> conversion = converter
                .convert(wordFile).as(DocumentType.MS_WORD)
                .to(outputFile).as(DocumentType.PDF)
                .prioritizeWith(1000) // optional
                .schedule();
            conversion.get(); // 这里会阻塞直到转换完成
            return outputFile;

        } catch (Exception e) {
            throw new IOException("Word 转 PDF 失败: " + e.getMessage(), e);
        }
    }

    private File convertWordToPdfLinux(File wordFile) throws IOException, InterruptedException {
        // 保留现有的 Linux 实现逻辑
        if (!isLibreOfficeInstalled()) {
            throw new IOException("LibreOffice未安装! 请先执行: sudo apt-get install libreoffice");
        }

        File outputDir = wordFile.getParentFile();
        String pdfName = FilenameUtils.getBaseName(wordFile.getName()) + ".pdf";
        File outputFile = new File(outputDir, pdfName);

        ProcessBuilder pb = new ProcessBuilder(
            "/usr/bin/soffice",
            "--headless",
            "--convert-to", "pdf",
            "--outdir", outputDir.getAbsolutePath(),
            wordFile.getAbsolutePath()
        );

        pb.redirectErrorStream(true);
        pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);

        Process process = pb.start();
        boolean completed = process.waitFor(5, TimeUnit.MINUTES);

        if (!completed) {
            process.destroyForcibly();
            throw new IOException("转换超时（5分钟）");
        }

        if (process.exitValue() != 0) {
            throw new IOException("LibreOffice转换失败，错误码: " + process.exitValue());
        }

        if (!outputFile.exists() || outputFile.length() == 0) {
            throw new IOException("PDF文件未生成或为空");
        }

        return outputFile;
    }

    private boolean isLibreOfficeInstalled() {
        try {
            Process p = Runtime.getRuntime().exec("which soffice");
            return p.waitFor(2, TimeUnit.SECONDS) && p.exitValue() == 0;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取文件扩展名
     * @param fileName 文件名
     * @return 文件扩展名（包括点号）
     */
    private String getFileExtension(String fileName) {
        if (fileName == null || fileName.lastIndexOf('.') == -1) {
            return ""; // 没有扩展名
        }
        return fileName.substring(fileName.lastIndexOf('.'));
    }
}

