///|
pub(all) struct Scorecard {
  title : String
  technical : Int
  melodic : Int
  harmonic : Int
  rhythmic : Int
  explainability : Int
  total : Int
  grade : String
} derive(Debug, Eq, ToJson)

///|
pub fn make_scorecard(output : PipelineOutput) -> Scorecard {
  let technical = cap_quality(
    100 -
    output.validation.cantus.error_count() * 20 -
    output.validation.counterpoint.error_count() * 20,
  )
  let melodic = cap_quality(
    100 - output.contour.leaps * 4 - output.contour.range * 2,
  )
  let harmonic = cap_quality(
    100 - output.harmony.dissonant * 6 - output.harmony.crossings * 15,
  )
  let rhythmic = cap_quality(100 - output.rhythm.syncopations * 4)
  let explainability = if pipeline_is_explainable(output) { 100 } else { 60 }
  let total = (technical + melodic + harmonic + rhythmic + explainability) / 5
  {
    title: "Counterpoint scorecard",
    technical,
    melodic,
    harmonic,
    rhythmic,
    explainability,
    total,
    grade: if total >= 90 {
      "excellent"
    } else if total >= 75 {
      "good"
    } else if total >= 60 {
      "review"
    } else {
      "revise"
    },
  }
}

///|
pub fn scorecard_grade(scorecard : Scorecard) -> String {
  scorecard.grade
}

///|
pub fn scorecard_dimensions(scorecard : Scorecard) -> Array[Int] {
  [
    scorecard.technical,
    scorecard.melodic,
    scorecard.harmonic,
    scorecard.rhythmic,
    scorecard.explainability,
  ]
}

///|
pub fn weakest_dimension(scorecard : Scorecard) -> String {
  let dimensions = scorecard_dimensions(scorecard)
  let names = ["technical", "melodic", "harmonic", "rhythmic", "explainability"]
  let mut index = 0
  for i in 1.. String {
  let lines : Array[String] = [
    "## \{scorecard.title}",
    "",
    "| Dimension | Score |",
    "| --- | ---: |",
    "| Technical | \{scorecard.technical} |",
    "| Melodic | \{scorecard.melodic} |",
    "| Harmonic | \{scorecard.harmonic} |",
    "| Rhythmic | \{scorecard.rhythmic} |",
    "| Explainability | \{scorecard.explainability} |",
    "",
    "Grade: \{scorecard.grade} (\{scorecard.total}/100)",
  ]
  lines.join("\n")
}

///|
pub fn scorecard_csv(scorecard : Scorecard) -> String {
  "\{scorecard.technical},\{scorecard.melodic},\{scorecard.harmonic},\{scorecard.rhythmic},\{scorecard.explainability},\{scorecard.total},\{scorecard.grade}"
}

///|
pub fn scorecard_passed(scorecard : Scorecard) -> Bool {
  scorecard.total >= 60
}

///|
pub fn scorecard_action(scorecard : Scorecard) -> String {
  match weakest_dimension(scorecard) {
    "technical" => "repair timeline input"
    "melodic" => "review leaps and contour"
    "harmonic" => "review vertical intervals"
    "rhythmic" => "review beat placement"
    _ => "add an explanation to the report"
  }
}

///|
pub fn scorecard_compare(left : Scorecard, right : Scorecard) -> Int {
  left.total - right.total
}