// Package h264 - MPEG4 format related functions
package h264

import (
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"encoding/hex"

	"github.com/AlexxIT/go2rtc/pkg/core"
)

// DecodeConfig - extract profile, SPS and PPS from MPEG4 config
func DecodeConfig(conf []byte) (profile []byte, sps []byte, pps []byte) {
	if len(conf) < 6 || conf[0] != 1 {
		return
	}

	profile = conf[1:4]

	count := conf[5] & 0x1F
	conf = conf[6:]
	for range count {
		if len(conf) < 2 {
			return
		}
		size := 2 + int(binary.BigEndian.Uint16(conf))
		if len(conf) < size {
			return
		}
		if sps == nil {
			sps = conf[2:size]
		}
		conf = conf[size:]
	}

	count = conf[0]
	conf = conf[1:]
	for range count {
		if len(conf) < 2 {
			return
		}
		size := 2 + int(binary.BigEndian.Uint16(conf))
		if len(conf) < size {
			return
		}
		if pps == nil {
			pps = conf[2:size]
		}
		conf = conf[size:]
	}

	return
}

func EncodeConfig(sps, pps []byte) []byte {
	spsSize := uint16(len(sps))
	ppsSize := uint16(len(pps))

	buf := make([]byte, 5+3+spsSize+3+ppsSize)
	buf[0] = 1
	copy(buf[1:], sps[1:4]) // profile
	buf[4] = 3 | 0xFC       // ? LengthSizeMinusOne

	b := buf[5:]
	_ = b[3]
	b[0] = 1 | 0xE0 // ? sps count
	binary.BigEndian.PutUint16(b[1:], spsSize)
	copy(b[3:], sps)

	b = buf[5+3+spsSize:]
	_ = b[3]
	b[0] = 1 // pps count
	binary.BigEndian.PutUint16(b[1:], ppsSize)
	copy(b[3:], pps)

	return buf
}

func ConfigToCodec(conf []byte) *core.Codec {
	buf := bytes.NewBufferString("packetization-mode=1")

	profile, sps, pps := DecodeConfig(conf)
	if profile != nil {
		buf.WriteString(";profile-level-id=")
		buf.WriteString(hex.EncodeToString(profile))
	}
	if sps != nil && pps != nil {
		buf.WriteString(";sprop-parameter-sets=")
		buf.WriteString(base64.StdEncoding.EncodeToString(sps))
		buf.WriteString(",")
		buf.WriteString(base64.StdEncoding.EncodeToString(pps))
	}

	return &core.Codec{
		Name:        core.CodecH264,
		ClockRate:   90000,
		FmtpLine:    buf.String(),
		PayloadType: core.PayloadTypeRAW,
	}
}
