///|
fn csv_cell(value : String) -> String {
  if value.contains(",") ||
    value.contains("\"") ||
    value.contains("\n") ||
    value.contains("\r") {
    "\"" + value.replace_all(old="\"", new="\"\"") + "\""
  } else {
    value
  }
}

///|
fn entry_kind_name(kind : EntryKind) -> String {
  match kind {
    Regular => "file"
    Directory => "directory"
    Symlink => "symlink"
    Other => "other"
  }
}

///|
pub fn render_snapshot_csv(snapshot : Snapshot) -> String {
  let lines : Array[String] = [
    "path,name,kind,extension,size_bytes,modified_at",
  ]
  for entry in snapshot.entries {
    lines.push(
      csv_cell(entry.path) +
      "," +
      csv_cell(entry.name()) +
      "," +
      entry_kind_name(entry.kind) +
      "," +
      csv_cell(entry.extension()) +
      "," +
      entry.size.to_string() +
      "," +
      entry.modified_at.to_string(),
    )
  }
  lines.join("\r\n") + "\r\n"
}

///|
pub fn render_directory_csv(snapshot : Snapshot) -> String {
  let lines : Array[String] = [
    "path,direct_files,direct_size_bytes,recursive_files,recursive_size_bytes",
  ]
  let stats = directory_stats(snapshot)
  stats.sort_by(fn(a, b) {
    if a.path < b.path {
      -1
    } else if a.path > b.path {
      1
    } else {
      0
    }
  })
  for stat in stats {
    lines.push(
      csv_cell(stat.path) +
      "," +
      stat.direct_files.to_string() +
      "," +
      stat.direct_size.to_string() +
      "," +
      stat.recursive_files.to_string() +
      "," +
      stat.recursive_size.to_string(),
    )
  }
  lines.join("\r\n") + "\r\n"
}

///|
pub fn render_diff_csv(diff : SnapshotDiff) -> String {
  let lines : Array[String] = [
    "path,change_kind,before_size_bytes,after_size_bytes,size_delta_bytes",
  ]
  for change in diff.changes {
    let before_size = match change.before {
      Some(entry) => entry.size
      None => 0L
    }
    let after_size = match change.after {
      Some(entry) => entry.size
      None => 0L
    }
    lines.push(
      csv_cell(change.path) +
      "," +
      change_kind_name(change.kind) +
      "," +
      before_size.to_string() +
      "," +
      after_size.to_string() +
      "," +
      change.size_delta.to_string(),
    )
  }
  lines.join("\r\n") + "\r\n"
}

///|
pub fn render_plan_csv(plan : CleanupPlan) -> String {
  let lines : Array[String] = [
    "source,destination,size_bytes,risk,rule_id,reason",
  ]
  for item in plan.items {
    lines.push(
      csv_cell(item.source) +
      "," +
      csv_cell(item.destination) +
      "," +
      item.expected_size.to_string() +
      "," +
      risk_name(item.risk) +
      "," +
      csv_cell(item.rule_id) +
      "," +
      csv_cell(item.reason),
    )
  }
  lines.join("\r\n") + "\r\n"
}