package storage

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
)

// Constants for detection video and audio types.
const (
	PacketTypeAV1   = 1
	PacketTypeH264  = 2
	PacketTypeH265  = 3
	PacketTypeMJPEG = 4
	PacketTypeVP8   = 5
	PacketTypeVP9   = 6

	PacketTypeG711 = 21
	PacketTypeAAC  = 22
	PacketTypeLPCM = 23
	PacketTypeOPUS = 24
)

// InterleavedPacket is the structure of each inner packet.
type InterleavedPacket struct {
	Type byte
	Pts  int64

	H264AUs     [][]byte
	LPCMSamples []byte
}

// Segment is overall structure according to each period.
type Segment struct {
	Date     string
	Duration string
	Packet   InterleavedPacket
	Packets  []InterleavedPacket
}

// writeString записывает строку: сначала int32 длина, затем данные.
func writeString(w io.Writer, s string) error {
	if err := binary.Write(w, binary.LittleEndian, int32(len(s))); err != nil {
		return err
	}
	_, err := w.Write([]byte(s))
	return err
}

// WritePacket записывает один interleaved пакет.
func WritePacket(w io.Writer, pkt InterleavedPacket) error {
	// Записываем тип пакета (1 байт)
	if err := binary.Write(w, binary.LittleEndian, pkt.Type); err != nil {
		return err
	}
	// Записываем pts (int64)
	if err := binary.Write(w, binary.LittleEndian, pkt.Pts); err != nil {
		return err
	}

	if pkt.Type == PacketTypeH264 {
		// Для H264 – AU как [][]byte.
		numAUs := int32(len(pkt.H264AUs))
		if err := binary.Write(w, binary.LittleEndian, numAUs); err != nil {
			return err
		}
		for _, au := range pkt.H264AUs {
			if err := binary.Write(w, binary.LittleEndian, int32(len(au))); err != nil {
				return err
			}
			if _, err := w.Write(au); err != nil {
				return err
			}
		}
	} else if pkt.Type == PacketTypeLPCM {
		// Для LPCM – просто длина и данные.
		if err := binary.Write(w, binary.LittleEndian, int32(len(pkt.LPCMSamples))); err != nil {
			return err
		}
		if _, err := w.Write(pkt.LPCMSamples); err != nil {
			return err
		}
	} else {
		return fmt.Errorf("неизвестный тип пакета: %d", pkt.Type)
	}
	return nil
}

// WriteHeader записывает заголовок сегмента (Start и Duration).
func WriteHeader(w io.Writer, seg Segment) error {
	var buf bytes.Buffer
	if err := writeString(&buf, seg.Date); err != nil {
		return err
	}
	if err := writeString(&buf, seg.Duration); err != nil {
		return err
	}
	segData := buf.Bytes()
	if err := binary.Write(w, binary.LittleEndian, int32(len(segData))); err != nil {
		return err
	}
	_, err := w.Write(segData)
	return err
}

// WriteInterleavedPacket записывает сегмент с пакетами.
// Теперь количество пакетов определяется динамически.
func WriteInterleavedPacket(w io.Writer, seg Segment) error {
	var buf bytes.Buffer

	if err := binary.Write(&buf, binary.LittleEndian, int32(1)); err != nil {
		return err
	}
	// Записываем каждый пакет.
	if err := WritePacket(&buf, seg.Packet); err != nil {
		return err
	}

	segData := buf.Bytes()
	if err := binary.Write(w, binary.LittleEndian, int32(len(segData))); err != nil {
		return err
	}
	_, err := w.Write(segData)
	return err
}