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

package telemetry // import "go.opentelemetry.io/otel/trace/internal/telemetry"

import (
	
	
	
	
	
	
	
	
	
	
	
)

// A Value represents a structured value.
// A zero value is valid and represents an empty value.
type Value struct {
	// Ensure forward compatibility by explicitly making this not comparable.
	noCmp [0]func() //nolint: unused  // This is indeed used.

	// num holds the value for Int64, Float64, and Bool. It holds the length
	// for String, Bytes, Slice, Map.
	num uint64
	// any holds either the KindBool, KindInt64, KindFloat64, stringptr,
	// bytesptr, sliceptr, or mapptr. If KindBool, KindInt64, or KindFloat64
	// then the value of Value is in num as described above. Otherwise, it
	// contains the value wrapped in the appropriate type.
	any any
}

type (
	// sliceptr represents a value in Value.any for KindString Values.
	stringptr *byte
	// bytesptr represents a value in Value.any for KindBytes Values.
	bytesptr *byte
	// sliceptr represents a value in Value.any for KindSlice Values.
	sliceptr *Value
	// mapptr represents a value in Value.any for KindMap Values.
	mapptr *Attr
)

// ValueKind is the kind of a [Value].
type ValueKind int

// ValueKind values.
const (
	ValueKindEmpty ValueKind = iota
	ValueKindBool
	ValueKindFloat64
	ValueKindInt64
	ValueKindString
	ValueKindBytes
	ValueKindSlice
	ValueKindMap
)

var valueKindStrings = []string{
	"Empty",
	"Bool",
	"Float64",
	"Int64",
	"String",
	"Bytes",
	"Slice",
	"Map",
}

func ( ValueKind) () string {
	if  >= 0 && int() < len(valueKindStrings) {
		return valueKindStrings[]
	}
	return "<unknown telemetry.ValueKind>"
}

// StringValue returns a new [Value] for a string.
func ( string) Value {
	return Value{
		num: uint64(len()),
		any: stringptr(unsafe.StringData()),
	}
}

// IntValue returns a [Value] for an int.
func ( int) Value { return Int64Value(int64()) }

// Int64Value returns a [Value] for an int64.
func ( int64) Value {
	return Value{
		num: uint64(), // nolint: gosec  // Store raw bytes.
		any: ValueKindInt64,
	}
}

// Float64Value returns a [Value] for a float64.
func ( float64) Value {
	return Value{num: math.Float64bits(), any: ValueKindFloat64}
}

// BoolValue returns a [Value] for a bool.
func ( bool) Value { //nolint:revive // Not a control flag.
	var  uint64
	if  {
		 = 1
	}
	return Value{num: , any: ValueKindBool}
}

// BytesValue returns a [Value] for a byte slice. The passed slice must not be
// changed after it is passed.
func ( []byte) Value {
	return Value{
		num: uint64(len()),
		any: bytesptr(unsafe.SliceData()),
	}
}

// SliceValue returns a [Value] for a slice of [Value]. The passed slice must
// not be changed after it is passed.
func ( ...Value) Value {
	return Value{
		num: uint64(len()),
		any: sliceptr(unsafe.SliceData()),
	}
}

// MapValue returns a new [Value] for a slice of key-value pairs. The passed
// slice must not be changed after it is passed.
func ( ...Attr) Value {
	return Value{
		num: uint64(len()),
		any: mapptr(unsafe.SliceData()),
	}
}

// AsString returns the value held by v as a string.
func ( Value) () string {
	if ,  := .any.(stringptr);  {
		return unsafe.String(, .num)
	}
	// TODO: error handle
	return ""
}

// asString returns the value held by v as a string. It will panic if the Value
// is not KindString.
func ( Value) () string {
	return unsafe.String(.any.(stringptr), .num)
}

// AsInt64 returns the value held by v as an int64.
func ( Value) () int64 {
	if .Kind() != ValueKindInt64 {
		// TODO: error handle
		return 0
	}
	return .asInt64()
}

