///|
/// Shared attribute key used across traces, logs, metrics, and resources.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/#attribute
pub struct Key {
  name : String
} derive(Eq, Compare, Hash, ToJson, Debug)

///|
/// Creates a key from its canonical string representation.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/#attribute
pub fn Key::new(name : StringView) -> Key {
  { name: name.to_owned() }
}

///|
/// Returns the original key name.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/#attribute
pub fn Key::as_string(self : Key) -> String {
  self.name
}

///|
pub impl Default for Key with fn default() -> Key {
  Key::new("")
}

///|
/// Attribute value supported by this SDK implementation.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/#anyvalue
pub(all) enum Value {
  Bool(Bool)
  Int64(Int64)
  Double(Double)
  String(String)
  Bytes(Bytes)
  Array(Array[Value])
} derive(Eq, Compare, Hash, ToJson, Debug)

///|
/// Pair of attribute key and value.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/#attribute
pub struct KeyValue {
  key : Key
  value : Value
} derive(Eq, Compare, Hash, ToJson, Debug)

///|
/// Creates a key/value pair using a string key.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/#attribute
pub fn KeyValue::new(key : StringView, value : Value) -> KeyValue {
  { key: Key::new(key), value }
}

///|
/// Parsed representation of the W3C `tracestate` header.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracestate
pub struct TraceState {
  entries : Map[String, String]
} derive(Eq, ToJson, Debug)

///|
/// Creates trace state from a full entry map.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracestate
pub fn TraceState::new(entries : Map[String, String]) -> TraceState {
  { entries, }
}

///|
/// Returns an empty trace state.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracestate
pub fn TraceState::empty() -> TraceState {
  { entries: {} }
}

///|
/// Looks up one trace state member by key.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracestate
pub fn TraceState::get(self : TraceState, key : StringView) -> String? {
  self.entries.get_from_string(key)
}

///|
/// Returns a copy with one key updated or inserted.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracestate
pub fn TraceState::set(
  self : TraceState,
  key : StringView,
  value : StringView,
) -> TraceState {
  let entries = self.entries.copy()
  entries[key.to_owned()] = value.to_owned()
  { entries, }
}

///|
/// Returns a copy of all trace state entries.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracestate
pub fn TraceState::entries(self : TraceState) -> Map[String, String] {
  self.entries.copy()
}

///|
/// Serializes the trace state into a `tracestate` header value.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracestate
pub fn TraceState::to_header(self : TraceState) -> String? {
  if self.entries.is_empty() {
    return None
  }
  let builder = StringBuilder::new()
  let mut is_first = true
  for key, value in self.entries {
    if !is_first {
      builder.write_char(',')
    }
    is_first = false
    builder.write_string(key)
    builder.write_char('=')
    builder.write_string(value)
  }
  Some(builder.to_string())
}

///|
/// Parses a `tracestate` header value, ignoring malformed members.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracestate
pub fn TraceState::from_header(value : StringView) -> TraceState {
  let entries : Map[String, String] = {}
  for item in value.split(",") {
    let item = item.trim()
    if item.is_empty() {
      continue
    }
    guard item.find("=") is Some(index)
    let key = item[:index].trim().to_owned()
    let val = item[index + 1:].trim().to_owned()
    if key != "" && val != "" {
      entries[key] = val
    }
  }
  { entries, }
}

///|
pub impl Default for TraceState with fn default() -> TraceState {
  TraceState::empty()
}

///|
/// Low 8 bits of the W3C trace flags field.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub struct TraceFlags {
  flags : UInt
} derive(Eq, Compare, Hash, ToJson, Debug)

///|
/// Creates trace flags while masking away bits outside the W3C byte.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn TraceFlags::new(flags : UInt) -> TraceFlags {
  { flags: flags & 0xffU }
}

///|
/// Returns whether the sampled bit is set.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn TraceFlags::is_sampled(self : TraceFlags) -> Bool {
  (self.flags & 0x1U) == 0x1U
}

///|
/// Returns a copy with the sampled bit toggled.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn TraceFlags::with_sampled(
  self : TraceFlags,
  sampled : Bool,
) -> TraceFlags {
  if sampled {
    TraceFlags::new(self.flags | 0x1U)
  } else {
    TraceFlags::new(self.flags & 0xfeU)
  }
}

///|
/// Serializes trace flags into the two-character lowercase hex form used by
/// `traceparent`.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn TraceFlags::to_hex(self : TraceFlags) -> String {
  let hex = self.flags.reinterpret_as_int().to_string(radix=16)
  if self.flags < 16U {
    "0" + hex
  } else {
    hex
  }
}

