package com.moka.gdtauto.util;

import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;

/**
 * 视频水印工具类
 * 用于在视频左上角添加文字水印（如剧名）
 * 使用JavaCV + FFmpeg实现
 *
 * @author moka
 */
@Slf4j
public class VideoWatermarkUtil {

    /**
     * 在视频左上角添加文字水印（全程）
     *
     * @param inputVideoPath  输入视频路径
     * @param outputVideoPath 输出视频路径
     * @param watermarkText   水印文字（如：《绝世龙王》）
     * @throws Exception 处理异常
     */
    public static void addWatermark(String inputVideoPath, String outputVideoPath, String watermarkText) throws Exception {
        addWatermark(inputVideoPath, outputVideoPath, watermarkText, null, 40, 50, 50);
    }

    /**
     * 在视频左上角添加文字水印（支持指定前N秒）
     *
     * @param inputVideoPath    输入视频路径
     * @param outputVideoPath   输出视频路径
     * @param watermarkText     水印文字（如：《绝世龙王》）
     * @param watermarkDuration 水印时长(秒)，null表示全程
     * @throws Exception 处理异常
     */
    public static void addWatermark(String inputVideoPath, String outputVideoPath, 
                                   String watermarkText, Integer watermarkDuration) throws Exception {
        addWatermark(inputVideoPath, outputVideoPath, watermarkText, watermarkDuration, 40, 50, 50);
    }

    /**
     * 在视频左上角添加文字水印（可自定义位置和字体大小、时长）
     *
     * @param inputVideoPath    输入视频路径
     * @param outputVideoPath   输出视频路径
     * @param watermarkText     水印文字（如：《绝世龙王》）
     * @param watermarkDuration 水印时长(秒)，null表示全程
     * @param fontSize          字体大小
     * @param x                 水印X坐标（从左边距）
     * @param y                 水印Y坐标（从顶部距）
     * @throws Exception 处理异常
     */
    public static void addWatermark(String inputVideoPath, String outputVideoPath,
                                   String watermarkText, Integer watermarkDuration,
                                   int fontSize, int x, int y) throws Exception {
        log.info("开始为视频添加水印, 输入路径: {}, 输出路径: {}, 水印文字: {}", inputVideoPath, outputVideoPath, watermarkText);

        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;
        Java2DFrameConverter converter = new Java2DFrameConverter();

        try {
            // 创建视频抓取器
            grabber = new FFmpegFrameGrabber(inputVideoPath);
            grabber.start();

            // 获取视频信息
            int videoWidth = grabber.getImageWidth();
            int videoHeight = grabber.getImageHeight();
            double frameRate = grabber.getFrameRate();
            int audioBitrate = grabber.getAudioBitrate();
            int videoBitrate = grabber.getVideoBitrate();
            String videoCodecName = grabber.getVideoCodec() != 0 ? "h264" : "h264";
            String audioCodecName = grabber.getAudioCodec() != 0 ? "aac" : "aac";

            log.info("视频信息 - 分辨率: {}x{}, 帧率: {}, 视频码率: {}, 音频码率: {}",
                    videoWidth, videoHeight, frameRate, videoBitrate, audioBitrate);

            // 创建输出目录
            File outputFile = new File(outputVideoPath);
            File parentDir = outputFile.getParentFile();
            if (parentDir != null && !parentDir.exists()) {
                parentDir.mkdirs();
            }

            // 创建视频录制器
            recorder = new FFmpegFrameRecorder(outputVideoPath, videoWidth, videoHeight, grabber.getAudioChannels());
            recorder.setVideoCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_H264);
            recorder.setFormat("mp4");
            recorder.setFrameRate(frameRate);
            recorder.setVideoBitrate(videoBitrate > 0 ? videoBitrate : 2000000);
            
            if (grabber.getAudioChannels() > 0) {
                recorder.setAudioCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_AAC);
                recorder.setAudioBitrate(audioBitrate > 0 ? audioBitrate : 128000);
                recorder.setSampleRate(grabber.getSampleRate());
            }

