package com.cmvr.edge.client.utils;

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class H265DecoderUtil {
    private static final Logger logger = LoggerFactory.getLogger(H265DecoderUtil.class);
    private static final int PIPE_BUFFER_SIZE = 1024 * 1024; // 1MB 缓冲区
    private static final int GRABBER_TIMEOUT = 500_000; // 500ms 超时

    private static volatile FFmpegFrameGrabber grabber;
    private static volatile PipedInputStream pipedInputStream;
    private static volatile PipedOutputStream pipedOutputStream;
    private static volatile Thread grabberThread;
    private static final AtomicBoolean isDecoderReady = new AtomicBoolean(false);
    private static final Object initLock = new Object();

    static {
        initializeDecoder();
    }

    private static void initializeDecoder() {
        synchronized (initLock) {
            if (isDecoderReady.get()) {
                logger.info("Decoder already initialized");
                return;
            }

            try {
                logger.info("Initializing decoder...");

                // 1. 初始化管道流（增大缓冲区防止阻塞）
                pipedInputStream = new PipedInputStream(PIPE_BUFFER_SIZE);
                pipedOutputStream = new PipedOutputStream(pipedInputStream);

                // 2. 配置 FFmpeg 抓取器
                grabber = new FFmpegFrameGrabber(pipedInputStream);
                grabber.setFormat("hevc");
                grabber.setVideoOption("threads", "4"); // 多线程解码
                grabber.setOption("probesize", "32");    // 减少探测数据量
                grabber.setOption("analyzeduration", "200000"); // 200ms 分析时长
                grabber.setOption("timeout", String.valueOf(GRABBER_TIMEOUT));

                // 3. 启动独立线程运行 FFmpeg
                grabberThread = new Thread(() -> {
                    try {
                        logger.info("Starting FFmpeg grabber...");
                        grabber.startUnsafe();
                        isDecoderReady.set(true);
                        logger.info("FFmpeg grabber started successfully");
                    } catch (FrameGrabber.Exception e) {
                        logger.error("FFmpeg start failed", e);
                        isDecoderReady.set(false);
                    }
                });
                grabberThread.setDaemon(true); // 设为守护线程
                grabberThread.start();

                // 4. 等待初始化完成
                int retry = 0;
                while (!isDecoderReady.get() && retry++ < 5) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }

//                if (!isDecoderReady.get()) {
//                    throw new IllegalStateException("Failed to initialize FFmpeg grabber");
//                }

            } catch (IOException e) {
                logger.error("Decoder initialization failed", e);
                cleanup();
                throw new RuntimeException("H265 decoder init failed", e);
            }
        }
    }

    public static String decodeToBase64Image(byte[] h265Data) {
        if (h265Data == null || h265Data.length == 0) {
            logger.warn("Empty H265 data received");
            return null;
        }

        if (!isDecoderReady.get()) {
            logger.error("Decoder not ready, reinitializing...");
            synchronized (initLock) {
                cleanup();
                initializeDecoder();
            }
            if (!isDecoderReady.get()) {
                return null;
            }
        }

        try {
            // 1. 写入数据（非阻塞）
            pipedOutputStream.write(h265Data);
            pipedOutputStream.flush();

            // 2. 抓取帧（带超时）
            Frame frame = null;
            int retry = 0;
            while (frame == null && retry++ < 3) {
                try {
                    frame = grabber.grab();
                    if (frame == null) {
                        logger.debug("Frame grab timeout, retrying...");
                        Thread.sleep(50);
                    }
                } catch (FrameGrabber.Exception e) {
                    logger.warn("Frame grab error", e);
                    if (e.getMessage().contains("Input/output error")) {
                        resetDecoder();
                    }
                }
            }

            if (frame == null || frame.image == null) {
                logger.warn("Failed to grab valid frame after retries");
                return null;
            }

            // 3. 转换为 Base64
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage image = converter.convert(frame);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", baos);
            return Base64.getEncoder().encodeToString(baos.toByteArray());

        } catch (Exception e) {
            logger.error("Decoding failed", e);
            return null;
        }
    }

    private static void resetDecoder() {
        synchronized (initLock) {
            cleanup();
            initializeDecoder();
        }
    }

    private static void cleanup() {
        try {
            if (grabber != null) {
                grabber.stop();
                grabber.close();
            }
            if (pipedOutputStream != null) {
                pipedOutputStream.close();
            }
            if (pipedInputStream != null) {
                pipedInputStream.close();
            }
            if (grabberThread != null && grabberThread.isAlive()) {
                grabberThread.interrupt();
            }
        } catch (Exception e) {
            logger.warn("Cleanup error", e);
        } finally {
            grabber = null;
            pipedInputStream = null;
            pipedOutputStream = null;
            grabberThread = null;
            isDecoderReady.set(false);
        }
    }

    private static boolean isIFrame(byte[] data) {
        // H.265 NAL 单元类型检测（简化版）
        if (data.length < 4 || data[0] != 0 || data[1] != 0 || data[2] != 1) {
            return false;
        }
        int nalType = (data[3] & 0x7E) >> 1;
        return nalType >= 0x20 && nalType <= 0x23; // VPS/SPS/PPS/IDR
    }


    /**
     * 将H.265帧流转换为MP4视频并编码为Base64
     */
    public static String convertH265FramesToVideo(List<byte[]> frames) {
        try {
            // 1. 合并帧数据
            ByteArrayOutputStream combinedStream = new ByteArrayOutputStream();
            for (byte[] frame : frames) {
                combinedStream.write(frame);
            }
            byte[] h265Data = combinedStream.toByteArray();

            // 2. 开启FFmpeg日志（关键调试步骤）
//            FFmpegLogCallback.set();

            // 3. 创建管道流（线程安全传输）
            PipedInputStream pipedInputStream = new PipedInputStream(2 * 1024 * 1024);
            PipedOutputStream pipedOutputStream = new PipedOutputStream(pipedInputStream);

            // 4. 启动写线程（将H.265数据写入管道）
            Thread writerThread = new Thread(() -> {
                try {
                    pipedOutputStream.write(h265Data);
                    pipedOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            writerThread.start();

            // 5. 初始化抓取器（解析H.265流）
            FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(pipedInputStream);
            grabber.setFormat("hevc"); // 强制指定H.265格式
            grabber.setOption("loglevel","quiet");
            grabber.start();

            // 6. 初始化录制器（输出到临时文件）
            File tempFile = File.createTempFile("temp_video", ".mp4");
            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(tempFile, grabber.getImageWidth(), grabber.getImageHeight());
            recorder.setFormat("mp4"); // 输出MP4格式

            // 关键参数配置（避免默认值失效）
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 使用H.264编码（兼容性更好）
            recorder.setFrameRate(grabber.getFrameRate()); // 匹配输入帧率
            recorder.setVideoBitrate(8000000); // 设置合理比特率（如8Mbps）
            recorder.setGopSize(30); // GOP大小（关键帧间隔）
            recorder.setOption("loglevel","quiet");
            recorder.start(); // 启动录制器

            // 7. 逐帧录制
            Frame frame;
            while ((frame = grabber.grab()) != null) {
                recorder.record(frame);
            }

            // 8. 停止资源
            recorder.stop();
            grabber.stop();

            // 9. 读取临时文件为Base64
            byte[] mp4Data = Files.readAllBytes(tempFile.toPath());
            String base64String = Base64.getEncoder().encodeToString(mp4Data);

            // 10. 清理临时文件
            tempFile.delete();

            return base64String;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}