package com.ycwl.basic.image.watermark.operator;

import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
import com.ycwl.basic.image.watermark.exception.ImageWatermarkException;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

@Slf4j
public class PrinterDefaultWatermarkOperator implements IOperator {
    private static final String FONT_PATH = "/PingFang_SC_t.ttf";
    public static String defaultFontName;
    public static float FONT_GLOBAL_OFFSET_PERCENT = 0;
    static {
        try {
            // 加载字体文件流
            InputStream fontStream = PrinterDefaultWatermarkOperator.class.getResourceAsStream(FONT_PATH);
            if (fontStream == null) {
                throw new RuntimeException("字体文件未找到！路径：" + FONT_PATH);
            }

            // 创建字体对象
            Font customFont = Font.createFont(Font.TRUETYPE_FONT, fontStream);

            // 注册字体到系统
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            ge.registerFont(customFont);

            // 更新默认字体名称为新字体的逻辑名称
            defaultFontName = customFont.getName(); // 如 "PingFang SC"
            FONT_GLOBAL_OFFSET_PERCENT = -0.3f;
        } catch (FontFormatException | IOException e) {
            log.error("加载字体文件失败", e);
            defaultFontName = "宋体";
        }
    }
    public static int EXTRA_BORDER_PX = 0;
    public static int OFFSET_Y = 15;
    public static Color BG_COLOR = Color.WHITE;
    public static int QRCODE_SIZE = 150;
    public static double QRCODE_LEFT_MARGIN_RATIO = 0.05;  // 二维码距离左边缘的图片宽度比例
    public static int QRCODE_OFFSET_Y = -35;

    public static int SCENIC_FONT_SIZE = 42;
    public static Color scenicColor = Color.white;
    public static int DATETIME_FONT_SIZE = 42;
    public static Color datetimeColor = Color.white;
    public static double TEXT_RIGHT_MARGIN_RATIO = 0.05;  // 文字距离右边缘的图片宽度比例

    // 默认四边偏移值(像素),当 WatermarkInfo 中未提供时使用
    public static int DEFAULT_OFFSET_TOP = 0;
    public static int DEFAULT_OFFSET_BOTTOM = 0;
    public static int DEFAULT_OFFSET_LEFT = 0;
    public static int DEFAULT_OFFSET_RIGHT = 0;

