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

package nack

import (
	
	

	
)

type receiveLog struct {
	packets         []uint64
	size            uint16
	end             uint16
	started         bool
	lastConsecutive uint16
	m               sync.RWMutex
}

func newReceiveLog( uint16) (*receiveLog, error) {
	 := make([]uint16, 0)
	 := false
	for  := 6;  < 16; ++ {
		if  == 1<< {
			 = true

			break
		}
		 = append(, 1<<)
	}

	if ! {
		return nil, fmt.Errorf("%w: %d is not a valid size, allowed sizes: %v", ErrInvalidSize, , )
	}

	return &receiveLog{
		packets: make([]uint64, /64),
		size:    ,
	}, nil
}

func ( *receiveLog) ( uint16) {
	.m.Lock()
	defer .m.Unlock()

	if !.started {
		.setReceived()
		.end = 
		.started = true
		.lastConsecutive = 

		return
	}

	 :=  - .end
	switch {
	case  == 0:
		return
	case  < rtpbuffer.Uint16SizeHalf:
		// this means a positive diff, in other words seq > end (with counting for rollovers)
		for  := .end + 1;  != ; ++ {
			// clear packets between end and seq (these may contain packets from a "size" ago)
			.delReceived()
		}
		.end = 

		if .lastConsecutive+1 ==  {
			.lastConsecutive = 
		} else if -.lastConsecutive > .size {
			.lastConsecutive =  - .size
			.fixLastConsecutive() // there might be valid packets at the beginning of the buffer now
		}
	case .lastConsecutive+1 == :
		// negative diff, seq < end (with counting for rollovers)
		.lastConsecutive = 
		.fixLastConsecutive() // there might be other valid packets after seq
	}

	.setReceived()
}

func ( *receiveLog) ( uint16) bool {
	.m.RLock()
	defer .m.RUnlock()

	 := .end - 
	if  >= rtpbuffer.Uint16SizeHalf {
		return false
	}

	if  >= .size {
		return false
	}

	return .getReceived()
}

func ( *receiveLog) ( uint16,  []uint16) []uint16 {
	.m.RLock()
	defer .m.RUnlock()

	 := .end - 
	if -.lastConsecutive >= rtpbuffer.Uint16SizeHalf {
		// until < s.lastConsecutive (counting for rollover)
		return nil
	}

	 := 0
	for  := .lastConsecutive + 1;  != +1; ++ {
		if !.getReceived() {
			[] = 
			++
		}
	}

	return [:]
}

func ( *receiveLog) ( uint16) {
	 :=  % .size
	.packets[/64] |= 1 << ( % 64)
}

func ( *receiveLog) ( uint16) {
	 :=  % .size
	.packets[/64] &^= 1 << ( % 64)
}

func ( *receiveLog) ( uint16) bool {
	 :=  % .size

	return (.packets[/64] & (1 << ( % 64))) != 0
}

func ( *receiveLog) () {
	 := .lastConsecutive + 1
	for ;  != .end+1 && .getReceived(); ++ { //nolint:revive
		// find all consecutive packets
	}

	.lastConsecutive =  - 1
}