// KEKS -- Go KEKS codec implementation
// Copyright (C) 2024-2025 Sergey Matveev <stargrave@stargrave.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program.  If not, see <http://www.gnu.org/licenses/>.

package keks

import (
	"io"
	"math/big"

	"go.cypherpunks.su/keks/types"
	"go.cypherpunks.su/tai64n/v4"
)

type DecodeOpts struct {
	// Maximal allowable string length. 0 means no limits, but pay
	// attention that if there is no sufficient memory available,
	// then Go may panic.
	MaxStrLen int64

	// Maximal allowable lists/maps length. 0 means no limits.
	MaxContLen int64

	// Disable UTF-8 codepoints validation check.
	DisableUTF8Check bool

	// Leave TAI64* values as is, do not convert to time.Time during unmarshal.
	LeaveTAI64 bool

	// Do not convert TAI to UTC.
	LeaveTAI bool

	// Store items offsets.
	SaveOffsets bool
}

type Decoder struct {
	R io.Reader
	B []byte

	opts *DecodeOpts

	types   []types.Type
	depths  []int8
	offsets []int64

	bigints  []*big.Int
	bools    []bool
	ints     []int64
	lens     []int
	rawTypes []AtomType
	strs     []string
	tai64nas []tai64n.TAI64NA
	tai64ns  []tai64n.TAI64N
	tai64s   []tai64n.TAI64
	uints    []uint64
	hexlets  []*Hexlet
	floats   []*Float

	blobChunkLens []int64
	blobChunkses  [][]string

	readBuf []byte // used only by BlobDecoder

	// After successful parsing of the data, it tells how many bytes
	// were read.
	Read int64

	depth int8
}

// Initialise decoder that will read from b bytes. After the parse,
// d.B will keep the remaining unread portion of unprocessed data.
// Pay attention, that decoded strings and byte slices will reference
// the original bytes buffer, that is why it is much more faster decoder.
func NewDecoderFromBytes(b []byte, opts *DecodeOpts) (d *Decoder) {
	return &Decoder{B: b, opts: opts}
}

// Initialise decoder that will read from r reader.
func NewDecoderFromReader(r io.Reader, opts *DecodeOpts) (d *Decoder) {
	return &Decoder{R: r, opts: opts}
}
