///|
pub(all) struct Insight {
  title : String
  severity : Severity
  detail : String
} derive(Eq, Debug)

///|
pub fn generate_insights(archive : HarArchive) -> Array[Insight] {
  let summary = analyze_archive(archive)
  let out : Array[Insight] = []
  add_failure_insight(summary, out)
  add_redirect_insight(summary, out)
  add_size_insight(summary, out)
  add_latency_insight(summary, out)
  add_domain_insight(summary, out)
  add_resource_insight(summary, out)
  if out.is_empty() {
    out.push(Insight::{
      title: "No major issues detected",
      severity: Info,
      detail: "The archive is small, successful, and within default latency thresholds.",
    })
  }
  out
}

///|
fn add_failure_insight(summary : HarSummary, out : Array[Insight]) -> Unit {
  if summary.failed_count > 0 {
    out.push(Insight::{
      title: "Failed requests detected",
      severity: Error,
      detail: summary.failed_count.to_string() +
      " requests returned 4xx or 5xx responses.",
    })
  }
}

///|
fn add_redirect_insight(summary : HarSummary, out : Array[Insight]) -> Unit {
  if summary.redirected_count > 3 {
    out.push(Insight::{
      title: "Redirect count is high",
      severity: Warning,
      detail: summary.redirected_count.to_string() +
      " redirects may add avoidable latency.",
    })
  }
}

///|
fn add_size_insight(summary : HarSummary, out : Array[Insight]) -> Unit {
  if summary.total_bytes > 5_000_000 {
    out.push(Insight::{
      title: "Transfer size is large",
      severity: Warning,
      detail: "Total transferred bytes are " +
      summary.total_bytes.to_string() +
      ".",
    })
  }
}

///|
fn add_latency_insight(summary : HarSummary, out : Array[Insight]) -> Unit {
  if summary.average_time > 500 {
    out.push(Insight::{
      title: "Average latency is high",
      severity: Warning,
      detail: "Average request time is " +
      summary.average_time.to_string() +
      "ms.",
    })
  }
  if summary.longest_time > 2000 {
    out.push(Insight::{
      title: "Slow outlier request",
      severity: Warning,
      detail: "The slowest request took " +
      summary.longest_time.to_string() +
      "ms.",
    })
  }
}

///|
fn add_domain_insight(summary : HarSummary, out : Array[Insight]) -> Unit {
  if summary.domains.length() > 8 {
    out.push(Insight::{
      title: "Many network domains",
      severity: Info,
      detail: summary.domains.length().to_string() + " domains were contacted.",
    })
  }
}

///|
fn add_resource_insight(summary : HarSummary, out : Array[Insight]) -> Unit {
  for i = 0; i < summary.resources.length(); i = i + 1 {
    let r = summary.resources[i]
    if r.kind == "image" && r.bytes > 2_000_000 {
      out.push(Insight::{
        title: "Large image payload",
        severity: Warning,
        detail: "Images transferred " + r.bytes.to_string() + " bytes.",
      })
    }
  }
}

///|
pub fn render_insights(insights : Array[Insight]) -> String {
  let mut out = ""
  for i = 0; i < insights.length(); i = i + 1 {
    let item = insights[i]
    out = out +
      severity_text(item.severity) +
      " " +
      item.title +
      " - " +
      item.detail +
      "\n"
  }
  out
}

///|
pub fn insight_count_by_severity(
  insights : Array[Insight],
  severity : Severity,
) -> Int {
  insights.count_if(i => i.severity == severity)
}