///|
/// Parses the two-character lowercase or uppercase hex form used by
/// `traceparent`.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn TraceFlags::from_hex(value : StringView) -> TraceFlags? {
  if value.length() != 2 {
    return None
  }
  let parsed = @string.parse_int(value.to_owned(), base=16) catch {
    _ => return None
  }
  Some(TraceFlags::new(parsed.reinterpret_as_uint()))
}

///|
pub impl Default for TraceFlags with fn default() -> TraceFlags {
  TraceFlags::new(0U)
}

///|
/// 16-byte trace identifier.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub struct TraceId {
  bytes : Bytes
} derive(Eq, Compare, Hash, ToJson, Debug)

///|
/// 8-byte span identifier.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub struct SpanId {
  bytes : Bytes
} derive(Eq, Compare, Hash, ToJson, Debug)

///|
fn all_zero(bytes : Bytes) -> Bool {
  for byte in bytes {
    if byte != b'\x00' {
      break false
    }
  } nobreak {
    true
  }
}

///|
fn encode_hex(bytes : Bytes) -> String {
  let builder = StringBuilder::new()
  for byte in bytes {
    let value = byte.to_int()
    if value < 16 {
      builder.write_char('0')
    }
    builder.write_string(value.to_string(radix=16))
  }
  builder.to_string()
}

///|
fn decode_hex(hex : StringView, expected_len : Int) -> Bytes? {
  if hex.length() != expected_len * 2 {
    return None
  }
  let bytes = []
  for i = 0; i < hex.length(); i = i + 2 {
    let part = hex[i:i + 2].to_owned()
    let value = @string.parse_int(part, base=16) catch { _ => return None }
    bytes.push(value.to_byte())
  }
  Some(Bytes::from_array(bytes))
}

///|
/// Returns the invalid all-zero trace ID.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn TraceId::invalid() -> TraceId {
  { bytes: Bytes::make(16, b'\x00') }
}

///|
/// Creates a trace ID from raw bytes when the width is correct.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
pub fn TraceId::from_bytes(bytes : Bytes) -> TraceId? {
  if bytes.length() != 16 {
    None
  } else {
    Some({ bytes, })
  }
}

///|
/// Parses a 32-character hexadecimal trace ID.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
pub fn TraceId::from_hex(hex : StringView) -> TraceId? {
  decode_hex(hex, 16).map(bytes => { bytes, })
}

///|
/// Returns the lowercase hexadecimal representation of this trace ID.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
pub fn TraceId::to_hex(self : TraceId) -> String {
  encode_hex(self.bytes)
}

///|
/// Returns the raw bytes backing this trace ID.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
pub fn TraceId::bytes(self : TraceId) -> Bytes {
  self.bytes
}

///|
/// Reports whether this trace ID has the correct width and is not all zeros.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#isvalid
pub fn TraceId::is_valid(self : TraceId) -> Bool {
  self.bytes.length() == 16 && !all_zero(self.bytes)
}

///|
pub impl Default for TraceId with fn default() -> TraceId {
  TraceId::invalid()
}

///|
/// Returns the invalid all-zero span ID.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn SpanId::invalid() -> SpanId {
  { bytes: Bytes::make(8, b'\x00') }
}

///|
/// Creates a span ID from raw bytes when the width is correct.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
pub fn SpanId::from_bytes(bytes : Bytes) -> SpanId? {
  if bytes.length() != 8 {
    None
  } else {
    Some({ bytes, })
  }
}

///|
/// Parses a 16-character hexadecimal span ID.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
pub fn SpanId::from_hex(hex : StringView) -> SpanId? {
  decode_hex(hex, 8).map(bytes => { bytes, })
}

///|
/// Returns the lowercase hexadecimal representation of this span ID.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
pub fn SpanId::to_hex(self : SpanId) -> String {
  encode_hex(self.bytes)
}

///|
/// Returns the raw bytes backing this span ID.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
pub fn SpanId::bytes(self : SpanId) -> Bytes {
  self.bytes
}

///|
/// Reports whether this span ID has the correct width and is not all zeros.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#isvalid
pub fn SpanId::is_valid(self : SpanId) -> Bool {
  self.bytes.length() == 8 && !all_zero(self.bytes)
}

///|
pub impl Default for SpanId with fn default() -> SpanId {
  SpanId::invalid()
}

///|
/// Immutable span identity and propagation state carried in contexts, spans,
/// logs, and links.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub struct SpanContext {
  trace_id : TraceId
  span_id : SpanId
  trace_flags : TraceFlags
  is_remote : Bool
  trace_state : TraceState
} derive(Eq, ToJson, Debug)

