package unpacker

import (
	"encoding/binary"
	"fmt"
	"git.insit.tech/psa/rtsp_reader-writer/writer/pkg/storage"
	"io"
)

// readString reads string length and then reads string data.
func readString(r io.Reader) (string, error) {
	var length int32
	if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
		return "", err
	}
	buf := make([]byte, length)
	if _, err := io.ReadFull(r, buf); err != nil {
		return "", err
	}
	return string(buf), nil
}

// readHeaderSegment reads header of the segment.
func readHeaderSegment(r io.Reader) (storage.Segment, error) {
	var seg storage.Segment
	date, err := readString(r)
	if err != nil {
		return seg, err
	}
	seg.Date = date

	duration, err := readString(r)
	if err != nil {
		return seg, err
	}
	seg.Duration = duration

	return seg, nil
}

// readPacket reads one interleaved packet.
func readPacket(r io.Reader) (storage.InterleavedPacket, error) {
	var pkt storage.InterleavedPacket

	// Read type of the packet.
	typeByte := make([]byte, 1)
	if _, err := io.ReadFull(r, typeByte); err != nil {
		return pkt, err
	}
	pkt.Type = typeByte[0]

	// Read PTS (int64).
	if err := binary.Read(r, binary.LittleEndian, &pkt.Pts); err != nil {
		return pkt, err
	}

	// Read data of the segment.
	if pkt.Type == storage.PacketTypeH264 {
		var numAUs int32
		if err := binary.Read(r, binary.LittleEndian, &numAUs); err != nil {
			return pkt, err
		}
		var auList [][]byte
		for i := 0; i < int(numAUs); i++ {
			var auLen int32
			if err := binary.Read(r, binary.LittleEndian, &auLen); err != nil {
				return pkt, err
			}
			auData := make([]byte, auLen)
			if _, err := io.ReadFull(r, auData); err != nil {
				return pkt, err
			}
			auList = append(auList, auData)
		}
		pkt.H264AUs = auList
	} else if pkt.Type == storage.PacketTypeLPCM {
		var auLen int32
		if err := binary.Read(r, binary.LittleEndian, &auLen); err != nil {
			return pkt, err
		}
		auData := make([]byte, auLen)
		if _, err := io.ReadFull(r, auData); err != nil {
			return pkt, err
		}
		pkt.LPCMSamples = auData
	} else {
		return pkt, fmt.Errorf("unknown type of the packet: %d", pkt.Type)
	}

	return pkt, nil
}

// readPacketSegment reads segment packets.
func readPacketSegment(r io.Reader) ([]storage.InterleavedPacket, error) {
	var numPackets int32
	if err := binary.Read(r, binary.LittleEndian, &numPackets); err != nil {
		return nil, err
	}

	var packets []storage.InterleavedPacket
	for i := 0; i < int(numPackets); i++ {
		pkt, err := readPacket(r)
		if err != nil {
			return nil, err
		}
		packets = append(packets, pkt)
	}
	return packets, nil
}
