package pkg

import (
	"bytes"
	_ "embed"
	"math/rand"
	"testing"

	"github.com/langhuihui/gomem"
	"m7s.live/v5/pkg/codec"
)

func bytesFromMemory(m gomem.Memory) []byte {
	if m.Size == 0 {
		return nil
	}
	out := make([]byte, 0, m.Size)
	for _, b := range m.Buffers {
		out = append(out, b...)
	}
	return out
}

func TestAnnexBReader_ReadNALU_Basic(t *testing.T) {

	var reader AnnexBReader

	// 3 个 NALU，分别使用 4 字节、3 字节、4 字节起始码
	expected1 := []byte{0x67, 0x42, 0x00, 0x1E}
	expected2 := []byte{0x68, 0xCE, 0x3C, 0x80}
	expected3 := []byte{0x65, 0x88, 0x84, 0x00}

	buf := append([]byte{0x00, 0x00, 0x00, 0x01}, expected1...)
	buf = append(buf, append([]byte{0x00, 0x00, 0x01}, expected2...)...)
	buf = append(buf, append([]byte{0x00, 0x00, 0x00, 0x01}, expected3...)...)

	reader.AppendBuffer(append(buf, codec.NALU_Delimiter2[:]...))

	// 读取并校验 3 个 NALU（不包含起始码）
	var n gomem.Memory
	if err := reader.ReadNALU(nil, &n); err != nil {
		t.Fatalf("read nalu 1: %v", err)
	}
	if !bytes.Equal(bytesFromMemory(n), expected1) {
		t.Fatalf("nalu1 mismatch")
	}

	n = gomem.Memory{}
	if err := reader.ReadNALU(nil, &n); err != nil {
		t.Fatalf("read nalu 2: %v", err)
	}
	if !bytes.Equal(bytesFromMemory(n), expected2) {
		t.Fatalf("nalu2 mismatch")
	}

	n = gomem.Memory{}
	if err := reader.ReadNALU(nil, &n); err != nil {
		t.Fatalf("read nalu 3: %v", err)
	}
	if !bytes.Equal(bytesFromMemory(n), expected3) {
		t.Fatalf("nalu3 mismatch")
	}

	// 再读一次应无更多起始码，返回 nil 错误且长度为 0
	if err := reader.ReadNALU(nil, &n); err != nil {
		t.Fatalf("expected nil error when no more nalu, got: %v", err)
	}
	if reader.Length != 4 {
		t.Fatalf("expected length 0 after reading all, got %d", reader.Length)
	}
}

func TestAnnexBReader_AppendBuffer_MultiChunk_Random(t *testing.T) {

	var reader AnnexBReader

	rng := rand.New(rand.NewSource(1)) // 固定种子，保证可复现

	// 生成随机 NALU（仅负载部分），并构造 AnnexB 数据（随机 3/4 字节起始码）
	numNALU := 12
	expectedPayloads := make([][]byte, 0, numNALU)
	fullStream := make([]byte, 0, 1024)

	for i := 0; i < numNALU; i++ {
		payloadLen := 1 + rng.Intn(32)
		payload := make([]byte, payloadLen)
		for j := 0; j < payloadLen; j++ {
			payload[j] = byte(rng.Intn(256))
		}
		expectedPayloads = append(expectedPayloads, payload)

		if rng.Intn(2) == 0 {
			fullStream = append(fullStream, 0x00, 0x00, 0x01)
		} else {
			fullStream = append(fullStream, 0x00, 0x00, 0x00, 0x01)
		}
		fullStream = append(fullStream, payload...)
	}
	fullStream = append(fullStream, codec.NALU_Delimiter2[:]...) // 结尾加个起始码，方便读取到最后一个 NALU
	// 随机切割为多段并 AppendBuffer
	for i := 0; i < len(fullStream); {
		// 每段长度 1..7 字节（或剩余长度）
		maxStep := 7
		remain := len(fullStream) - i
		step := 1 + rng.Intn(maxStep)
		if step > remain {
			step = remain
		}
		reader.AppendBuffer(fullStream[i : i+step])
		i += step
	}

	// 依次读取并校验
	for idx, expected := range expectedPayloads {
		var n gomem.Memory
		if err := reader.ReadNALU(nil, &n); err != nil {
			t.Fatalf("read nalu %d: %v", idx+1, err)
		}
		got := bytesFromMemory(n)
		if !bytes.Equal(got, expected) {
			t.Fatalf("nalu %d mismatch: expected %d bytes, got %d bytes", idx+1, len(expected), len(got))
		}
	}

	// 没有更多 NALU
	var n gomem.Memory
	if err := reader.ReadNALU(nil, &n); err != nil {
		t.Fatalf("expected nil error when no more nalu, got: %v", err)
	}
}

// 起始码跨越两个缓冲区的情况测试（例如 00 00 | 00 01）
func TestAnnexBReader_StartCodeAcrossBuffers(t *testing.T) {
	var reader AnnexBReader
	// 构造一个 4 字节起始码被拆成两段的情况，后跟一个短 payload
	reader.AppendBuffer([]byte{0x00, 0x00})
	reader.AppendBuffer([]byte{0x00})
	reader.AppendBuffer([]byte{0x01, 0x11, 0x22, 0x33}) // payload: 11 22 33
	reader.AppendBuffer(codec.NALU_Delimiter2[:])
	var n gomem.Memory
	if err := reader.ReadNALU(nil, &n); err != nil {
		t.Fatalf("read nalu: %v", err)
	}
	got := bytesFromMemory(n)
	expected := []byte{0x11, 0x22, 0x33}
	if !bytes.Equal(got, expected) {
		t.Fatalf("payload mismatch: expected %v got %v", expected, got)
	}
}

//go:embed test.h264
var annexbH264Sample []byte

var clipSizesH264 = [...]int{7823, 7157, 5137, 6268, 5958, 4573, 5661, 5589, 3917, 5207, 5347, 4111, 4755, 5199, 3761, 5014, 4981, 3736, 5075, 4889, 3739, 4701, 4655, 3471, 4086, 4428, 3309, 4388, 28, 8, 63974, 63976, 37544, 4945, 6525, 6974, 4874, 6317, 6141, 4455, 5833, 4105, 5407, 5479, 3741, 5142, 4939, 3745, 4945, 4857, 3518, 4624, 4930, 3649, 4846, 5020, 3293, 4588, 4571, 3430, 4844, 4822, 21223, 8461, 7188, 4882, 6108, 5870, 4432, 5389, 5466, 3726}

func TestAnnexBReader_EmbeddedAnnexB_H265(t *testing.T) {
	var reader AnnexBReader
	offset := 0
	for _, size := range clipSizesH264 {
		reader.AppendBuffer(annexbH264Sample[offset : offset+size])
		offset += size
		var nalu gomem.Memory
		if err := reader.ReadNALU(nil, &nalu); err != nil {
			t.Fatalf("read nalu: %v", err)
		} else {
			t.Logf("read nalu: %d bytes", nalu.Size)
			if nalu.Size > 0 {
				tryH264Type := codec.ParseH264NALUType(nalu.Buffers[0][0])
				t.Logf("tryH264Type: %d", tryH264Type)
			}
		}
	}
}