///|
/// Creates a span context with explicit trace identity, flags, and state.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn SpanContext::new(
  trace_id : TraceId,
  span_id : SpanId,
  trace_flags? : TraceFlags = Default::default(),
  is_remote? : Bool = false,
  trace_state? : TraceState = Default::default(),
) -> SpanContext {
  { trace_id, span_id, trace_flags, is_remote, trace_state }
}

///|
/// Returns an empty invalid span context.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn SpanContext::empty() -> SpanContext {
  SpanContext::new(TraceId::invalid(), SpanId::invalid())
}

///|
/// Returns the trace ID.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
pub fn SpanContext::trace_id(self : SpanContext) -> TraceId {
  self.trace_id
}

///|
/// Returns the span ID.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
pub fn SpanContext::span_id(self : SpanContext) -> SpanId {
  self.span_id
}

///|
/// Returns the trace flags.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn SpanContext::trace_flags(self : SpanContext) -> TraceFlags {
  self.trace_flags
}

///|
/// Returns the trace state.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracestate
pub fn SpanContext::trace_state(self : SpanContext) -> TraceState {
  self.trace_state
}

///|
/// Returns whether this context came from an inbound carrier.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#isremote
pub fn SpanContext::is_remote(self : SpanContext) -> Bool {
  self.is_remote
}

///|
/// Reports whether both trace ID and span ID are valid.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#isvalid
pub fn SpanContext::is_valid(self : SpanContext) -> Bool {
  self.trace_id.is_valid() && self.span_id.is_valid()
}

///|
/// Reports whether the sampled bit is set.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spancontext
pub fn SpanContext::is_sampled(self : SpanContext) -> Bool {
  self.trace_flags.is_sampled()
}

///|
/// Returns a copy with the remote/local marker updated.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#isremote
pub fn SpanContext::with_remote(
  self : SpanContext,
  is_remote : Bool,
) -> SpanContext {
  { ..self, is_remote, }
}

///|
pub impl Default for SpanContext with fn default() -> SpanContext {
  SpanContext::empty()
}

///|
/// Identifies the instrumentation library or component that produced telemetry.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub struct InstrumentationScope {
  name : String
  version : String?
  schema_url : String?
  attributes : Array[KeyValue]
} derive(Eq, Compare, Hash, ToJson, Debug)

///|
/// Builder for `InstrumentationScope`.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub struct InstrumentationScopeBuilder {
  name : String
  mut version : String?
  mut schema_url : String?
  mut attributes : Array[KeyValue]
}

///|
/// Starts building an instrumentation scope for the given library name.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub fn InstrumentationScope::builder(
  name : StringView,
) -> InstrumentationScopeBuilder {
  { name: name.to_owned(), version: None, schema_url: None, attributes: [] }
}

///|
/// Returns the scope name.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub fn InstrumentationScope::name(self : InstrumentationScope) -> String {
  self.name
}

///|
/// Returns the optional scope version.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub fn InstrumentationScope::version(self : InstrumentationScope) -> String? {
  self.version
}

///|
/// Returns the optional schema URL applied to telemetry from this scope.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub fn InstrumentationScope::schema_url(self : InstrumentationScope) -> String? {
  self.schema_url
}

///|
/// Returns the scope attributes.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub fn InstrumentationScope::attributes(
  self : InstrumentationScope,
) -> Array[KeyValue] {
  self.attributes
}

///|
/// Sets the instrumentation library version.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub fn InstrumentationScopeBuilder::with_version(
  self : InstrumentationScopeBuilder,
  version : StringView,
) -> InstrumentationScopeBuilder {
  self.version = Some(version.to_owned())
  self
}

///|
/// Sets the schema URL attached to this scope.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub fn InstrumentationScopeBuilder::with_schema_url(
  self : InstrumentationScopeBuilder,
  schema_url : StringView,
) -> InstrumentationScopeBuilder {
  self.schema_url = Some(schema_url.to_owned())
  self
}

///|
/// Sets the attributes attached to this scope.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub fn InstrumentationScopeBuilder::with_attributes(
  self : InstrumentationScopeBuilder,
  attributes : ArrayView[KeyValue],
) -> InstrumentationScopeBuilder {
  self.attributes = attributes.to_owned()
  self
}

///|
/// Finishes the scope builder.
/// Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
pub fn InstrumentationScopeBuilder::build(
  self : InstrumentationScopeBuilder,
) -> InstrumentationScope {
  {
    name: self.name,
    version: self.version,
    schema_url: self.schema_url,
    attributes: self.attributes,
  }
}

///|
pub impl Default for InstrumentationScope with fn default() -> InstrumentationScope {
  InstrumentationScope::builder("").build()
}