// asInt64 returns the value held by v as an int64. If v is not of KindInt64,
// this will return garbage.
func ( Value) () int64 {
	// Assumes v.num was a valid int64 (overflow not checked).
	return int64(.num) // nolint: gosec
}

// AsBool returns the value held by v as a bool.
func ( Value) () bool {
	if .Kind() != ValueKindBool {
		// TODO: error handle
		return false
	}
	return .asBool()
}

// asBool returns the value held by v as a bool. If v is not of KindBool, this
// will return garbage.
func ( Value) () bool { return .num == 1 }

// AsFloat64 returns the value held by v as a float64.
func ( Value) () float64 {
	if .Kind() != ValueKindFloat64 {
		// TODO: error handle
		return 0
	}
	return .asFloat64()
}

// asFloat64 returns the value held by v as a float64. If v is not of
// KindFloat64, this will return garbage.
func ( Value) () float64 { return math.Float64frombits(.num) }

// AsBytes returns the value held by v as a []byte.
func ( Value) () []byte {
	if ,  := .any.(bytesptr);  {
		return unsafe.Slice((*byte)(), .num)
	}
	// TODO: error handle
	return nil
}

// asBytes returns the value held by v as a []byte. It will panic if the Value
// is not KindBytes.
func ( Value) () []byte {
	return unsafe.Slice((*byte)(.any.(bytesptr)), .num)
}

// AsSlice returns the value held by v as a []Value.
func ( Value) () []Value {
	if ,  := .any.(sliceptr);  {
		return unsafe.Slice((*Value)(), .num)
	}
	// TODO: error handle
	return nil
}

// asSlice returns the value held by v as a []Value. It will panic if the Value
// is not KindSlice.
func ( Value) () []Value {
	return unsafe.Slice((*Value)(.any.(sliceptr)), .num)
}

// AsMap returns the value held by v as a []Attr.
func ( Value) () []Attr {
	if ,  := .any.(mapptr);  {
		return unsafe.Slice((*Attr)(), .num)
	}
	// TODO: error handle
	return nil
}

// asMap returns the value held by v as a []Attr. It will panic if the
// Value is not KindMap.
func ( Value) () []Attr {
	return unsafe.Slice((*Attr)(.any.(mapptr)), .num)
}

// Kind returns the Kind of v.
func ( Value) () ValueKind {
	switch x := .any.(type) {
	case ValueKind:
		return 
	case stringptr:
		return ValueKindString
	case bytesptr:
		return ValueKindBytes
	case sliceptr:
		return ValueKindSlice
	case mapptr:
		return ValueKindMap
	default:
		return ValueKindEmpty
	}
}

// Empty reports whether v does not hold any value.
func ( Value) () bool { return .Kind() == ValueKindEmpty }

// Equal reports whether v is equal to w.
func ( Value) ( Value) bool {
	 := .Kind()
	 := .Kind()
	if  !=  {
		return false
	}
	switch  {
	case ValueKindInt64, ValueKindBool:
		return .num == .num
	case ValueKindString:
		return .asString() == .asString()
	case ValueKindFloat64:
		return .asFloat64() == .asFloat64()
	case ValueKindSlice:
		return slices.EqualFunc(.asSlice(), .asSlice(), Value.)
	case ValueKindMap:
		 := sortMap(.asMap())
		 := sortMap(.asMap())
		return slices.EqualFunc(, , Attr.Equal)
	case ValueKindBytes:
		return bytes.Equal(.asBytes(), .asBytes())
	case ValueKindEmpty:
		return true
	default:
		// TODO: error handle
		return false
	}
}

func sortMap( []Attr) []Attr {
	 := make([]Attr, len())
	copy(, )
	slices.SortFunc(, func(,  Attr) int {
		return cmp.Compare(.Key, .Key)
	})

	return 
}

