///|
fn fnv1a_step(hash : Int, ch : Char) -> Int {
  let mut value = hash
  value = value ^ ch.to_int()
  value = value * 16777619
  value & 0x7fffffff
}

///|
pub fn stable_hash(text : StringView) -> String {
  let mut hash = 5381
  for ch in text {
    hash = fnv1a_step(hash, ch)
  }
  hash.to_string()
}

///|
pub fn stable_result_key(
  rule_id : StringView,
  message : StringView,
  uri : StringView,
  line : Int,
  column : Int,
) -> String {
  let raw = "\{rule_id}|\{message}|\{uri}|\{line}|\{column}"
  stable_hash(raw)
}

///|
pub fn SarifResult::with_fingerprint(
  self : SarifResult,
  key : StringView,
  value : StringView,
) -> SarifResult {
  let fingerprints = self.fingerprints.copy()
  let needle = key.to_owned()
  for i, item in fingerprints {
    if item.key == needle {
      fingerprints[i] = Fingerprint::Fingerprint(key, value)
      return { ..self, fingerprints, }
    }
  }
  fingerprints.push(Fingerprint::Fingerprint(key, value))
  { ..self, fingerprints, }
}

///|
pub fn SarifResult::with_stable_fingerprint(self : SarifResult) -> SarifResult {
  match (self.primary_uri(), self.primary_region()) {
    (Some(uri), Some(region)) => {
      let key = stable_result_key(
        self.rule_id,
        self.message.text,
        uri,
        region.start_line,
        region.start_column,
      )
      self.with_fingerprint("stableKey", key)
    }
    _ =>
      self.with_fingerprint(
        "stableKey",
        stable_hash("\{self.rule_id}|\{self.message.text}"),
      )
  }
}

///|
pub fn SarifRun::with_stable_fingerprints(self : SarifRun) -> SarifRun {
  {
    ..self,
    results: self.results.map(result => result.with_stable_fingerprint()),
  }
}

///|
pub fn SarifLog::with_stable_fingerprints(self : SarifLog) -> SarifLog {
  { ..self, runs: self.runs.map(run => run.with_stable_fingerprints()) }
}