package delta

import (
	
	
	
	
	

	
	
	
	
)

type BinaryPackedEncoding struct {
	encoding.NotSupported
}

func ( *BinaryPackedEncoding) () string {
	return "DELTA_BINARY_PACKED"
}

func ( *BinaryPackedEncoding) () format.Encoding {
	return format.DeltaBinaryPacked
}

func ( *BinaryPackedEncoding) ( []byte,  []int32) ([]byte, error) {
	return encodeInt32([:0], ), nil
}

func ( *BinaryPackedEncoding) ( []byte,  []int64) ([]byte, error) {
	return encodeInt64([:0], ), nil
}

func ( *BinaryPackedEncoding) ( []int32,  []byte) ([]int32, error) {
	 := unsafecast.Slice[byte]()
	, ,  := decodeInt32([:0], )
	return unsafecast.Slice[int32](), .wrap()
}

func ( *BinaryPackedEncoding) ( []int64,  []byte) ([]int64, error) {
	 := unsafecast.Slice[byte]()
	, ,  := decodeInt64([:0], )
	return unsafecast.Slice[int64](), .wrap()
}

func ( *BinaryPackedEncoding) ( error) error {
	if  != nil {
		 = encoding.Error(, )
	}
	return 
}

const (
	blockSize     = 128
	numMiniBlocks = 4
	miniBlockSize = blockSize / numMiniBlocks
	// The parquet spec does not enforce a limit to the block size, but we need
	// one otherwise invalid inputs may result in unbounded memory allocations.
	//
	// 65K+ values should be enough for any valid use case.
	maxSupportedBlockSize = 65536

	maxHeaderLength32    = 4 * binary.MaxVarintLen64
	maxMiniBlockLength32 = binary.MaxVarintLen64 + numMiniBlocks + (4 * blockSize)

	maxHeaderLength64    = 8 * binary.MaxVarintLen64
	maxMiniBlockLength64 = binary.MaxVarintLen64 + numMiniBlocks + (8 * blockSize)
)

var (
	encodeInt32 = encodeInt32Default
	encodeInt64 = encodeInt64Default
)

func encodeInt32Default( []byte,  []int32) []byte {
	 := len()
	 := int32(0)
	if  > 0 {
		 = [0]
	}

	 := len()
	 = resize(, +maxHeaderLength32)
	 = [:+encodeBinaryPackedHeader([:], blockSize, numMiniBlocks, , int64())]

	if  < 2 {
		return 
	}

	 := 
	for  := 1;  < len();  += blockSize {
		 := [blockSize]int32{}
		 := copy([:], [:])

		 = blockDeltaInt32(&, )
		 := blockMinInt32(&)
		blockSubInt32(&, )
		blockClearInt32(&, )

		 := [numMiniBlocks]byte{}
		blockBitWidthsInt32(&, &)

		 := len()
		 = resize(, +maxMiniBlockLength32+4)
		 += encodeBlockHeader([:], int64(), )

		for ,  := range  {
			if  != 0 {
				 := (*[miniBlockSize]int32)([*miniBlockSize:])
				encodeMiniBlockInt32([:], , uint())
				 += (miniBlockSize * int()) / 8
			}
		}

		 = [:]
	}

	return 
}

func encodeInt64Default( []byte,  []int64) []byte {
	 := len()
	 := int64(0)
	if  > 0 {
		 = [0]
	}

	 := len()
	 = resize(, +maxHeaderLength64)
	 = [:+encodeBinaryPackedHeader([:], blockSize, numMiniBlocks, , )]

	if  < 2 {
		return 
	}

	 := 
	for  := 1;  < len();  += blockSize {
		 := [blockSize]int64{}
		 := copy([:], [:])

		 = blockDeltaInt64(&, )
		 := blockMinInt64(&)
		blockSubInt64(&, )
		blockClearInt64(&, )

		 := [numMiniBlocks]byte{}
		blockBitWidthsInt64(&, &)

		 := len()
		 = resize(, +maxMiniBlockLength64+8)
		 += encodeBlockHeader([:], , )

		for ,  := range  {
			if  != 0 {
				 := (*[miniBlockSize]int64)([*miniBlockSize:])
				encodeMiniBlockInt64([:], , uint())
				 += (miniBlockSize * int()) / 8
			}
		}

		 = [:]
	}

	return 
}

