package log

import (
	
	
	
	
)

// Kind enumerates the dynamic type stored in a [Value].
type Kind uint8

// Value kinds.
const (
	KindAny Kind = iota
	KindString
	KindInt64
	KindUint64
	KindFloat64
	KindBool
	KindDuration
	KindTime
	KindError
	KindGroup
)

// Attr is a key-value pair attached to a log record.
type Attr struct {
	Key   string
	Value Value
}

// Value holds an attribute value without boxing scalar kinds into an interface.
//
// num carries int64/uint64/float64/bool/duration bits; s carries strings; a
// carries the boxed value for KindAny, KindTime and KindError. It is modeled on
// slog.Value but kept deliberately small and explicit.
type Value struct {
	kind Kind
	num  uint64
	s    string
	a    any
}

// Kind returns the value's kind.
func ( Value) () Kind { return .kind }

// Int64 returns the value as int64. Valid for KindInt64 and KindDuration.
func ( Value) () int64 { return int64(.num) }

// Uint64 returns the value as uint64. Valid for KindUint64.
func ( Value) () uint64 { return .num }

// Float64 returns the value as float64. Valid for KindFloat64.
func ( Value) () float64 { return math.Float64frombits(.num) }

// Bool returns the value as bool. Valid for KindBool.
func ( Value) () bool { return .num != 0 }

// Duration returns the value as time.Duration. Valid for KindDuration.
func ( Value) () time.Duration { return time.Duration(int64(.num)) }

// Time returns the value as time.Time, or the zero time. Valid for KindTime.
func ( Value) () time.Time {
	,  := .a.(time.Time)
	return 
}

// Error returns the value as error, or nil. Valid for KindError.
func ( Value) () error {
	,  := .a.(error)
	return 
}

// Group returns the value's child attributes, or nil. Valid for KindGroup.
func ( Value) () []Attr {
	,  := .a.([]Attr)
	return 
}

// Any returns the value boxed into an interface, regardless of kind.
func ( Value) () any {
	switch .kind {
	case KindString:
		return .s
	case KindInt64:
		return int64(.num)
	case KindUint64:
		return .num
	case KindFloat64:
		return math.Float64frombits(.num)
	case KindBool:
		return .num != 0
	case KindDuration:
		return time.Duration(int64(.num))
	case KindTime:
		return .Time()
	case KindError:
		return .Error()
	case KindGroup:
		return .Group()
	default:
		return .a
	}
}

// String renders the value to a string. For KindString it returns the string
// unchanged, so Value also satisfies fmt.Stringer.
func ( Value) () string {
	switch .kind {
	case KindString:
		return .s
	case KindInt64:
		return strconv.FormatInt(int64(.num), 10)
	case KindUint64:
		return strconv.FormatUint(.num, 10)
	case KindFloat64:
		return strconv.FormatFloat(math.Float64frombits(.num), 'g', -1, 64)
	case KindBool:
		return strconv.FormatBool(.num != 0)
	case KindDuration:
		return time.Duration(int64(.num)).String()
	case KindTime:
		return .Time().String()
	case KindError:
		if  := .Error();  != nil {
			return .Error()
		}
		return "<nil>"
	case KindGroup:
		return fmt.Sprint(.Group())
	default:
		return fmt.Sprint(.a)
	}
}

// String returns a string Attr.
func (,  string) Attr {
	return Attr{Key: , Value: Value{kind: KindString, s: }}
}

// Int returns an int Attr, stored as int64.
func ( string,  int) Attr {
	return Int64(, int64())
}

// Int64 returns an int64 Attr.
func ( string,  int64) Attr {
	return Attr{Key: , Value: Value{kind: KindInt64, num: uint64()}}
}

// Uint64 returns a uint64 Attr.
func ( string,  uint64) Attr {
	return Attr{Key: , Value: Value{kind: KindUint64, num: }}
}

// Float64 returns a float64 Attr.
func ( string,  float64) Attr {
	return Attr{Key: , Value: Value{kind: KindFloat64, num: math.Float64bits()}}
}

// Bool returns a bool Attr.
func ( string,  bool) Attr {
	var  uint64
	if  {
		 = 1
	}
	return Attr{Key: , Value: Value{kind: KindBool, num: }}
}

// Duration returns a time.Duration Attr.
func ( string,  time.Duration) Attr {
	return Attr{Key: , Value: Value{kind: KindDuration, num: uint64()}}
}

// Time returns a time.Time Attr.
func ( string,  time.Time) Attr {
	return Attr{Key: , Value: Value{kind: KindTime, a: }}
}

// Error returns an Attr with the conventional key "error". A nil err is kept as
// a nil-valued error Attr.
func ( error) Attr {
	return Attr{Key: "error", Value: Value{kind: KindError, a: }}
}

// Int32 returns an int32 Attr, stored as int64.
func ( string,  int32) Attr {
	return Int64(, int64())
}

// NamedError returns an error Attr under an explicit key. Unlike Error, which
// uses the conventional "error" key, this lets callers name the field.
func ( string,  error) Attr {
	return Attr{Key: , Value: Value{kind: KindError, a: }}
}

// Stringer returns an Attr holding value.String(). A nil Stringer yields the
// string "<nil>".
func ( string,  fmt.Stringer) Attr {
	if  == nil {
		return String(, "<nil>")
	}
	return String(, .String())
}

// Group returns an Attr whose value is the given child attributes. Adapters
// render it as a nested object. As a special case, an empty key inlines the
// children into the parent (like log/slog), matching zap's Inline.
func ( string,  ...Attr) Attr {
	return Attr{Key: , Value: Value{kind: KindGroup, a: }}
}

// Any returns an Attr holding an arbitrary value. Prefer the typed constructors
// for scalars: Any boxes the value into an interface.
func ( string,  any) Attr {
	return Attr{Key: , Value: Value{kind: KindAny, a: }}
}