// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0

///|
/// One attribute, as an OTLP `KeyValue`: a name, and a value tagged with its type.
///
/// The tag is what makes an integer stay an integer across the wire; a receiver
/// that had to guess would show `200` as text on one dashboard and as a number on
/// another.
fn write_attributes(
  w : JsonWriter,
  attributes : Array[(String, @trace.Value)],
) -> Unit {
  w.open_array()
  for attribute in attributes {
    w.open_object()
    w.name("key")
    w.string(attribute.0)
    w.name("value")
    write_any_value(w, attribute.1)
    w.close_object()
  }
  w.close_array()
}

///|
/// One attribute value, tagged with the field name of its type.
///
/// An array keeps the tag of its elements: OpenTelemetry requires an array
/// attribute to be homogeneous, which is why the value type has one variant per
/// element type rather than one array of values.
fn write_any_value(w : JsonWriter, value : @trace.Value) -> Unit {
  w.open_object()
  match value {
    @trace.Bool(v) => {
      w.name("boolValue")
      w.boolean(v)
    }
    @trace.Int(v) => {
      w.name("intValue")
      w.int64(v)
    }
    @trace.Double(v) => {
      w.name("doubleValue")
      w.double(v)
    }
    @trace.Str(v) => {
      w.name("stringValue")
      w.string(v)
    }
    @trace.Bools(values) => {
      w.name("arrayValue")
      w.open_object()
      w.name("values")
      w.open_array()
      for v in values {
        w.open_object()
        w.name("boolValue")
        w.boolean(v)
        w.close_object()
      }
      w.close_array()
      w.close_object()
    }
    @trace.Ints(values) => {
      w.name("arrayValue")
      w.open_object()
      w.name("values")
      w.open_array()
      for v in values {
        w.open_object()
        w.name("intValue")
        w.int64(v)
        w.close_object()
      }
      w.close_array()
      w.close_object()
    }
    @trace.Doubles(values) => {
      w.name("arrayValue")
      w.open_object()
      w.name("values")
      w.open_array()
      for v in values {
        w.open_object()
        w.name("doubleValue")
        w.double(v)
        w.close_object()
      }
      w.close_array()
      w.close_object()
    }
    @trace.Strs(values) => {
      w.name("arrayValue")
      w.open_object()
      w.name("values")
      w.open_array()
      for v in values {
        w.open_object()
        w.name("stringValue")
        w.string(v)
        w.close_object()
      }
      w.close_array()
      w.close_object()
    }
  }
  w.close_object()
}