package shop.alien.util.pdf;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * 图片转PDF工具类
 * 支持单张图片转PDF、多张图片合并为一个PDF
 * 支持从本地文件、URL、字节数组转换
 *
 * @author system
 * @since 2026-01-05
 */
public class ImageToPdfUtil {

    /**
     * 将单张图片文件转换为PDF
     *
     * @param imagePath 图片文件路径
     * @param pdfPath   PDF文件保存路径
     * @return 是否转换成功
     */
    public static boolean imageToPdf(String imagePath, String pdfPath) {
        return imageToPdf(new File(imagePath), new File(pdfPath));
    }

    /**
     * 将单张图片文件转换为PDF
     *
     * @param imageFile 图片文件
     * @param pdfFile   PDF文件
     * @return 是否转换成功
     */
    public static boolean imageToPdf(File imageFile, File pdfFile) {
        if (imageFile == null || !imageFile.exists()) {
            throw new IllegalArgumentException("图片文件不存在: " + (imageFile != null ? imageFile.getPath() : "null"));
        }

        try (InputStream imageStream = new FileInputStream(imageFile)) {
            return imageToPdf(imageStream, pdfFile);
        } catch (IOException e) {
            throw new RuntimeException("读取图片文件失败: " + imageFile.getPath(), e);
        }
    }