func encodeBinaryPackedHeader( []byte, , ,  int,  int64) ( int) {
	 += binary.PutUvarint([:], uint64())
	 += binary.PutUvarint([:], uint64())
	 += binary.PutUvarint([:], uint64())
	 += binary.PutVarint([:], )
	return 
}

func encodeBlockHeader( []byte,  int64,  [numMiniBlocks]byte) ( int) {
	 += binary.PutVarint(, int64())
	 += copy([:], [:])
	return 
}

func blockClearInt32( *[blockSize]int32,  int) {
	if  < blockSize {
		 := [:]
		for  := range  {
			[] = 0
		}
	}
}

func blockDeltaInt32( *[blockSize]int32,  int32) int32 {
	for ,  := range  {
		[],  = -, 
	}
	return 
}

func blockMinInt32( *[blockSize]int32) int32 {
	 := [0]
	for ,  := range [1:] {
		if  <  {
			 = 
		}
	}
	return 
}

func blockSubInt32( *[blockSize]int32,  int32) {
	for  := range  {
		[] -= 
	}
}

func blockBitWidthsInt32( *[numMiniBlocks]byte,  *[blockSize]int32) {
	for  := range  {
		 := ( + 0) * miniBlockSize
		 := ( + 1) * miniBlockSize
		 := 0

		for ,  := range [:] {
			if  := bits.Len32(uint32());  >  {
				 = 
			}
		}

		[] = byte()
	}
}

func blockClearInt64( *[blockSize]int64,  int) {
	if  < blockSize {
		 := [:]
		for  := range  {
			[] = 0
		}
	}
}

func blockDeltaInt64( *[blockSize]int64,  int64) int64 {
	for ,  := range  {
		[],  = -, 
	}
	return 
}

func blockMinInt64( *[blockSize]int64) int64 {
	 := [0]
	for ,  := range [1:] {
		if  <  {
			 = 
		}
	}
	return 
}

func blockSubInt64( *[blockSize]int64,  int64) {
	for  := range  {
		[] -= 
	}
}

func blockBitWidthsInt64( *[numMiniBlocks]byte,  *[blockSize]int64) {
	for  := range  {
		 := ( + 0) * miniBlockSize
		 := ( + 1) * miniBlockSize
		 := 0

		for ,  := range [:] {
			if  := bits.Len64(uint64());  >  {
				 = 
			}
		}

		[] = byte()
	}
}

func decodeInt32(,  []byte) ([]byte, []byte, error) {
	, , , , ,  := decodeBinaryPackedHeader()
	if  != nil {
		return , , 
	}
	if  == 0 {
		return , , nil
	}
	if  < math.MinInt32 ||  > math.MaxInt32 {
		return , , fmt.Errorf("first value out of range: %d", )
	}

	 := len()
	 = resize(, len()+4*)
	 := unsafecast.Slice[int32]()
	[] = int32()
	++
	--
	 := int32()
	 :=  / 

	const  = 16
	 := make([]byte, 256+)

	for  > 0 && len() > 0 {
		var  int64
		var  []byte
		, , ,  = decodeBinaryPackedBlock(, )
		if  != nil {
			return , , 
		}

		 := 

		for ,  := range  {
			 := min(, )
			if  != 0 {
				 := ( * int()) / 8
				 := 
				if  <= len() {
					 = [:]
				}
				 = [len():]
				if cap() < +bitpack.PaddingInt32 {
					 = resize([:0], +bitpack.PaddingInt32)
					 = [:copy(, )]
				}
				 = [:]
				bitpack.UnpackInt32([:+], , uint())
			}
			 += 
			 -= 
			if  == 0 {
				break
			}
		}

		 = decodeBlockInt32([:], int32(), )
	}

	if  > 0 {
		return , , fmt.Errorf("%d missing values: %w", , io.ErrUnexpectedEOF)
	}

	return , , nil
}