            recorder.start();

            // 计算水印结束帧数（如果指定了水印时长）
            Integer watermarkEndFrame = null;
            if (watermarkDuration != null && watermarkDuration > 0) {
                watermarkEndFrame = (int) (watermarkDuration * frameRate);
                log.info("水印将在前 {} 秒（{}帧）显示", watermarkDuration, watermarkEndFrame);
            }

            // 处理每一帧
            Frame frame;
            int frameCount = 0;
            int imageFrameCount = 0;
            while ((frame = grabber.grab()) != null) {
                // 如果是图像帧，判断是否添加水印
                if (frame.image != null) {
                    imageFrameCount++;
                    BufferedImage bufferedImage = converter.convert(frame);
                    if (bufferedImage != null) {
                        // 如果在水印时长范围内（或全程显示），添加水印
                        boolean shouldAddWatermark = (watermarkEndFrame == null) || (imageFrameCount <= watermarkEndFrame);
                        if (shouldAddWatermark) {
                            addTextWatermark(bufferedImage, watermarkText, fontSize, x, y);
                        }
                        frame = converter.convert(bufferedImage);
                    }
                    frameCount++;
                    if (frameCount % 100 == 0) {
                        log.info("已处理 {} 帧", frameCount);
                    }
                }
                
                // 录制帧（包括音频帧）
                recorder.record(frame);
            }

            log.info("视频水印添加成功，总共处理 {} 帧，保存到: {}", frameCount, outputVideoPath);

        } finally {
            // 释放资源
            if (grabber != null) {
                try {
                    grabber.stop();
                    grabber.release();
                } catch (Exception e) {
                    log.error("关闭grabber失败", e);
                }
            }
            if (recorder != null) {
                try {
                    recorder.stop();
                    recorder.release();
                } catch (Exception e) {
                    log.error("关闭recorder失败", e);
                }
            }
            converter.close();
        }
    }

    /**
     * 在BufferedImage上添加文字水印
     */
    private static void addTextWatermark(BufferedImage image, String text, int fontSize, int x, int y) {
        Graphics2D g2d = image.createGraphics();

        // 设置抗锯齿
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        // 设置字体
        Font font = new Font("Microsoft YaHei", Font.BOLD, fontSize);
        g2d.setFont(font);

        // 绘制黑色描边
        g2d.setColor(new Color(0, 0, 0, 180));
        for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
                g2d.drawString(text, x + i, y + j);
            }
        }

        // 绘制白色文字
        g2d.setColor(new Color(255, 255, 255, 230));
        g2d.drawString(text, x, y);

        g2d.dispose();
    }

    /**
     * 提取视频第一帧作为预览图
     *
     * @param videoPath 视频路径
     * @param imagePath 输出图片路径
     * @throws Exception 处理异常
     */
    public static void extractFirstFrame(String videoPath, String imagePath) throws Exception {
        FFmpegFrameGrabber grabber = null;
        Java2DFrameConverter converter = new Java2DFrameConverter();

        try {
            grabber = new FFmpegFrameGrabber(videoPath);
            grabber.start();

            Frame frame = grabber.grabImage();
            if (frame != null) {
                BufferedImage image = converter.convert(frame);
                if (image != null) {
                    File outputFile = new File(imagePath);
                    File parentDir = outputFile.getParentFile();
                    if (parentDir != null && !parentDir.exists()) {
                        parentDir.mkdirs();
                    }

                    String format = imagePath.endsWith(".png") ? "png" : "jpg";
                    ImageIO.write(image, format, outputFile);
                    log.info("成功提取视频第一帧: {}", imagePath);
                }
            }
        } finally {
            if (grabber != null) {
                try {
                    grabber.stop();
                    grabber.release();
                } catch (Exception e) {
                    log.error("关闭grabber失败", e);
                }
            }
            converter.close();
        }
    }
}
