///|
/// The Morphir key-name fragments that mark a sensitive key.
pub fn default_redact_fragments() -> Array[String] {
  [
    "token",
    "password",
    "passwd",
    "secret",
    "credential",
    "api_key",
    "apikey",
    "private_key",
    "access_key",
  ]
}

///|
/// A copy of `value` with each sensitive subtree replaced by the text
/// ``. A key is sensitive when its name, in lowercase with `-`
/// changed to `_`, holds a fragment. The default fragment list is Morphir's.
pub fn redact(
  value : ConfigValue,
  fragments~ : Array[String] = default_redact_fragments(),
) -> ConfigValue {
  redact_at(value, None, fragments)
}

///|
fn redact_at(
  value : ConfigValue,
  field_name : String?,
  fragments : Array[String],
) -> ConfigValue {
  if field_name is Some(name) && is_sensitive(name, fragments) {
    return string("")
  }
  match value.ion.kind() {
    Struct(fields) => {
      let out = []
      for field in fields {
        let name = field.name().text().unwrap_or("")
        let child = redact_at({ ion: field.value() }, Some(name), fragments)
        out.push(@ion.Field::from_token(field.name(), child.ion))
      }
      {
        ion: @ion.Ion::from_fields(out).with_annotations(value.ion.annotations()),
      }
    }
    List(items) => {
      {
        ion: @ion.Ion::list(
            items.map(item => redact_at({ ion: item }, None, fragments).ion),
          )
          .with_annotations(value.ion.annotations()),
      }
    }
    Sexp(items) => {
      {
        ion: @ion.Ion::sexp(
            items.map(item => redact_at({ ion: item }, None, fragments).ion),
          )
          .with_annotations(value.ion.annotations()),
      }
    }
    _ => value
  }
}

///|
fn is_sensitive(name : String, fragments : Array[String]) -> Bool {
  let normalized = name.to_lower().replace_all(old="-", new="_")
  fragments.any(fragment => normalized.contains(fragment))
}