/*
 * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
 * SPDX-License-Identifier: Apache-2.0
 */

package table

import (
	

	
)

// MergeIterator merges multiple iterators.
// NOTE: MergeIterator owns the array of iterators and is responsible for closing them.
type MergeIterator struct {
	left  node
	right node
	small *node

	curKey  []byte
	reverse bool
}

type node struct {
	valid bool
	key   []byte
	iter  y.Iterator

	// The two iterators are type asserted from `y.Iterator`, used to inline more function calls.
	// Calling functions on concrete types is much faster (about 25-30%) than calling the
	// interface's function.
	merge  *MergeIterator
	concat *ConcatIterator
}

func ( *node) ( y.Iterator) {
	.iter = 
	// It's okay if the type assertion below fails and n.merge/n.concat are set to nil.
	// We handle the nil values of merge and concat in all the methods.
	.merge, _ = .(*MergeIterator)
	.concat, _ = .(*ConcatIterator)
}

func ( *node) () {
	switch {
	case .merge != nil:
		.valid = .merge.small.valid
		if .valid {
			.key = .merge.small.key
		}
	case .concat != nil:
		.valid = .concat.Valid()
		if .valid {
			.key = .concat.Key()
		}
	default:
		.valid = .iter.Valid()
		if .valid {
			.key = .iter.Key()
		}
	}
}

func ( *node) () {
	switch {
	case .merge != nil:
		.merge.Next()
	case .concat != nil:
		.concat.Next()
	default:
		.iter.Next()
	}
	.setKey()
}

func ( *node) () {
	.iter.Rewind()
	.setKey()
}

func ( *node) ( []byte) {
	.iter.Seek()
	.setKey()
}

func ( *MergeIterator) () {
	if !.bigger().valid {
		return
	}
	if !.small.valid {
		.swapSmall()
		return
	}
	 := y.CompareKeys(.small.key, .bigger().key)
	switch {
	case  == 0: // Both the keys are equal.
		// In case of same keys, move the right iterator ahead.
		.right.next()
		if &.right == .small {
			.swapSmall()
		}
		return
	case  < 0: // Small is less than bigger().
		if .reverse {
			.swapSmall()
		} else { //nolint:staticcheck
			// we don't need to do anything. Small already points to the smallest.
		}
		return
	default: // bigger() is less than small.
		if .reverse {
			// Do nothing since we're iterating in reverse. Small currently points to
			// the bigger key and that's okay in reverse iteration.
		} else {
			.swapSmall()
		}
		return
	}
}

func ( *MergeIterator) () *node {
	if .small == &.left {
		return &.right
	}
	return &.left
}

func ( *MergeIterator) () {
	if .small == &.left {
		.small = &.right
		return
	}
	if .small == &.right {
		.small = &.left
		return
	}
}

// Next returns the next element. If it is the same as the current key, ignore it.
func ( *MergeIterator) () {
	for .Valid() {
		if !bytes.Equal(.small.key, .curKey) {
			break
		}
		.small.next()
		.fix()
	}
	.setCurrent()
}

func ( *MergeIterator) () {
	.curKey = append(.curKey[:0], .small.key...)
}

// Rewind seeks to first element (or last element for reverse iterator).
func ( *MergeIterator) () {
	.left.rewind()
	.right.rewind()
	.fix()
	.setCurrent()
}

// Seek brings us to element with key >= given key.
func ( *MergeIterator) ( []byte) {
	.left.seek()
	.right.seek()
	.fix()
	.setCurrent()
}

// Valid returns whether the MergeIterator is at a valid element.
func ( *MergeIterator) () bool {
	return .small.valid
}

// Key returns the key associated with the current iterator.
func ( *MergeIterator) () []byte {
	return .small.key
}

// Value returns the value associated with the iterator.
func ( *MergeIterator) () y.ValueStruct {
	return .small.iter.Value()
}

// Close implements y.Iterator.
func ( *MergeIterator) () error {
	 := .left.iter.Close()
	 := .right.iter.Close()
	if  != nil {
		return y.Wrap(, "MergeIterator")
	}
	return y.Wrap(, "MergeIterator")
}

// NewMergeIterator creates a merge iterator.
func ( []y.Iterator,  bool) y.Iterator {
	switch len() {
	case 0:
		return nil
	case 1:
		return [0]
	case 2:
		 := &MergeIterator{
			reverse: ,
		}
		.left.setIterator([0])
		.right.setIterator([1])
		// Assign left iterator randomly. This will be fixed when user calls rewind/seek.
		.small = &.left
		return 
	}
	 := len() / 2
	return (
		[]y.Iterator{
			([:], ),
			([:], ),
		}, )
}