// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package rtcp

import (
	
	
	
)

// SLIEntry represents a single entry to the SLI packet's
// list of lost slices.
type SLIEntry struct {
	// ID of first lost slice
	First uint16

	// Number of lost slices
	Number uint16

	// ID of related picture
	Picture uint8
}

// The SliceLossIndication packet informs the encoder about the loss of a picture slice
type SliceLossIndication struct {
	// SSRC of sender
	SenderSSRC uint32

	// SSRC of the media source
	MediaSSRC uint32

	SLI []SLIEntry
}

const (
	sliLength = 2
	sliOffset = 8
)

// Marshal encodes the SliceLossIndication in binary
func ( SliceLossIndication) () ([]byte, error) {
	if len(.SLI)+sliLength > math.MaxUint8 {
		return nil, errTooManyReports
	}

	 := make([]byte, sliOffset+(len(.SLI)*4))
	binary.BigEndian.PutUint32(, .SenderSSRC)
	binary.BigEndian.PutUint32([4:], .MediaSSRC)
	for ,  := range .SLI {
		 := ((uint32(.First) & 0x1FFF) << 19) |
			((uint32(.Number) & 0x1FFF) << 6) |
			(uint32(.Picture) & 0x3F)
		binary.BigEndian.PutUint32([sliOffset+(4*):], )
	}
	,  := .Header().Marshal()
	if  != nil {
		return nil, 
	}

	return append(, ...), nil
}

// Unmarshal decodes the SliceLossIndication from binary
func ( *SliceLossIndication) ( []byte) error {
	if len() < (headerLength + ssrcLength) {
		return errPacketTooShort
	}

	var  Header
	if  := .Unmarshal();  != nil {
		return 
	}

	if len() < (headerLength + int(4*.Length)) {
		return errPacketTooShort
	}

	if .Type != TypeTransportSpecificFeedback || .Count != FormatSLI {
		return errWrongType
	}

	.SenderSSRC = binary.BigEndian.Uint32([headerLength:])
	.MediaSSRC = binary.BigEndian.Uint32([headerLength+ssrcLength:])
	for  := headerLength + sliOffset;  < (headerLength + int(.Length*4));  += 4 {
		 := binary.BigEndian.Uint32([:])
		.SLI = append(.SLI, SLIEntry{
			First:   uint16(( >> 19) & 0x1FFF),
			Number:  uint16(( >> 6) & 0x1FFF),
			Picture: uint8( & 0x3F),
		})
	}
	return nil
}

// MarshalSize returns the size of the packet once marshaled
func ( *SliceLossIndication) () int {
	return headerLength + sliOffset + (len(.SLI) * 4)
}

// Header returns the Header associated with this packet.
func ( *SliceLossIndication) () Header {
	return Header{
		Count:  FormatSLI,
		Type:   TypeTransportSpecificFeedback,
		Length: uint16((.MarshalSize() / 4) - 1),
	}
}

func ( *SliceLossIndication) () string {
	return fmt.Sprintf("SliceLossIndication %x %x %+v", .SenderSSRC, .MediaSSRC, .SLI)
}

// DestinationSSRC returns an array of SSRC values that this packet refers to.
func ( *SliceLossIndication) () []uint32 {
	return []uint32{.MediaSSRC}
}