///|
pub fn csv_escape(text : String) -> String {
  if text.find(",") is Some(_) ||
    text.find("\"") is Some(_) ||
    text.find("\n") is Some(_) {
    "\"" + text_replace(text, "\"", "\"\"") + "\""
  } else {
    text
  }
}

///|
pub fn csv_row(values : Array[String]) -> String {
  let cells : Array[String] = []
  for value in values {
    cells.push(csv_escape(value))
  }
  join_with(cells, ",")
}

///|
pub fn decisions_csv(
  text : String,
  agent : String,
  paths : Array[String],
) -> String {
  let robots = parse(text)
  let rows : Array[String] = [csv_row(["path", "allowed", "kind", "pattern"])]
  for path in paths {
    let decision = decide(robots, agent, path)
    rows.push(
      csv_row([
        path,
        if decision.allowed {
          "true"
        } else {
          "false"
        },
        decision.matched_kind,
        decision.matched_pattern,
      ]),
    )
  }
  join_lines(rows)
}

///|
pub fn rules_csv(text : String) -> String {
  let rows : Array[String] = [csv_row(["agents", "kind", "pattern"])]
  for group in parse(text).groups {
    for rule in group.rules {
      rows.push(
        csv_row([join_with(group.agents, "|"), rule.kind, rule.pattern]),
      )
    }
  }
  join_lines(rows)
}

///|
pub fn sitemap_csv(xml : String) -> String {
  let rows : Array[String] = [
    csv_row(["loc", "lastmod", "changefreq", "priority"]),
  ]
  for entry in sitemap_entries(xml) {
    rows.push(
      csv_row([entry.loc, entry.lastmod, entry.changefreq, entry.priority]),
    )
  }
  join_lines(rows)
}

///|
pub fn frontier_csv(items : Array[FrontierItem]) -> String {
  let rows : Array[String] = [csv_row(["url", "path", "allowed", "reason"])]
  for item in items {
    rows.push(
      csv_row([
        item.url,
        item.path,
        if item.allowed {
          "true"
        } else {
          "false"
        },
        item.reason,
      ]),
    )
  }
  join_lines(rows)
}