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

package rtcp

import (
	
	
)

// A ReceiverReport (RR) packet provides reception quality feedback for an RTP stream
type ReceiverReport struct {
	// The synchronization source identifier for the originator of this RR packet.
	SSRC uint32
	// Zero or more reception report blocks depending on the number of other
	// sources heard by this sender since the last report. Each reception report
	// block conveys statistics on the reception of RTP packets from a
	// single synchronization source.
	Reports []ReceptionReport
	// Extension contains additional, payload-specific information that needs to
	// be reported regularly about the receiver.
	ProfileExtensions []byte
}

const (
	ssrcLength     = 4
	rrSSRCOffset   = headerLength
	rrReportOffset = rrSSRCOffset + ssrcLength
)

// Marshal encodes the ReceiverReport in binary
func ( ReceiverReport) () ([]byte, error) {
	/*
	 *         0                   1                   2                   3
	 *         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 * header |V=2|P|    RC   |   PT=RR=201   |             length            |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *        |                     SSRC of packet sender                     |
	 *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
	 * report |                 SSRC_1 (SSRC of first source)                 |
	 * block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *   1    | fraction lost |       cumulative number of packets lost       |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *        |           extended highest sequence number received           |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *        |                      interarrival jitter                      |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *        |                         last SR (LSR)                         |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *        |                   delay since last SR (DLSR)                  |
	 *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
	 * report |                 SSRC_2 (SSRC of second source)                |
	 * block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *   2    :                               ...                             :
	 *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
	 *        |                  profile-specific extensions                  |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 */

	 := make([]byte, .MarshalSize())
	 := [headerLength:]

	binary.BigEndian.PutUint32(, .SSRC)

	for ,  := range .Reports {
		,  := .Marshal()
		if  != nil {
			return nil, 
		}
		 := ssrcLength + receptionReportLength*
		copy([:], )
	}

	if len(.Reports) > countMax {
		return nil, errTooManyReports
	}

	 := make([]byte, len(.ProfileExtensions))
	copy(, .ProfileExtensions)

	// if the length of the profile extensions isn't devisible
	// by 4, we need to pad the end.
	for (len() & 0x3) != 0 {
		 = append(, 0)
	}

	 = append(, ...)

	,  := .Header().Marshal()
	if  != nil {
		return nil, 
	}
	copy(, )

	return , nil
}

// Unmarshal decodes the ReceiverReport from binary
func ( *ReceiverReport) ( []byte) error {
	/*
	 *         0                   1                   2                   3
	 *         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 * header |V=2|P|    RC   |   PT=RR=201   |             length            |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *        |                     SSRC of packet sender                     |
	 *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
	 * report |                 SSRC_1 (SSRC of first source)                 |
	 * block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *   1    | fraction lost |       cumulative number of packets lost       |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *        |           extended highest sequence number received           |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *        |                      interarrival jitter                      |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *        |                         last SR (LSR)                         |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *        |                   delay since last SR (DLSR)                  |
	 *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
	 * report |                 SSRC_2 (SSRC of second source)                |
	 * block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *   2    :                               ...                             :
	 *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
	 *        |                  profile-specific extensions                  |
	 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 */

	if len() < (headerLength + ssrcLength) {
		return errPacketTooShort
	}

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

	if .Type != TypeReceiverReport {
		return errWrongType
	}

	.SSRC = binary.BigEndian.Uint32([rrSSRCOffset:])

	for  := rrReportOffset;  < len() && len(.Reports) < int(.Count);  += receptionReportLength {
		var  ReceptionReport
		if  := .Unmarshal([:]);  != nil {
			return 
		}
		.Reports = append(.Reports, )
	}
	.ProfileExtensions = [rrReportOffset+(len(.Reports)*receptionReportLength):]

	if uint8(len(.Reports)) != .Count {
		return errInvalidHeader
	}

	return nil
}

// MarshalSize returns the size of the packet once marshaled
func ( *ReceiverReport) () int {
	 := 0
	for ,  := range .Reports {
		 += .len()
	}
	return headerLength + ssrcLength + 
}

// Header returns the Header associated with this packet.
func ( *ReceiverReport) () Header {
	return Header{
		Count:  uint8(len(.Reports)),
		Type:   TypeReceiverReport,
		Length: uint16((.MarshalSize()/4)-1) + uint16(getPadding(len(.ProfileExtensions))),
	}
}

// DestinationSSRC returns an array of SSRC values that this packet refers to.
func ( *ReceiverReport) () []uint32 {
	 := make([]uint32, len(.Reports))
	for ,  := range .Reports {
		[] = .SSRC
	}
	return 
}

func ( ReceiverReport) () string {
	 := fmt.Sprintf("ReceiverReport from %x\n", .SSRC)
	 += "\tSSRC    \tLost\tLastSequence\n"
	for ,  := range .Reports {
		 += fmt.Sprintf("\t%x\t%d/%d\t%d\n", .SSRC, .FractionLost, .TotalLost, .LastSequenceNumber)
	}
	 += fmt.Sprintf("\tProfile Extension Data: %v\n", .ProfileExtensions)
	return 
}