package codec

import (
	"fmt"

	"github.com/deepch/vdk/codec/h264parser"
)

// Start Code + NAL Unit -> NALU Header + NALU Body
// RTP Packet -> NALU Header + NALU Body

// NALU Body -> Slice Header + Slice data
// Slice data -> flags + Macroblock layer1 + Macroblock layer2 + ...
// Macroblock layer1 -> mb_type + PCM Data
// Macroblock layer2 -> mb_type + Sub_mb_pred or mb_pred + Residual Data
// Residual Data ->
type H264NALUType byte

func (b H264NALUType) Or(b2 byte) byte {
	return byte(b) | b2
}

func (b H264NALUType) Offset() int {
	switch b {
	case NALU_STAPA:
		return 1
	case NALU_STAPB:
		return 3
	case NALU_FUA:
		return 2
	case NALU_FUB:
		return 4
	}
	return 0
}

func (b H264NALUType) Byte() byte {
	return byte(b)
}
func ParseH264NALUType(b byte) H264NALUType {
	return H264NALUType(b & 0x1F)
}
func (t *H264NALUType) Parse(b byte) H264NALUType {
	*t = H264NALUType(b & 0x1F)
	return *t
}

func (H264NALUType) ParseBytes(bs []byte) H264NALUType {
	return H264NALUType(bs[0] & 0x1F)
}

const (
	// NALU Type
	NALU_Unspecified           H264NALUType = iota
	NALU_Non_IDR_Picture                    // 1
	NALU_Data_Partition_A                   // 2
	NALU_Data_Partition_B                   // 3
	NALU_Data_Partition_C                   // 4
	NALU_IDR_Picture                        // 5
	NALU_SEI                                // 6
	NALU_SPS                                // 7
	NALU_PPS                                // 8
	NALU_Access_Unit_Delimiter              // 9
	NALU_Sequence_End                       // 10
	NALU_Stream_End                         // 11
	NALU_Filler_Data                        // 12
	NALU_SPS_Extension                      // 13
	NALU_Prefix                             // 14
	NALU_SPS_Subset                         // 15
	NALU_DPS                                // 16
	NALU_Reserved1                          // 17
	NALU_Reserved2                          // 18
	NALU_Not_Auxiliary_Coded                // 19
	NALU_Coded_Slice_Extension              // 20
	NALU_Reserved3                          // 21
	NALU_Reserved4                          // 22
	NALU_Reserved5                          // 23
	NALU_STAPA                              // 24
	NALU_STAPB
	NALU_MTAP16
	NALU_MTAP24
	NALU_FUA // 28
	NALU_FUB
	// 24 - 31 NALU_NotReserved

)

var (
	NALU_AUD_BYTE   = []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xF0}
	NALU_Delimiter1 = [3]byte{0x00, 0x00, 0x01}
	NALU_Delimiter2 = [4]byte{0x00, 0x00, 0x00, 0x01}
)

// H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)
// NAL - Network Abstract Layer
// raw byte sequence payload (RBSP) 原始字节序列载荷

// SplitH264 以0x00000001分割H264裸数据
//func SplitH264(payload []byte) (nalus [][]byte) {
//	for _, v := range bytes.SplitN(payload, NALU_Delimiter2, -1) {
//		if len(v) == 0 {
//			continue
//		}
//		nalus = append(nalus, bytes.SplitN(v, NALU_Delimiter1, -1)...)
//	}
//	return
//}

type (
	H264Ctx struct {
		h264parser.CodecData
	}
)

func NewH264CtxFromRecord(record []byte) (ret *H264Ctx, err error) {
	ret = &H264Ctx{}
	ret.CodecData, err = h264parser.NewCodecDataFromAVCDecoderConfRecord(record)
	return
}

func (*H264Ctx) FourCC() FourCC {
	return FourCC_H264
}

func (ctx *H264Ctx) GetInfo() string {
	return fmt.Sprintf("fps: %d, resolution: %s", ctx.FPS(), ctx.Resolution())
}

func (h264 *H264Ctx) GetBase() ICodecCtx {
	return h264
}

func (ctx *H264Ctx) GetRecord() []byte {
	return ctx.Record
}

func (h264 *H264Ctx) String() string {
	return fmt.Sprintf("avc1.%02X%02X%02X", h264.RecordInfo.AVCProfileIndication, h264.RecordInfo.ProfileCompatibility, h264.RecordInfo.AVCLevelIndication)
}
