// Copyright (c) 2026 The elk-go Authors.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0.
//
// SPDX-License-Identifier: EPL-2.0

package javacompat

// OrderedMap is an insertion-ordered map matching LinkedHashMap's default
// (accessOrder=false) behavior. Replacing a value does not move its key;
// removing and reinserting a key appends it at the end.
//
// The zero value is ready to use.
type OrderedMap[ comparable,  any] struct {
	entries []orderedEntry[, ]
	index   map[]int
}

type orderedEntry[ comparable,  any] struct {
	key   
	value 
}

// NewOrderedMap constructs an empty insertion-ordered map.
func [ comparable,  any]() *OrderedMap[, ] {
	return &OrderedMap[, ]{index: make(map[]int)}
}

// Len returns the number of entries.
func ( *OrderedMap[, ]) () int { return len(.entries) }

// IsEmpty reports whether the map has no entries.
func ( *OrderedMap[, ]) () bool { return len(.entries) == 0 }

// Put inserts or replaces a value. It returns the old value and whether the
// key was already present.
func ( *OrderedMap[, ]) ( ,  ) (, bool) {
	if ,  := .index[];  {
		 := .entries[].value
		.entries[].value = 
		return , true
	}
	if .index == nil {
		.index = make(map[]int)
	}
	.index[] = len(.entries)
	.entries = append(.entries, orderedEntry[, ]{key: , value: })
	var  
	return , false
}

// PutIfAbsent inserts only when key is absent and returns the existing or new
// value plus whether an existing entry was found.
func ( *OrderedMap[, ]) ( ,  ) (, bool) {
	if ,  := .Get();  {
		return , true
	}
	.Put(, )
	return , false
}

// Get looks up a value.
func ( *OrderedMap[, ]) ( ) (, bool) {
	if ,  := .index[];  {
		return .entries[].value, true
	}
	var  
	return , false
}

// ContainsKey reports whether key is present.
func ( *OrderedMap[, ]) ( ) bool {
	,  := .index[]
	return 
}

// Remove deletes key, preserving the relative order of all remaining keys.
func ( *OrderedMap[, ]) ( ) (, bool) {
	,  := .index[]
	if ! {
		var  
		return , false
	}
	 := .entries[].value
	delete(.index, )
	copy(.entries[:], .entries[+1:])
	var  orderedEntry[, ]
	.entries[len(.entries)-1] = 
	.entries = .entries[:len(.entries)-1]
	for  := ;  < len(.entries); ++ {
		.index[.entries[].key] = 
	}
	return , true
}

// Clear removes all entries.
func ( *OrderedMap[, ]) () {
	clear(.entries)
	.entries = .entries[:0]
	clear(.index)
}

// Keys returns keys in insertion order.
func ( *OrderedMap[, ]) () [] {
	 := make([], len(.entries))
	for ,  := range .entries {
		[] = .key
	}
	return 
}

// Values returns values in key insertion order.
func ( *OrderedMap[, ]) () [] {
	 := make([], len(.entries))
	for ,  := range .entries {
		[] = .value
	}
	return 
}

// Range visits entries in insertion order until visit returns false.
// Structural mutation during Range is unsupported, matching Java iterator
// fail-fast semantics without exposing a concurrent-modification exception.
func ( *OrderedMap[, ]) ( func(, ) bool) {
	for ,  := range .entries {
		if !(.key, .value) {
			return
		}
	}
}

// First returns the oldest entry.
func ( *OrderedMap[, ]) () (, , bool) {
	if len(.entries) == 0 {
		var  
		var  
		return , , false
	}
	 := .entries[0]
	return .key, .value, true
}

// Last returns the newest entry.
func ( *OrderedMap[, ]) () (, , bool) {
	if len(.entries) == 0 {
		var  
		var  
		return , , false
	}
	 := .entries[len(.entries)-1]
	return .key, .value, true
}

// OrderedSet is an insertion-ordered set matching LinkedHashSet.
// The zero value is ready to use.
type OrderedSet[ comparable] struct {
	values OrderedMap[, struct{}]
}

// NewOrderedSet constructs an empty insertion-ordered set.
func [ comparable]() *OrderedSet[] { return &OrderedSet[]{} }

// Add inserts value and reports whether the set changed.
func ( *OrderedSet[]) ( ) bool {
	if .values.ContainsKey() {
		return false
	}
	.values.Put(, struct{}{})
	return true
}

// Contains reports whether value is present.
func ( *OrderedSet[]) ( ) bool { return .values.ContainsKey() }

// Remove deletes value and reports whether the set changed.
func ( *OrderedSet[]) ( ) bool {
	,  := .values.Remove()
	return 
}

// Len returns the number of values.
func ( *OrderedSet[]) () int { return .values.Len() }

// IsEmpty reports whether the set is empty.
func ( *OrderedSet[]) () bool { return .values.IsEmpty() }

// Clear removes every value.
func ( *OrderedSet[]) () { .values.Clear() }

// Values returns values in insertion order.
func ( *OrderedSet[]) () [] { return .values.Keys() }

// Range visits values in insertion order until visit returns false.
func ( *OrderedSet[]) ( func() bool) {
	.values.Range(func( ,  struct{}) bool { return () })
}