package rtmp

import (
	"time"

	"github.com/deepch/vdk/codec/aacparser"
	. "m7s.live/v5/pkg"
	"m7s.live/v5/pkg/codec"
	"m7s.live/v5/pkg/util"
)

type RTMPAudio struct {
	RTMPData
}

func (avcc *RTMPAudio) Parse(t *AVTrack) (err error) {
	reader := avcc.NewReader()
	var b byte
	b, err = reader.ReadByte()
	if err != nil {
		return
	}
	switch b & 0b1111_0000 >> 4 {
	case 7:
		if t.ICodecCtx == nil {
			var ctx codec.PCMACtx
			ctx.SampleRate = 8000
			ctx.Channels = 1
			ctx.SampleSize = 8
			t.ICodecCtx = &ctx
		}
	case 8:
		if t.ICodecCtx == nil {
			var ctx codec.PCMUCtx
			ctx.SampleRate = 8000
			ctx.Channels = 1
			ctx.SampleSize = 8
			t.ICodecCtx = &ctx
		}
	case 10:
		b, err = reader.ReadByte()
		if err != nil {
			return
		}
		if b == 0 {
			var ctx codec.AACCtx
			var cloneFrame RTMPAudio
			cloneFrame.CopyFrom(&avcc.Memory)
			ctx.CodecData, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(cloneFrame.Buffers[0][2:])
			t.SequenceFrame = &cloneFrame
			t.ICodecCtx = &ctx
		}
	}
	return
}

func (avcc *RTMPAudio) ConvertCtx(from codec.ICodecCtx) (to codec.ICodecCtx, seq IAVFrame, err error) {
	to = from.GetBase()
	switch v := to.(type) {
	case *codec.AACCtx:
		var seqFrame RTMPAudio
		seqFrame.AppendOne(append([]byte{0xAF, 0x00}, v.ConfigBytes...))
		seq = &seqFrame
	}
	return
}

func (avcc *RTMPAudio) Demux(codecCtx codec.ICodecCtx) (raw any, err error) {
	reader := avcc.NewReader()
	var result util.Memory
	if _, ok := codecCtx.(*codec.AACCtx); ok {
		err = reader.Skip(2)
		reader.Range(result.AppendOne)
		return result, err
	} else {
		err = reader.Skip(1)
		reader.Range(result.AppendOne)
		return result, err
	}
}

func (avcc *RTMPAudio) Mux(codecCtx codec.ICodecCtx, from *AVFrame) {
	avcc.Timestamp = uint32(from.Timestamp / time.Millisecond)
	audioData := from.Raw.(AudioData)
	avcc.InitRecycleIndexes(1)
	switch c := codecCtx.FourCC(); c {
	case codec.FourCC_MP4A:
		head := avcc.NextN(2)
		head[0], head[1] = 0xAF, 0x01
		avcc.Append(audioData.Buffers...)
	case codec.FourCC_ALAW, codec.FourCC_ULAW:
		head := avcc.NextN(1)
		head[0] = byte(ParseAudioCodec(c))<<4 | (1 << 1)
		avcc.Append(audioData.Buffers...)
	}
}