    @Override
    public File process(WatermarkInfo info) throws ImageWatermarkException {
        // 获取缩放倍数,默认为1.0(不缩放)
        double scale = info.getScale() != null ? info.getScale() : 1.0;

        // 获取四边偏移值,优先使用传入的值,否则使用默认值,并应用缩放
        int offsetTop = (int) ((info.getOffsetTop() != null ? info.getOffsetTop() : DEFAULT_OFFSET_TOP) * scale);
        int offsetBottom = (int) ((info.getOffsetBottom() != null ? info.getOffsetBottom() : DEFAULT_OFFSET_BOTTOM) * scale);
        int offsetLeft = (int) ((info.getOffsetLeft() != null ? info.getOffsetLeft() : DEFAULT_OFFSET_LEFT) * scale);
        int offsetRight = (int) ((info.getOffsetRight() != null ? info.getOffsetRight() : DEFAULT_OFFSET_RIGHT) * scale);

        BufferedImage baseImage;
        BufferedImage qrcodeImage;
        BufferedImage faceImage = null;
        try {
            baseImage = ImageIO.read(info.getOriginalFile());
            qrcodeImage = ImageIO.read(info.getQrcodeFile());
            if (info.getFaceFile() != null && info.getFaceFile().isFile()) {
                try {
                    faceImage = ImageIO.read(info.getFaceFile());
                } catch (IOException e) {
                    log.warn("头像文件读取失败", e);
                }
            }
        } catch (IOException e) {
            throw new ImageWatermarkException("图片打开失败");
        }

        // 应用缩放到所有常量
        int scaledExtraBorder = (int) (EXTRA_BORDER_PX * scale);
        int scaledOffsetY = (int) (OFFSET_Y * scale);
        int scaledQrcodeSize = (int) (QRCODE_SIZE * scale);
        int scaledQrcodeOffsetY = (int) (QRCODE_OFFSET_Y * scale);
        int scaledScenicFontSize = (int) (SCENIC_FONT_SIZE * scale);
        int scaledDatetimeFontSize = (int) (DATETIME_FONT_SIZE * scale);

        // 新图像画布
        BufferedImage newImage = new BufferedImage(baseImage.getWidth() + 2 * scaledExtraBorder, baseImage.getHeight() + 2 * scaledExtraBorder, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = newImage.createGraphics();
        g2d.setColor(BG_COLOR);
        g2d.fillRect(0, 0, newImage.getWidth(), newImage.getHeight());
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.drawImage(baseImage, scaledExtraBorder, scaledExtraBorder, null);
        int newQrcodeHeight = scaledQrcodeSize;
        int newQrcodeWidth = (int) (newQrcodeHeight * 1.0 / qrcodeImage.getHeight() * qrcodeImage.getWidth());
        Font scenicFont = new Font(defaultFontName, Font.BOLD, scaledScenicFontSize);
        Font datetimeFont = new Font(defaultFontName, Font.BOLD, scaledDatetimeFontSize);
        FontMetrics scenicFontMetrics = g2d.getFontMetrics(scenicFont);
        FontMetrics datetimeFontMetrics = g2d.getFontMetrics(datetimeFont);
        int scenicLineHeight = scenicFontMetrics.getHeight();
        int dtLineHeight = datetimeFontMetrics.getHeight();
        int scenicLineWidth = scenicFontMetrics.stringWidth(info.getScenicLine());
        int datetimeLineWidth = datetimeFontMetrics.stringWidth(info.getDatetimeLine());

        // 二维码放置在左下角，距离左边缘图片宽度的5%，再加上左侧偏移
        int qrcodeOffsetX = (int) (newImage.getWidth() * QRCODE_LEFT_MARGIN_RATIO) + offsetLeft;
        int qrcodeOffsetY = scaledExtraBorder + baseImage.getHeight() - scaledOffsetY - newQrcodeHeight - offsetBottom;
        Shape originalClip = g2d.getClip();

        // 创建比二维码大10像素的白色圆形背景（10像素也要缩放）
        int whiteCirclePadding = (int) (10 * scale);
        int whiteCircleSize = Math.max(newQrcodeWidth, newQrcodeHeight) + whiteCirclePadding;
        int whiteCircleX = qrcodeOffsetX - (whiteCircleSize - newQrcodeWidth) / 2;
        int whiteCircleY = qrcodeOffsetY + scaledQrcodeOffsetY - (whiteCircleSize - newQrcodeHeight) / 2;

        // 绘制白色圆形背景
        g2d.setColor(Color.WHITE);
        Ellipse2D whiteCircle = new Ellipse2D.Double(whiteCircleX, whiteCircleY, whiteCircleSize, whiteCircleSize);
        g2d.fill(whiteCircle);

        // 用白色圆形尺寸裁切二维码(保持二维码原始尺寸,但用大圆裁切)
        Ellipse2D qrcodeCircle = new Ellipse2D.Double(whiteCircleX, whiteCircleY, whiteCircleSize, whiteCircleSize);
        g2d.setClip(qrcodeCircle);
        g2d.drawImage(qrcodeImage, qrcodeOffsetX, qrcodeOffsetY + scaledQrcodeOffsetY, newQrcodeWidth, newQrcodeHeight, null);
        g2d.setClip(originalClip);

        // 在圆形二维码中央绘制圆形头像
        if (faceImage != null) {
            // 计算圆形头像的尺寸和位置
            int avatarDiameter = (int) (newQrcodeHeight * 0.45);
            int avatarX = qrcodeOffsetX + (newQrcodeWidth - avatarDiameter) / 2;
            int avatarY = qrcodeOffsetY + scaledQrcodeOffsetY + (newQrcodeHeight - avatarDiameter) / 2;

            // 保存当前的渲染设置
            RenderingHints originalHints = g2d.getRenderingHints();

            // 设置高质量渲染
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            // 创建圆形剪切区域
            Ellipse2D avatarCircle = new Ellipse2D.Double(avatarX, avatarY, avatarDiameter, avatarDiameter);
            g2d.setClip(avatarCircle);

            // 实现CSS cover效果的缩放逻辑
            double faceWidth = faceImage.getWidth();
            double faceHeight = faceImage.getHeight();
            double scaleX = avatarDiameter / faceWidth;
            double scaleY = avatarDiameter / faceHeight;
            double faceScale = Math.max(scaleX, scaleY); // 使用较大的缩放比例以填满圆形

            int scaledWidth = (int) (faceWidth * faceScale);
            int scaledHeight = (int) (faceHeight * faceScale);

            // 计算居中位置
            int faceDrawX = avatarX + (avatarDiameter - scaledWidth) / 2;
            int faceDrawY = avatarY + (avatarDiameter - scaledHeight) / 2;

            // 绘制缩放后的头像
            g2d.drawImage(faceImage, faceDrawX, faceDrawY, scaledWidth, scaledHeight, null);

            // 恢复原始设置
            g2d.setClip(originalClip);
            g2d.setRenderingHints(originalHints);
        }

        // 计算文字与二维码垂直居中对齐的Y坐标
        int qrcodeTop = qrcodeOffsetY + scaledQrcodeOffsetY;
        int qrcodeBottom = qrcodeTop + newQrcodeHeight;
        int qrcodeCenter = (qrcodeTop + qrcodeBottom) / 2;

        // 两行文字的总高度
        int totalTextHeight = scenicLineHeight + dtLineHeight;

        // 计算第一行文字的Y坐标（基线位置），使两行文字整体垂直居中于二维码
        int textStartY = qrcodeCenter - totalTextHeight / 2 + scenicFontMetrics.getAscent();

        // 文字右对齐，放置在右下角，距离右边缘图片宽度的5%，再减去右侧偏移
        int textRightX = newImage.getWidth() - (int) (newImage.getWidth() * TEXT_RIGHT_MARGIN_RATIO) - offsetRight;

        g2d.setFont(scenicFont);
        g2d.setColor(scenicColor);
        g2d.drawString(info.getScenicLine(), textRightX - scenicLineWidth, textStartY);

        g2d.setFont(datetimeFont);
        g2d.setColor(datetimeColor);
        g2d.drawString(info.getDatetimeLine(), textRightX - datetimeLineWidth, textStartY + scenicLineHeight);

        String fileName = info.getWatermarkedFile().getName();
        String formatName = "jpg"; // 默认格式为 jpg
        if (fileName.endsWith(".png")) {
            formatName = "png";
        } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
            formatName = "jpg";
        }
        ImageWriter writer = ImageIO.getImageWritersByFormatName(formatName).next();
        ImageOutputStream ios;
        try {
            ios = ImageIO.createImageOutputStream(info.getWatermarkedFile());
        } catch (IOException e) {
            throw new ImageWatermarkException("图片保存失败，目标文件无法写入");
        }
        writer.setOutput(ios);
        try {
            // 使用 ImageWriter 设置写入质量
            ImageWriteParam writeParam = writer.getDefaultWriteParam();
            if (writeParam.canWriteCompressed()) {
                writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                writeParam.setCompressionQuality(0.75f); // 设置写入质量为 75%
            }
            writer.write(null, new javax.imageio.IIOImage(newImage, null, null), writeParam);
        } catch (IOException e) {
            throw new ImageWatermarkException("图片保存失败");
        }
        finally {
            g2d.dispose();
            try {
                ios.close();
            } catch (IOException ignore) {
            }
            writer.dispose();
        }
        return info.getWatermarkedFile();
    }
}