func decodeInt64(,  []byte) ([]byte, []byte, error) {
	, , , , ,  := decodeBinaryPackedHeader()
	if  != nil {
		return , , 
	}
	if  == 0 {
		return , , nil
	}

	 := len()
	 = resize(, len()+8*)
	 := unsafecast.Slice[int64]()
	[] = 
	++
	--
	 := 
	 :=  / 

	const  = 16
	 := make([]byte, 512+)

	for  > 0 && len() > 0 {
		var  int64
		var  []byte
		, , ,  = decodeBinaryPackedBlock(, )
		if  != nil {
			return , , 
		}
		 := 

		for ,  := range  {
			 := min(, )
			if  != 0 {
				 := ( * int()) / 8
				 := 
				if  <= len() {
					 = [:]
				}
				 = [len():]
				if len() < +bitpack.PaddingInt64 {
					 = resize([:0], +bitpack.PaddingInt64)
					 = [:copy(, )]
				}
				 = [:]
				bitpack.UnpackInt64([:+], , uint())
			}
			 += 
			 -= 
			if  == 0 {
				break
			}
		}

		 = decodeBlockInt64([:], , )
	}

	if  > 0 {
		return , , fmt.Errorf("%d missing values: %w", , io.ErrUnexpectedEOF)
	}

	return , , nil
}

func decodeBinaryPackedHeader( []byte) (, ,  int,  int64,  []byte,  error) {
	 := uint64(0)
	 := 0
	 := 0

	if , ,  = decodeUvarint([:], "block size");  != nil {
		return
	}
	 += 
	 = int()

	if , ,  = decodeUvarint([:], "number of mini-blocks");  != nil {
		return
	}
	 += 
	 = int()

	if , ,  = decodeUvarint([:], "total values");  != nil {
		return
	}
	 += 
	 = int()

	if , ,  = decodeVarint([:], "first value");  != nil {
		return
	}
	 += 

	if  == 0 {
		 = fmt.Errorf("invalid number of mini block (%d)", )
	} else if ( <= 0) || (%128) != 0 {
		 = fmt.Errorf("invalid block size is not a multiple of 128 (%d)", )
	} else if  > maxSupportedBlockSize {
		 = fmt.Errorf("invalid block size is too large (%d)", )
	} else if  :=  / ; ( <= 0) || (%32) != 0 {
		 = fmt.Errorf("invalid mini block size is not a multiple of 32 (%d)", )
	} else if  < 0 {
		 = fmt.Errorf("invalid total number of values is negative (%d)", )
	} else if  > math.MaxInt32 {
		 = fmt.Errorf("too many values: %d", )
	}

	return , , , , [:], 
}

func decodeBinaryPackedBlock( []byte,  int) ( int64, ,  []byte,  error) {
	, ,  := decodeVarint(, "min delta")
	if  != nil {
		return 0, nil, , 
	}
	 = [:]
	if len() <  {
		,  = , nil
	} else {
		,  = [:], [:]
	}
	return , , , nil
}

func decodeUvarint( []byte,  string) ( uint64,  int,  error) {
	,  = binary.Uvarint()
	if  == 0 {
		return 0, 0, fmt.Errorf("decoding %s: %w", , io.ErrUnexpectedEOF)
	}
	if  < 0 {
		return 0, 0, fmt.Errorf("overflow decoding %s (read %d/%d bytes)", , -, len())
	}
	return , , nil
}

func decodeVarint( []byte,  string) ( int64,  int,  error) {
	,  = binary.Varint()
	if  == 0 {
		return 0, 0, fmt.Errorf("decoding %s: %w", , io.ErrUnexpectedEOF)
	}
	if  < 0 {
		return 0, 0, fmt.Errorf("overflow decoding %s (read %d/%d bytes)", , -, len())
	}
	return , , nil
}