    /**
     * 将图片输入流转换为PDF
     *
     * @param imageStream 图片输入流
     * @param pdfFile     PDF文件
     * @return 是否转换成功
     */
    public static boolean imageToPdf(InputStream imageStream, File pdfFile) {
        if (imageStream == null) {
            throw new IllegalArgumentException("图片输入流不能为空");
        }
        if (pdfFile == null) {
            throw new IllegalArgumentException("PDF文件不能为空");
        }

        // 确保PDF文件目录存在
        File parentDir = pdfFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        try (PDDocument document = new PDDocument()) {
            BufferedImage bufferedImage = ImageIO.read(imageStream);
            if (bufferedImage == null) {
                throw new IllegalArgumentException("无法读取图片，可能不是有效的图片格式");
            }

            // 创建PDF页面，使用图片的尺寸
            PDPage page = new PDPage(new PDRectangle(bufferedImage.getWidth(), bufferedImage.getHeight()));
            document.addPage(page);

            // 将图片添加到PDF页面
            PDImageXObject pdImage = PDImageXObject.createFromByteArray(
                    document, imageToByteArray(bufferedImage), "image");

            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                contentStream.drawImage(pdImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());
            }

            document.save(pdfFile);
            return true;
        } catch (IOException e) {
            throw new RuntimeException("图片转PDF失败", e);
        }
    }

    /**
     * 将图片URL转换为PDF
     *
     * @param imageUrl 图片URL
     * @param pdfPath  PDF文件保存路径
     * @return 是否转换成功
     */
    public static boolean imageUrlToPdf(String imageUrl, String pdfPath) {
        return imageUrlToPdf(imageUrl, new File(pdfPath));
    }

    /**
     * 将图片URL转换为PDF
     *
     * @param imageUrl 图片URL
     * @param pdfFile  PDF文件
     * @return 是否转换成功
     */
    public static boolean imageUrlToPdf(String imageUrl, File pdfFile) {
        if (imageUrl == null || imageUrl.trim().isEmpty()) {
            throw new IllegalArgumentException("图片URL不能为空");
        }

        HttpURLConnection connection = null;
        try {
            URL url = new URL(imageUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(10000); // 10秒连接超时
            connection.setReadTimeout(30000);    // 30秒读取超时
            connection.setRequestMethod("GET");
            connection.setRequestProperty("User-Agent", "Mozilla/5.0");

            InputStream imageStream = connection.getInputStream();
            try {
                return imageToPdf(imageStream, pdfFile);
            } finally {
                if (imageStream != null) {
                    imageStream.close();
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("从URL下载图片失败: " + imageUrl, e);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    /**
     * 将图片字节数组转换为PDF
     *
     * @param imageBytes 图片字节数组
     * @param pdfPath    PDF文件保存路径
     * @return 是否转换成功
     */
    public static boolean imageBytesToPdf(byte[] imageBytes, String pdfPath) {
        return imageBytesToPdf(imageBytes, new File(pdfPath));
    }

    /**
     * 将图片字节数组转换为PDF
     *
     * @param imageBytes 图片字节数组
     * @param pdfFile    PDF文件
     * @return 是否转换成功
     */
    public static boolean imageBytesToPdf(byte[] imageBytes, File pdfFile) {
        if (imageBytes == null || imageBytes.length == 0) {
            throw new IllegalArgumentException("图片字节数组不能为空");
        }

        ByteArrayInputStream imageStream = new ByteArrayInputStream(imageBytes);
        try {
            return imageToPdf(imageStream, pdfFile);
        } finally {
            try {
                imageStream.close();
            } catch (IOException e) {
                // ByteArrayInputStream的close()实际上不会抛出异常，但为了编译通过需要捕获
            }
        }
    }

    /**
     * 将多张图片合并为一个PDF
     *
     * @param imagePaths 图片文件路径列表
     * @param pdfPath    PDF文件保存路径
     * @return 是否转换成功
     */
    public static boolean imagesToPdf(List<String> imagePaths, String pdfPath) {
        return imagesToPdfFromPaths(imagePaths, new File(pdfPath));
    }

    /**
     * 将多张图片合并为一个PDF（从文件路径）
     *
     * @param imagePaths 图片文件路径列表
     * @param pdfFile    PDF文件
     * @return 是否转换成功
     */
    public static boolean imagesToPdfFromPaths(List<String> imagePaths, File pdfFile) {
        if (imagePaths == null || imagePaths.isEmpty()) {
            throw new IllegalArgumentException("图片路径列表不能为空");
        }

        List<File> imageFiles = new ArrayList<>();
        for (String imagePath : imagePaths) {
            imageFiles.add(new File(imagePath));
        }
        return imagesToPdfFromFiles(imageFiles, pdfFile);
    }

    /**
     * 将多张图片合并为一个PDF（从文件对象）
     *
     * @param imageFiles 图片文件列表
     * @param pdfFile    PDF文件
     * @return 是否转换成功
     */
    public static boolean imagesToPdfFromFiles(List<File> imageFiles, File pdfFile) {
        if (imageFiles == null || imageFiles.isEmpty()) {
            throw new IllegalArgumentException("图片文件列表不能为空");
        }
        if (pdfFile == null) {
            throw new IllegalArgumentException("PDF文件不能为空");
        }

        // 确保PDF文件目录存在
        File parentDir = pdfFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        try (PDDocument document = new PDDocument()) {
            for (File imageFile : imageFiles) {
                if (imageFile == null || !imageFile.exists()) {
                    continue; // 跳过不存在的文件
                }

                try (FileInputStream imageStream = new FileInputStream(imageFile)) {
                    BufferedImage bufferedImage = ImageIO.read(imageStream);
                    if (bufferedImage == null) {
                        continue; // 跳过无法读取的图片
                    }

                    // 创建PDF页面，使用图片的尺寸
                    PDPage page = new PDPage(new PDRectangle(bufferedImage.getWidth(), bufferedImage.getHeight()));
                    document.addPage(page);

                    // 将图片添加到PDF页面
                    PDImageXObject pdImage = PDImageXObject.createFromByteArray(
                            document, imageToByteArray(bufferedImage), "image");

                    try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                        contentStream.drawImage(pdImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());
                    }
                } catch (IOException e) {
                    // 记录错误但继续处理其他图片
                    System.err.println("处理图片失败: " + imageFile.getPath() + ", 错误: " + e.getMessage());
                }
            }

            if (document.getNumberOfPages() == 0) {
                throw new RuntimeException("没有成功添加任何图片到PDF");
            }

            document.save(pdfFile);
            return true;
        } catch (IOException e) {
            throw new RuntimeException("多张图片转PDF失败", e);
        }
    }

    /**
     * 将多张图片URL合并为一个PDF
     *
     * @param imageUrls 图片URL列表
     * @param pdfPath   PDF文件保存路径
     * @return 是否转换成功
     */
    public static boolean imageUrlsToPdf(List<String> imageUrls, String pdfPath) {
        return imageUrlsToPdf(imageUrls, new File(pdfPath));
    }

    /**
     * 将多张图片URL合并为一个PDF
     *
     * @param imageUrls 图片URL列表
     * @param pdfFile   PDF文件
     * @return 是否转换成功
     */
    public static boolean imageUrlsToPdf(List<String> imageUrls, File pdfFile) {
        if (imageUrls == null || imageUrls.isEmpty()) {
            throw new IllegalArgumentException("图片URL列表不能为空");
        }

        // 确保PDF文件目录存在
        File parentDir = pdfFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        try (PDDocument document = new PDDocument()) {
            for (String imageUrl : imageUrls) {
                if (imageUrl == null || imageUrl.trim().isEmpty()) {
                    continue; // 跳过空的URL
                }

                try {
                    URL url = new URL(imageUrl);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setConnectTimeout(10000);
                    connection.setReadTimeout(30000);
                    connection.setRequestMethod("GET");
                    connection.setRequestProperty("User-Agent", "Mozilla/5.0");

                    InputStream imageStream = connection.getInputStream();
                    try {
                        BufferedImage bufferedImage = ImageIO.read(imageStream);
                        if (bufferedImage == null) {
                            continue; // 跳过无法读取的图片
                        }

                        // 创建PDF页面，使用图片的尺寸
                        PDPage page = new PDPage(new PDRectangle(bufferedImage.getWidth(), bufferedImage.getHeight()));
                        document.addPage(page);

                        // 将图片添加到PDF页面
                        PDImageXObject pdImage = PDImageXObject.createFromByteArray(
                                document, imageToByteArray(bufferedImage), "image");

                        try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                            contentStream.drawImage(pdImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());
                        }
                    } finally {
                        if (imageStream != null) {
                            imageStream.close();
                        }
                    }
                } catch (IOException e) {
                    // 记录错误但继续处理其他图片
                    System.err.println("处理图片URL失败: " + imageUrl + ", 错误: " + e.getMessage());
                }
            }

            if (document.getNumberOfPages() == 0) {
                throw new RuntimeException("没有成功添加任何图片到PDF");
            }

            document.save(pdfFile);
            return true;
        } catch (IOException e) {
            throw new RuntimeException("多张图片URL转PDF失败", e);
        }
    }

    /**
     * 将图片转换为字节数组
     *
     * @param bufferedImage 图片对象
     * @return 图片字节数组
     */
    private static byte[] imageToByteArray(BufferedImage bufferedImage) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        String format = "png"; // 默认使用PNG格式
        ImageIO.write(bufferedImage, format, baos);
        return baos.toByteArray();
    }

    /**
     * 将图片输入流转换为PDF字节数组（内存方式，不保存文件）
     *
     * @param imageStream 图片输入流
     * @return PDF字节数组
     */
    public static byte[] imageToPdfBytes(InputStream imageStream) {
        if (imageStream == null) {
            throw new IllegalArgumentException("图片输入流不能为空");
        }

        try (PDDocument document = new PDDocument();
             ByteArrayOutputStream pdfOutputStream = new ByteArrayOutputStream()) {
            BufferedImage bufferedImage = ImageIO.read(imageStream);
            if (bufferedImage == null) {
                throw new IllegalArgumentException("无法读取图片，可能不是有效的图片格式");
            }

            // 创建PDF页面，使用图片的尺寸
            PDPage page = new PDPage(new PDRectangle(bufferedImage.getWidth(), bufferedImage.getHeight()));
            document.addPage(page);

            // 将图片添加到PDF页面
            PDImageXObject pdImage = PDImageXObject.createFromByteArray(
                    document, imageToByteArray(bufferedImage), "image");

            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                contentStream.drawImage(pdImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());
            }

            // 将PDF保存到字节数组
            document.save(pdfOutputStream);
            return pdfOutputStream.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("图片转PDF失败", e);
        }
    }

    /**
     * 将图片输入流转换为PDF字节数组（A4页面大小，内存方式）
     *
     * @param imageStream 图片输入流
     * @return PDF字节数组
     */
    public static byte[] imageToPdfA4Bytes(InputStream imageStream) {
        if (imageStream == null) {
            throw new IllegalArgumentException("图片输入流不能为空");
        }

        try (PDDocument document = new PDDocument();
             ByteArrayOutputStream pdfOutputStream = new ByteArrayOutputStream()) {
            BufferedImage bufferedImage = ImageIO.read(imageStream);
            if (bufferedImage == null) {
                throw new IllegalArgumentException("无法读取图片，可能不是有效的图片格式");
            }

            // 创建A4页面
            PDPage page = new PDPage(PDRectangle.A4);
            document.addPage(page);

            // 计算图片在A4页面上的尺寸（保持宽高比）
            float pageWidth = PDRectangle.A4.getWidth();
            float pageHeight = PDRectangle.A4.getHeight();
            float imageWidth = bufferedImage.getWidth();
            float imageHeight = bufferedImage.getHeight();

            // 计算缩放比例，使图片适应A4页面
            float scaleX = pageWidth / imageWidth;
            float scaleY = pageHeight / imageHeight;
            float scale = Math.min(scaleX, scaleY);

            float scaledWidth = imageWidth * scale;
            float scaledHeight = imageHeight * scale;

            // 居中显示
            float x = (pageWidth - scaledWidth) / 2;
            float y = (pageHeight - scaledHeight) / 2;

            // 将图片添加到PDF页面
            PDImageXObject pdImage = PDImageXObject.createFromByteArray(
                    document, imageToByteArray(bufferedImage), "image");

            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                contentStream.drawImage(pdImage, x, y, scaledWidth, scaledHeight);
            }

            // 将PDF保存到字节数组
            document.save(pdfOutputStream);
            return pdfOutputStream.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("图片转PDF失败", e);
        }
    }

    /**
     * 将单张图片转换为PDF（A4页面大小，图片自适应）
     *
     * @param imagePath 图片文件路径
     * @param pdfPath   PDF文件保存路径
     * @return 是否转换成功
     */
    public static boolean imageToPdfA4(String imagePath, String pdfPath) {
        return imageToPdfA4(new File(imagePath), new File(pdfPath));
    }

    /**
     * 将单张图片转换为PDF（A4页面大小，图片自适应）
     *
     * @param imageFile 图片文件
     * @param pdfFile   PDF文件
     * @return 是否转换成功
     */
    public static boolean imageToPdfA4(File imageFile, File pdfFile) {
        if (imageFile == null || !imageFile.exists()) {
            throw new IllegalArgumentException("图片文件不存在: " + (imageFile != null ? imageFile.getPath() : "null"));
        }

        // 确保PDF文件目录存在
        File parentDir = pdfFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        try (PDDocument document = new PDDocument()) {
            BufferedImage bufferedImage = ImageIO.read(imageFile);
            if (bufferedImage == null) {
                throw new IllegalArgumentException("无法读取图片，可能不是有效的图片格式");
            }

            // 创建A4页面
            PDPage page = new PDPage(PDRectangle.A4);
            document.addPage(page);

            // 计算图片在A4页面上的尺寸（保持宽高比）
            float pageWidth = PDRectangle.A4.getWidth();
            float pageHeight = PDRectangle.A4.getHeight();
            float imageWidth = bufferedImage.getWidth();
            float imageHeight = bufferedImage.getHeight();

            // 计算缩放比例，使图片适应A4页面
            float scaleX = pageWidth / imageWidth;
            float scaleY = pageHeight / imageHeight;
            float scale = Math.min(scaleX, scaleY);

            float scaledWidth = imageWidth * scale;
            float scaledHeight = imageHeight * scale;

            // 居中显示
            float x = (pageWidth - scaledWidth) / 2;
            float y = (pageHeight - scaledHeight) / 2;

            // 将图片添加到PDF页面
            PDImageXObject pdImage = PDImageXObject.createFromByteArray(
                    document, imageToByteArray(bufferedImage), "image");

            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                contentStream.drawImage(pdImage, x, y, scaledWidth, scaledHeight);
            }

            document.save(pdfFile);
            return true;
        } catch (IOException e) {
            throw new RuntimeException("图片转PDF失败", e);
        }
    }

    /**
     * 将多张图片合并为一个PDF（A4页面大小，每张图片一页，图片自适应）
     *
     * @param imageFiles 图片文件列表
     * @param pdfFile    PDF文件
     * @return 是否转换成功
     */
    public static boolean imagesToPdfA4(List<File> imageFiles, File pdfFile) {
        if (imageFiles == null || imageFiles.isEmpty()) {
            throw new IllegalArgumentException("图片文件列表不能为空");
        }
        if (pdfFile == null) {
            throw new IllegalArgumentException("PDF文件不能为空");
        }

        // 确保PDF文件目录存在
        File parentDir = pdfFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        try (PDDocument document = new PDDocument()) {
            float pageWidth = PDRectangle.A4.getWidth();
            float pageHeight = PDRectangle.A4.getHeight();

            for (File imageFile : imageFiles) {
                if (imageFile == null || !imageFile.exists()) {
                    continue; // 跳过不存在的文件
                }

                try (FileInputStream imageStream = new FileInputStream(imageFile)) {
                    BufferedImage bufferedImage = ImageIO.read(imageStream);
                    if (bufferedImage == null) {
                        continue; // 跳过无法读取的图片
                    }

                    // 创建A4页面
                    PDPage page = new PDPage(PDRectangle.A4);
                    document.addPage(page);

                    // 计算图片在A4页面上的尺寸（保持宽高比）
                    float imageWidth = bufferedImage.getWidth();
                    float imageHeight = bufferedImage.getHeight();

                    // 计算缩放比例，使图片适应A4页面
                    float scaleX = pageWidth / imageWidth;
                    float scaleY = pageHeight / imageHeight;
                    float scale = Math.min(scaleX, scaleY);

                    float scaledWidth = imageWidth * scale;
                    float scaledHeight = imageHeight * scale;

                    // 居中显示
                    float x = (pageWidth - scaledWidth) / 2;
                    float y = (pageHeight - scaledHeight) / 2;

                    // 将图片添加到PDF页面
                    PDImageXObject pdImage = PDImageXObject.createFromByteArray(
                            document, imageToByteArray(bufferedImage), "image");

                    try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                        contentStream.drawImage(pdImage, x, y, scaledWidth, scaledHeight);
                    }
                } catch (IOException e) {
                    // 记录错误但继续处理其他图片
                    System.err.println("处理图片失败: " + imageFile.getPath() + ", 错误: " + e.getMessage());
                }
            }

            if (document.getNumberOfPages() == 0) {
                throw new RuntimeException("没有成功添加任何图片到PDF");
            }

            document.save(pdfFile);
            return true;
        } catch (IOException e) {
            throw new RuntimeException("多张图片转PDF失败", e);
        }
    }

    /**
     * 将多张图片输入流合并为一个PDF字节数组（内存方式，不保存文件）
     *
     * @param imageStreams 图片输入流列表
     * @return PDF字节数组
     */
    public static byte[] imagesToPdfBytes(List<InputStream> imageStreams) {
        if (imageStreams == null || imageStreams.isEmpty()) {
            throw new IllegalArgumentException("图片输入流列表不能为空");
        }

        try (PDDocument document = new PDDocument();
             ByteArrayOutputStream pdfOutputStream = new ByteArrayOutputStream()) {
            
            for (InputStream imageStream : imageStreams) {
                if (imageStream == null) {
                    continue; // 跳过空的输入流
                }

                try {
                    BufferedImage bufferedImage = ImageIO.read(imageStream);
                    if (bufferedImage == null) {
                        continue; // 跳过无法读取的图片
                    }

                    // 创建PDF页面，使用图片的尺寸
                    PDPage page = new PDPage(new PDRectangle(bufferedImage.getWidth(), bufferedImage.getHeight()));
                    document.addPage(page);

                    // 将图片添加到PDF页面
                    PDImageXObject pdImage = PDImageXObject.createFromByteArray(
                            document, imageToByteArray(bufferedImage), "image");

                    try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                        contentStream.drawImage(pdImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());
                    }
                } catch (IOException e) {
                    // 记录错误但继续处理其他图片
                    System.err.println("处理图片输入流失败: " + e.getMessage());
                } finally {
                    // 关闭输入流
                    if (imageStream != null) {
                        try {
                            imageStream.close();
                        } catch (IOException e) {
                            // 忽略关闭异常
                        }
                    }
                }
            }

            if (document.getNumberOfPages() == 0) {
                throw new RuntimeException("没有成功添加任何图片到PDF");
            }

            // 将PDF保存到字节数组
            document.save(pdfOutputStream);
            return pdfOutputStream.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("多张图片转PDF失败", e);
        }
    }
}
