// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

// DO NOT MODIFY. Generated by gotmpl.
// source: internal/shared/attrnorm/dedup.go.tmpl

// Package attrnorm normalizes attribute values.
package attrnorm

import (
	"reflect"
	"unsafe"

	"go.opentelemetry.io/otel/attribute"
)

var (
	keyValueType = reflect.TypeFor[attribute.KeyValue]()
	valueType    = reflect.TypeFor[attribute.Value]()
)

// rawValue mirrors attribute.Value. It is used only to read immutable slice
// storage without calling AsMap or AsSlice on no-op paths.
type rawValue struct {
	vtype    attribute.Type
	numeric  uint64
	stringly string
	slice    any
}

// Value returns value with all map values deduplicated and whether it changed.
//
// Duplicate map keys are resolved using last-value-wins semantics.
func Value(value attribute.Value) (attribute.Value, bool) {
	switch value.Type() {
	case attribute.SLICE:
		return deduplicateSliceValue(value)
	case attribute.MAP:
		return deduplicateMapValue(value)
	default:
		return value, false
	}
}

// KeyValue returns kv with all map values deduplicated and whether it changed.
func KeyValue(kv attribute.KeyValue) (attribute.KeyValue, bool) {
	value, changed := Value(kv.Value)
	if changed {
		kv.Value = value
	}
	return kv, changed
}

// KeyValues returns kvs with all map values deduplicated and whether they changed.
//
// The returned slice is the original kvs slice if no value needs
// deduplication. Top-level keys in kvs are not deduplicated.
func KeyValues(kvs []attribute.KeyValue) ([]attribute.KeyValue, bool) {
	// Preserve the caller's slice on the common no-op path. Once a changed
	// value is found, copy the prior values exactly once and fill the rest in
	// place as the scan continues.
	var normalized []attribute.KeyValue
	for i, kv := range kvs {
		kv, changed := KeyValue(kv)
		if normalized != nil {
			normalized[i] = kv
			continue
		}
		if !changed {
			continue
		}

		normalized = make([]attribute.KeyValue, len(kvs))
		copy(normalized, kvs[:i])
		normalized[i] = kv
	}
	if normalized == nil {
		return kvs, false
	}
	return normalized, true
}

// Set returns set with all map values deduplicated and whether it changed.
//
// The returned Set is the original set if no value needs deduplication.
// Top-level key uniqueness remains attribute.Set's responsibility; this only
// normalizes map attribute values.
func Set(set attribute.Set) (attribute.Set, bool) {
	if set.Len() == 0 {
		return set, false
	}

	// Most attribute sets contain no duplicate map keys. Delay allocation until
	// the first changed value so the no-op path returns the original Set.
	var normalized []attribute.KeyValue
	for i := range set.Len() {
		kv, _ := set.Get(i)
		kv, changed := KeyValue(kv)
		if normalized != nil {
			normalized = append(normalized, kv)
			continue
		}
		if !changed {
			continue
		}

		normalized = make([]attribute.KeyValue, 0, set.Len())
		for j := range i {
			prior, _ := set.Get(j)
			normalized = append(normalized, prior)
		}
		normalized = append(normalized, kv)
	}
	if normalized == nil {
		return set, false
	}

	return attribute.NewSet(normalized...), true
}

func deduplicateSliceValue(value attribute.Value) (attribute.Value, bool) {
	storage := valueStorage(value)
	length := valueLen(storage)

	// Slice values can contain map values, so recurse into each element while
	// keeping the original attribute.Value when no element changes.
	var normalized []attribute.Value
	for i := range length {
		elem := valueAt(storage, i)
		elem, changed := Value(elem)
		if normalized != nil {
			normalized[i] = elem
			continue
		}
		if !changed {
			continue
		}

		normalized = make([]attribute.Value, length)
		for j := range i {
			normalized[j] = valueAt(storage, j)
		}
		normalized[i] = elem
	}
	if normalized == nil {
		return value, false
	}
	return attribute.SliceValue(normalized...), true
}

