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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 从 FFmpeg mpegps 输出流中按 Pack Header(0x000001BA) 切分完整 PS 包。
 */
public final class PsStreamFramer {

    private byte[] buffer = new byte[0];

    public List<byte[]> feed(byte[] chunk, int offset, int length) {
        if (length <= 0) {
            return Collections.emptyList();
        }
        buffer = concat(buffer, chunk, offset, length);
        return extractCompletePacks(false);
    }

    public List<byte[]> flush() {
        if (buffer.length < 4) {
            buffer = new byte[0];
            return Collections.emptyList();
        }
        return extractCompletePacks(true);
    }

    private List<byte[]> extractCompletePacks(boolean flushRemainder) {
        List<Integer> starts = findPackStarts(buffer);
        List<byte[]> packs = new ArrayList<>();
        if (starts.size() >= 2) {
            for (int i = 0; i < starts.size() - 1; i++) {
                packs.add(Arrays.copyOfRange(buffer, starts.get(i), starts.get(i + 1)));
            }
            buffer = Arrays.copyOfRange(buffer, starts.get(starts.size() - 1), buffer.length);
        }
        if (flushRemainder && buffer.length >= 14 && isPackStart(buffer, 0)) {
            packs.add(buffer);
            buffer = new byte[0];
        }
        return packs;
    }

    private static List<Integer> findPackStarts(byte[] data) {
        List<Integer> starts = new ArrayList<>();
        for (int i = 0; i <= data.length - 4; i++) {
            if (isPackStart(data, i)) {
                if (starts.isEmpty() || starts.get(starts.size() - 1) != i) {
                    starts.add(i);
                }
            }
        }
        return starts;
    }

    private static boolean isPackStart(byte[] data, int offset) {
        return offset + 3 < data.length
                && data[offset] == 0x00
                && data[offset + 1] == 0x00
                && data[offset + 2] == 0x01
                && (data[offset + 3] & 0xFF) == 0xBA;
    }

    private static byte[] concat(byte[] left, byte[] right, int offset, int length) {
        byte[] merged = new byte[left.length + length];
        System.arraycopy(left, 0, merged, 0, left.length);
        System.arraycopy(right, offset, merged, left.length, length);
        return merged;
    }
}
