// Copyright 2026 The Erigon Authors
// This file is part of Erigon.
//
// Erigon 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, either version 3 of the License, or
// (at your option) any later version.
//
// Erigon 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 Erigon. If not, see <http://www.gnu.org/licenses/>.

package app

import (
	"context"
	"reflect"

	"github.com/erigontech/erigon/node/app/util"
)

type Keys interface {
	Len() int

	IsArray() bool
	IsMap() bool
}

type KeyArray []any

func (keys KeyArray) Len() int {
	return len(keys)
}

func (keys KeyArray) IsArray() bool {
	return true
}

func (keys KeyArray) IsMap() bool {
	return false
}

type KeyMap map[any]any

func (keys KeyMap) Len() int {
	return len(keys)
}

func (keys KeyMap) IsArray() bool {
	return false
}

func (keys KeyMap) IsMap() bool {
	return true
}

type Selector interface {
	Test(context context.Context, entity any) bool
}

type KeyedSelector interface {
	Keys() Keys
	Test(context context.Context, entity any) bool
}

// SelectorComparator provides a basic comparison on selectors by comparing
// the values of the selectors keys
func SelectorComparator(a, b any) int {
	aKeys := a.(KeyedSelector).Keys()
	bKeys := b.(KeyedSelector).Keys()
	aArray, aOk := aKeys.(KeyArray)
	bArray, bOk := bKeys.(KeyArray)
	if aOk && bOk {
		return util.CompoundCompare([]any(aArray), []any(bArray))
	}
	return util.CompoundCompare(aKeys, bKeys)
}

type RangeSelector interface {
	From() Keys
	To() Keys
	Test(context context.Context, entity any) bool
}

const (
	// Unordered indicates the selection order is unimportant from the selectors
	// perspective.  If the underlying entities have a natural order due to thier
	// storage that may be returned but none is assumed.  T
	Unordered SelectOrder = 0
	// The returned entities should be returned in a forward order as defined by the
	// ordering of the entities selected
	Forward SelectOrder = 1
	// The returned entities should be returned in reverse order as defined by the
	// ordering of the entities selected
	Reverse SelectOrder = -1
)

// VersionType is a constant indicating the underlying type of
//
//	the Version represented by the base Version interface
type SelectOrder int

type Ordered interface {
	Order() SelectOrder
}

type OrderedSelector interface {
	Selector
	Ordered
}

type all struct{}

func (s all) Keys() Keys {
	return KeyArray(nil)
}

func (s all) Test(context context.Context, entity any) bool {
	return true
}

func (s all) CompareTo(entity any) int {
	switch entity.(type) {
	case all:
		return 0
	case none:
		return 1
	}
	return -1
}

type none struct{}

func (s none) Keys() Keys {
	return KeyArray(nil)
}

func (s none) Test(context context.Context, entity any) bool {
	return false
}

func (s none) CompareTo(entity any) int {
	if _, ok := entity.(*none); ok {
		return 0
	}

	return -1
}

var Selectors = struct {
	Any  all
	None none
}{
	Any:  all{},
	None: none{},
}

type TypedSelector interface {
	Selector
}

type TypeSelector struct {
	Type reflect.Type
}

func (selector *TypeSelector) Keys() Keys {
	return KeyArray{selector.Type}
}

func (selector *TypeSelector) Test(context context.Context, entity any) bool {
	if selector.Type != nil {
		return reflect.TypeOf(entity) == selector.Type
	}

	return true
}
