///|
pub struct SignatureComponent {
  key : String
  value : String
} derive(Eq, Debug)

///|
pub fn SignatureComponent::new(
  key : String,
  value : String,
) -> SignatureComponent {
  { key, value }
}

///|
fn first_ascii_index(input : String, wanted : UInt16) -> Int {
  for i in 0.. Int {
  if trim_ascii(input) == "" {
    return 0
  }
  let mut count = 1
  for i in 0.. Array[String] {
  let count = count_signature_parts(input)
  if count == 0 {
    return []
  }
  let comma = ','.to_int().to_uint16()
  let mut cursor = 0
  let mut start = 0
  Array::makei(count, _ => {
    while cursor < input.length() && input.unsafe_get(cursor) != comma {
      cursor = cursor + 1
    }
    let part = trim_ascii(input[start:cursor].to_owned())
    if cursor < input.length() {
      cursor = cursor + 1
    }
    start = cursor
    part
  })
}

///|
fn parse_signature_component(input : String) -> SignatureComponent? {
  let separator = first_ascii_index(input, '='.to_int().to_uint16())
  if separator <= 0 || separator >= input.length() - 1 {
    return None
  }
  let key = trim_ascii(input[0:separator].to_owned())
  let value = trim_ascii(input[separator + 1:].to_owned())
  if key == "" || value == "" {
    None
  } else {
    Some(SignatureComponent::new(key, value))
  }
}

///|
pub fn parse_signature_header(input : String) -> Array[SignatureComponent] {
  let parts = split_signature_parts(input)
  let parsed : Array[SignatureComponent] = []
  for part in parts {
    match parse_signature_component(part) {
      Some(component) => parsed.push(component)
      None => ()
    }
  }
  parsed
}

///|
pub fn signature_values(
  components : Array[SignatureComponent],
  key : String,
) -> Array[String] {
  let values : Array[String] = []
  for component in components {
    if component.key == key {
      values.push(component.value)
    }
  }
  values
}

///|
pub fn first_signature_value(
  components : Array[SignatureComponent],
  key : String,
) -> String? {
  for component in components {
    if component.key == key {
      return Some(component.value)
    }
  }
  None
}

///|
pub struct StripeSignature {
  timestamp : Int
  timestamp_text : String
  v1_signatures : Array[String]
  legacy_signatures : Array[String]
  unknown_components : Array[SignatureComponent]
} derive(Eq, Debug)

///|
pub fn StripeSignature::empty() -> StripeSignature {
  {
    timestamp: 0,
    timestamp_text: "",
    v1_signatures: [],
    legacy_signatures: [],
    unknown_components: [],
  }
}

///|
pub fn StripeSignature::is_well_formed(self : StripeSignature) -> Bool {
  self.timestamp > 0 && self.v1_signatures.length() > 0
}

///|
pub fn parse_stripe_signature(input : String) -> StripeSignature {
  let components = parse_signature_header(input)
  let timestamp_text = first_signature_value(components, "t").unwrap_or("")
  let v1_signatures = signature_values(components, "v1")
  let legacy_signatures = signature_values(components, "v0")
  let unknown_components : Array[SignatureComponent] = []
  for component in components {
    if component.key != "t" && component.key != "v1" && component.key != "v0" {
      unknown_components.push(component)
    }
  }
  {
    timestamp: parse_positive_int(timestamp_text),
    timestamp_text,
    v1_signatures,
    legacy_signatures,
    unknown_components,
  }
}

///|
pub fn stripe_signature_summary(signature : StripeSignature) -> String {
  let builder = StringBuilder::new()
  builder.write_string("timestamp=")
  builder.write_string(signature.timestamp.to_string())
  builder.write_string(" v1=")
  builder.write_string(signature.v1_signatures.length().to_string())
  builder.write_string(" legacy=")
  builder.write_string(signature.legacy_signatures.length().to_string())
  builder.write_string(" unknown=")
  builder.write_string(signature.unknown_components.length().to_string())
  builder.to_string()
}