func deduplicateMapValue(value attribute.Value) (attribute.Value, bool) {
	storage := valueStorage(value)
	length := keyValueLen(storage)
	if length <= 1 {
		// A single map entry cannot duplicate its own key, but its value might
		// contain a map or slice that needs recursive normalization.
		if length == 1 {
			kv, changed := KeyValue(keyValueAt(storage, 0))
			if changed {
				return attribute.MapValue(kv), true
			}
		}
		return value, false
	}

	var normalized []attribute.KeyValue
	for i := 0; i < length; {
		// attribute.MapValue stores key-values sorted by key using a stable
		// sort. Equal keys therefore form a contiguous run, and the last
		// element in that run is the last value provided by the caller.
		first := keyValueAt(storage, i)
		j := i + 1
		for j < length && keyValueAt(storage, j).Key == first.Key {
			j++
		}

		kv, nestedChanged := KeyValue(keyValueAt(storage, j-1))
		// j-i > 1 means the current key run contained duplicates.
		changed := nestedChanged || j-i > 1
		if normalized != nil {
			normalized = append(normalized, kv)
		} else if changed {
			normalized = make([]attribute.KeyValue, 0, length)
			for k := range i {
				normalized = append(normalized, keyValueAt(storage, k))
			}
			normalized = append(normalized, kv)
		}
		i = j
	}
	if normalized == nil {
		return value, false
	}
	return attribute.MapValue(normalized...), true
}

func valueStorage(value attribute.Value) any {
	// attribute.Value does not expose allocation-free map/slice iteration.
	// The raw mirror lets us read the immutable backing array directly and
	// reserve AsMap/AsSlice-style allocation for paths that actually change.
	return (*rawValue)(
		unsafe.Pointer(&value),
	).slice //nolint:gosec // Read-only mirror of attribute.Value for allocation-free iteration.
}

func valueLen(storage any) int {
	// attribute.Value stores small slices in fixed-size array values. Handle
	// the common sizes directly and fall back to reflection for larger arrays.
	switch storage.(type) {
	case [0]attribute.Value:
		return 0
	case [1]attribute.Value:
		return 1
	case [2]attribute.Value:
		return 2
	case [3]attribute.Value:
		return 3
	case [4]attribute.Value:
		return 4
	case [5]attribute.Value:
		return 5
	default:
		return arrayLen(storage, valueType)
	}
}

func valueAt(storage any, i int) attribute.Value {
	switch values := storage.(type) {
	case [1]attribute.Value:
		return values[i]
	case [2]attribute.Value:
		return values[i]
	case [3]attribute.Value:
		return values[i]
	case [4]attribute.Value:
		return values[i]
	case [5]attribute.Value:
		return values[i]
	default:
		return arrayAt[attribute.Value](storage, valueType, i)
	}
}

func keyValueLen(storage any) int {
	// attribute.Value stores small maps in fixed-size key-value arrays. Handle
	// the common sizes directly and fall back to reflection for larger arrays.
	switch storage.(type) {
	case [0]attribute.KeyValue:
		return 0
	case [1]attribute.KeyValue:
		return 1
	case [2]attribute.KeyValue:
		return 2
	case [3]attribute.KeyValue:
		return 3
	case [4]attribute.KeyValue:
		return 4
	case [5]attribute.KeyValue:
		return 5
	default:
		return arrayLen(storage, keyValueType)
	}
}

func keyValueAt(storage any, i int) attribute.KeyValue {
	switch kvs := storage.(type) {
	case [1]attribute.KeyValue:
		return kvs[i]
	case [2]attribute.KeyValue:
		return kvs[i]
	case [3]attribute.KeyValue:
		return kvs[i]
	case [4]attribute.KeyValue:
		return kvs[i]
	case [5]attribute.KeyValue:
		return kvs[i]
	default:
		return arrayAt[attribute.KeyValue](storage, keyValueType, i)
	}
}

func arrayLen(storage any, elem reflect.Type) int {
	// Be defensive around invalid or unexpected Value storage. Returning zero
	// makes malformed storage a no-op instead of panicking in telemetry paths.
	array := reflect.ValueOf(storage)
	if array.Kind() != reflect.Array || array.Type().Elem() != elem {
		return 0
	}
	return array.Len()
}

func arrayAt[T any](storage any, elem reflect.Type, i int) T {
	// Match arrayLen's fail-closed behavior for unexpected storage.
	array := reflect.ValueOf(storage)
	if array.Kind() != reflect.Array || array.Type().Elem() != elem || i < 0 || i >= array.Len() {
		var zero T
		return zero
	}
	return array.Index(i).Interface().(T)
}
