package com.usky.cdi.service.sip.ps;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * FFmpeg H264→PS remux 会话：后台读 stdout，按 Pack 边界切帧。
 */
@Slf4j
public final class FfmpegPsRemuxSession implements AutoCloseable {

    private static final int READ_BUF = 256 * 1024;

    private final FfmpegPsRemuxer remuxer;
    private final PsStreamFramer framer = new PsStreamFramer();
    private final LinkedBlockingQueue<byte[]> packQueue = new LinkedBlockingQueue<>();
    private final Thread readerThread;
    private volatile boolean running = true;
    private volatile String readerError;

    public FfmpegPsRemuxSession(double frameRate) throws IOException {
        remuxer = new FfmpegPsRemuxer(frameRate);
        readerThread = new Thread(this::readLoop, "ffmpeg-ps-read");
        readerThread.setDaemon(true);
        readerThread.start();
    }

    public void submitAccessUnit(byte[] annexB) throws IOException {
        remuxer.writeAccessUnit(annexB);
    }

    public boolean isAlive() {
        return remuxer.isAlive() && readerError == null;
    }

    /**
     * 等待 remux 产出的完整 PS Pack（可能 0~N 个）。
     */
    public List<byte[]> pollPacks(long timeoutMs) throws InterruptedException {
        List<byte[]> packs = new ArrayList<>();
        byte[] first = packQueue.poll(timeoutMs, TimeUnit.MILLISECONDS);
        if (first != null) {
            packs.add(first);
            packQueue.drainTo(packs);
        }
        return packs;
    }

    private void readLoop() {
        byte[] buf = new byte[READ_BUF];
        try {
            InputStream in = remuxer.psOutput();
            while (running) {
                int n = in.read(buf);
                if (n < 0) {
                    break;
                }
                if (n > 0) {
                    for (byte[] pack : framer.feed(buf, 0, n)) {
                        packQueue.offer(pack);
                    }
                }
            }
            for (byte[] pack : framer.flush()) {
                packQueue.offer(pack);
            }
        } catch (IOException e) {
            if (running) {
                readerError = e.getMessage();
                log.warn("FFmpeg PS 读取异常: {}", e.getMessage());
            }
        }
    }

    @Override
    public void close() {
        running = false;
        remuxer.close();
        try {
            readerThread.join(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        packQueue.clear();
    }

    public String getReaderError() {
        return readerError;
    }

    public List<byte[]> drainAll() {
        List<byte[]> packs = new ArrayList<>();
        packQueue.drainTo(packs);
        return packs.isEmpty() ? Collections.emptyList() : packs;
    }
}
