package avro

import (
	
	
	
	
	
)

const (
	maxIntBufSize  = 5
	maxLongBufSize = 10
)

// ReaderFunc is a function used to customize the Reader.
type ReaderFunc func(r *Reader)

// WithReaderConfig specifies the configuration to use with a reader.
func ( API) ReaderFunc {
	return func( *Reader) {
		.cfg = .(*frozenConfig)
	}
}

// Reader is an Avro specific io.Reader.
type Reader struct {
	cfg    *frozenConfig
	reader io.Reader
	slab   []byte
	buf    []byte
	head   int
	tail   int
	Error  error
}

// NewReader creates a new Reader.
func ( io.Reader,  int,  ...ReaderFunc) *Reader {
	 := &Reader{
		cfg:    DefaultConfig.(*frozenConfig),
		reader: ,
		buf:    make([]byte, ),
		head:   0,
		tail:   0,
	}

	for ,  := range  {
		()
	}

	return 
}

// Reset resets a Reader with a new byte array attached.
func ( *Reader) ( []byte) *Reader {
	.reader = nil
	.buf = 
	.head = 0
	.tail = len()
	return 
}

// ReportError record an error in iterator instance with current position.
func ( *Reader) (,  string) {
	if .Error != nil && !errors.Is(.Error, io.EOF) {
		return
	}

	.Error = fmt.Errorf("avro: %s: %s", , )
}

func ( *Reader) () bool {
	if .reader == nil {
		if .Error == nil {
			.head = .tail
			.Error = io.EOF
		}
		return false
	}

	for {
		,  := .reader.Read(.buf)
		if  == 0 {
			if  != nil {
				if .Error == nil {
					.Error = 
				}
				return false
			}
			continue
		}

		.head = 0
		.tail = 
		return true
	}
}

func ( *Reader) () byte {
	if .head == .tail {
		if !.loadMore() {
			.Error = io.ErrUnexpectedEOF
			return 0
		}
	}

	 := .buf[.head]
	.head++

	return 
}

// Peek returns the next byte in the buffer.
// The Reader Error will be io.EOF if no next byte exists.
func ( *Reader) () byte {
	if .head == .tail {
		if !.loadMore() {
			return 0
		}
	}
	return .buf[.head]
}

// Read reads data into the given bytes.
func ( *Reader) ( []byte) {
	 := len()
	 := 0

	for  <  {
		if .head == .tail {
			if !.loadMore() {
				.Error = io.ErrUnexpectedEOF
				return
			}
		}

		 := copy([:], .buf[.head:.tail])
		.head += 
		 += 
	}
}

// ReadBool reads a Bool from the Reader.
func ( *Reader) () bool {
	 := .readByte()

	if  != 0 &&  != 1 {
		.ReportError("ReadBool", "invalid bool")
	}
	return  == 1
}

// ReadInt reads an Int from the Reader.
//
//nolint:dupl
func ( *Reader) () int32 {
	if .Error != nil {
		return 0
	}

	var (
		 int
		 uint32
		 uint8
	)

	for {
		 := .tail
		if .tail-.head+ > maxIntBufSize {
			 = .head + maxIntBufSize - 
		}

		// Consume what it is in the buffer.
		var  int
		for ,  := range .buf[.head:] {
			 |= uint32(&0x7f) << 
			if &0x80 == 0 {
				.head +=  + 1
				return int32(( >> 1) ^ -( & 1))
			}
			 += 7
			++
		}
		if  >= maxIntBufSize {
			.ReportError("ReadInt", "int overflow")
			return 0
		}
		.head += 
		 += 

		// We ran out of buffer and are not at the end of the int,
		// Read more into the buffer.
		if !.loadMore() {
			.Error = fmt.Errorf("reading int: %w", .Error)
			return 0
		}
	}
}

// ReadLong reads a Long from the Reader.
//
//nolint:dupl
func ( *Reader) () int64 {
	if .Error != nil {
		return 0
	}

	var (
		 int
		 uint64
		 uint8
	)

	for {
		 := .tail
		if .tail-.head+ > maxLongBufSize {
			 = .head + maxLongBufSize - 
		}

		// Consume what it is in the buffer.
		var  int
		for ,  := range .buf[.head:] {
			 |= uint64(&0x7f) << 
			if &0x80 == 0 {
				.head +=  + 1
				return int64(( >> 1) ^ -( & 1))
			}
			 += 7
			++
		}
		if  >= maxLongBufSize {
			.ReportError("ReadLong", "int overflow")
			return 0
		}
		.head += 
		 += 

		// We ran out of buffer and are not at the end of the long,
		// Read more into the buffer.
		if !.loadMore() {
			.Error = fmt.Errorf("reading long: %w", .Error)
			return 0
		}
	}
}

// ReadFloat reads a Float from the Reader.
func ( *Reader) () float32 {
	var  [4]byte
	.Read([:])

	 := *(*float32)(unsafe.Pointer(&[0]))
	return 
}

// ReadDouble reads a Double from the Reader.
func ( *Reader) () float64 {
	var  [8]byte
	.Read([:])

	 := *(*float64)(unsafe.Pointer(&[0]))
	return 
}

// ReadBytes reads Bytes from the Reader.
func ( *Reader) () []byte {
	return .readBytes("bytes")
}

// ReadString reads a String from the Reader.
func ( *Reader) () string {
	 := .readBytes("string")
	if len() == 0 {
		return ""
	}

	return *(*string)(unsafe.Pointer(&))
}

func ( *Reader) ( string) []byte {
	 := int(.ReadLong())
	if  < 0 {
		 := "Read" + strings.ToTitle()
		.ReportError(, "invalid "++" length")
		return nil
	}
	if  == 0 {
		return []byte{}
	}
	if  := .cfg.getMaxByteSliceSize();  > 0 &&  >  {
		 := "Read" + strings.ToTitle()
		.ReportError(, "size is greater than `Config.MaxByteSliceSize`")
		return nil
	}

	// The bytes are entirely in the buffer and of a reasonable size.
	// Use the byte slab.
	if .head+ <= .tail &&  <= 1024 {
		if cap(.slab) <  {
			.slab = make([]byte, 1024)
		}
		 := .slab[:]
		.slab = .slab[:]
		copy(, .buf[.head:.head+])
		.head += 
		return 
	}

	 := make([]byte, )
	.Read()
	return 
}

// ReadBlockHeader reads a Block Header from the Reader.
func ( *Reader) () (int64, int64) {
	 := .ReadLong()
	if  < 0 {
		 := .ReadLong()

		return -, 
	}

	return , 0
}