///|
pub fn edit_distance(left : String, right : String) -> Int {
  let prev = Array::make(right.length() + 1, 0)
  let curr = Array::make(right.length() + 1, 0)
  for j = 0; j <= right.length(); j = j + 1 {
    prev[j] = j
  }
  for i = 1; i <= left.length(); i = i + 1 {
    curr[0] = i
    for j = 1; j <= right.length(); j = j + 1 {
      let cost = if left[i - 1] == right[j - 1] { 0 } else { 1 }
      curr[j] = min_int(
        min_int(curr[j - 1] + 1, prev[j] + 1),
        prev[j - 1] + cost,
      )
    }
    for j = 0; j <= right.length(); j = j + 1 {
      prev[j] = curr[j]
    }
  }
  prev[right.length()]
}

///|
pub fn min_int(a : Int, b : Int) -> Int {
  if a < b {
    a
  } else {
    b
  }
}

///|
pub fn suggest_directive(key : String) -> String? {
  let known = [
    "user-agent", "allow", "disallow", "crawl-delay", "sitemap", "host",
  ]
  let mut best = ""
  let mut score = 999
  for item in known {
    let distance = edit_distance(lower_ascii(key), item)
    if distance < score {
      score = distance
      best = item
    }
  }
  if score <= 3 {
    Some(best)
  } else {
    None
  }
}

///|
pub fn directive_suggestion_report(text : String) -> String {
  let lines : Array[String] = []
  for item in unknown_directives(text) {
    match suggest_directive(item.key) {
      Some(suggestion) =>
        lines.push(
          "line " + item.line.to_string() + ": did you mean " + suggestion + "?",
        )
      None =>
        lines.push("line " + item.line.to_string() + ": unknown " + item.key)
    }
  }
  if lines.is_empty() {
    "ok"
  } else {
    join_lines(lines)
  }
}

///|
pub fn rule_suggestion(text : String, agent : String, path : String) -> String {
  let decision = decide(parse(text), agent, path)
  if decision.matched_kind == "none" {
    "no matching rule; add Allow or Disallow for " + path_parent(path)
  } else if decision.allowed {
    "allowed by " + decision.matched_pattern
  } else {
    "blocked by " + decision.matched_pattern
  }
}

///|
pub fn diagnostics_report(
  text : String,
  agent : String,
  paths : Array[String],
) -> String {
  join_lines([
    "directives:",
    directive_suggestion_report(text),
    "sensitive:",
    sensitive_report(text, agent),
    "coverage:",
    coverage_report(text, agent, paths),
  ])
}