// String returns Value's value as a string, formatted like [fmt.Sprint].
//
// The returned string is meant for debugging;
// the string representation is not stable.
func ( Value) () string {
	switch .Kind() {
	case ValueKindString:
		return .asString()
	case ValueKindInt64:
		// Assumes v.num was a valid int64 (overflow not checked).
		return strconv.FormatInt(int64(.num), 10) // nolint: gosec
	case ValueKindFloat64:
		return strconv.FormatFloat(.asFloat64(), 'g', -1, 64)
	case ValueKindBool:
		return strconv.FormatBool(.asBool())
	case ValueKindBytes:
		return string(.asBytes())
	case ValueKindMap:
		return fmt.Sprint(.asMap())
	case ValueKindSlice:
		return fmt.Sprint(.asSlice())
	case ValueKindEmpty:
		return "<nil>"
	default:
		// Try to handle this as gracefully as possible.
		//
		// Don't panic here. The goal here is to have developers find this
		// first if a slog.Kind is is not handled. It is
		// preferable to have user's open issue asking why their attributes
		// have a "unhandled: " prefix than say that their code is panicking.
		return fmt.Sprintf("<unhandled telemetry.ValueKind: %s>", .Kind())
	}
}

// MarshalJSON encodes v into OTLP formatted JSON.
func ( *Value) () ([]byte, error) {
	switch .Kind() {
	case ValueKindString:
		return json.Marshal(struct {
			 string `json:"stringValue"`
		}{.asString()})
	case ValueKindInt64:
		return json.Marshal(struct {
			 string `json:"intValue"`
		}{strconv.FormatInt(int64(.num), 10)}) // nolint: gosec  // From raw bytes.
	case ValueKindFloat64:
		return json.Marshal(struct {
			 float64 `json:"doubleValue"`
		}{.asFloat64()})
	case ValueKindBool:
		return json.Marshal(struct {
			 bool `json:"boolValue"`
		}{.asBool()})
	case ValueKindBytes:
		return json.Marshal(struct {
			 []byte `json:"bytesValue"`
		}{.asBytes()})
	case ValueKindMap:
		return json.Marshal(struct {
			 struct {
				 []Attr `json:"values"`
			} `json:"kvlistValue"`
		}{struct {
			 []Attr `json:"values"`
		}{.asMap()}})
	case ValueKindSlice:
		return json.Marshal(struct {
			 struct {
				 []Value `json:"values"`
			} `json:"arrayValue"`
		}{struct {
			 []Value `json:"values"`
		}{.asSlice()}})
	case ValueKindEmpty:
		return nil, nil
	default:
		return nil, fmt.Errorf("unknown Value kind: %s", .Kind().String())
	}
}

// UnmarshalJSON decodes the OTLP formatted JSON contained in data into v.
func ( *Value) ( []byte) error {
	 := json.NewDecoder(bytes.NewReader())

	,  := .Token()
	if  != nil {
		return 
	}
	if  != json.Delim('{') {
		return errors.New("invalid Value type")
	}

	for .More() {
		,  := .Token()
		if  != nil {
			if errors.Is(, io.EOF) {
				// Empty.
				return nil
			}
			return 
		}

		,  := .(string)
		if ! {
			return fmt.Errorf("invalid Value key: %#v", )
		}

		switch  {
		case "stringValue", "string_value":
			var  string
			 = .Decode(&)
			* = StringValue()
		case "boolValue", "bool_value":
			var  bool
			 = .Decode(&)
			* = BoolValue()
		case "intValue", "int_value":
			var  protoInt64
			 = .Decode(&)
			* = Int64Value(.Int64())
		case "doubleValue", "double_value":
			var  float64
			 = .Decode(&)
			* = Float64Value()
		case "bytesValue", "bytes_value":
			var  string
			if  := .Decode(&);  != nil {
				return 
			}
			var  []byte
			,  = base64.StdEncoding.DecodeString()
			* = BytesValue()
		case "arrayValue", "array_value":
			var  struct{  []Value }
			 = .Decode(&)
			* = SliceValue(....)
		case "kvlistValue", "kvlist_value":
			var  struct{  []Attr }
			 = .Decode(&)
			* = MapValue(....)
		default:
			// Skip unknown.
			continue
		}
		// Use first valid. Ignore the rest.
		return 
	}

	// Only unknown fields. Return nil without unmarshaling any value.
	return nil
}