///|
fn quality_bool_points(value : Bool, points : Int) -> Int {
  if value {
    points
  } else {
    0
  }
}

///|
fn annotation_has_attributes(annotation : Annotation) -> Bool {
  for feature in annotation.features {
    if feature.attributes.length() > 0 {
      return true
    }
  }
  false
}

///|
fn annotation_has_hierarchy(annotation : Annotation) -> Bool {
  let models = annotation.to_gene_models()
  if models.length() == 0 {
    false
  } else {
    for gene in models {
      if gene.transcripts.length() > 0 {
        for tx in gene.transcripts {
          if tx.exons.length() > 0 {
            return true
          }
        }
      }
    }
    false
  }
}

///|
fn quality_score(
  metrics : AnnotationMetrics,
  report : ValidationReport,
  has_required_hierarchy : Bool,
  has_attributes : Bool,
  has_multiple_seqids : Bool,
) -> Int {
  let mut score = 0
  score += quality_bool_points(metrics.feature_count > 0, 10)
  score += quality_bool_points(metrics.gene_count > 0, 15)
  score += quality_bool_points(metrics.transcript_count > 0, 15)
  score += quality_bool_points(metrics.exon_count > 0, 15)
  score += quality_bool_points(has_required_hierarchy, 20)
  score += quality_bool_points(has_attributes, 10)
  score += quality_bool_points(has_multiple_seqids, 5)
  score -= report.error_count() * 20
  score -= report.warning_count() * 5
  if score < 0 {
    0
  } else if score > 100 {
    100
  } else {
    score
  }
}

///|
pub fn Annotation::quality_report(self : Annotation) -> QualityReport {
  let metrics = self.metrics()
  let validation = self.validate()
  let has_required_hierarchy = annotation_has_hierarchy(self)
  let has_attributes = annotation_has_attributes(self)
  let has_multiple_seqids = metrics.seqid_count > 1
  {
    score: quality_score(
      metrics, validation, has_required_hierarchy, has_attributes, has_multiple_seqids,
    ),
    feature_count: metrics.feature_count,
    gene_count: metrics.gene_count,
    transcript_count: metrics.transcript_count,
    exon_count: metrics.exon_count,
    validation_errors: validation.error_count(),
    validation_warnings: validation.warning_count(),
    has_required_hierarchy,
    has_attributes,
    has_multiple_seqids,
  }
}

///|
pub fn QualityReport::grade(self : QualityReport) -> String {
  if self.score >= 90 {
    "A"
  } else if self.score >= 75 {
    "B"
  } else if self.score >= 60 {
    "C"
  } else if self.score >= 40 {
    "D"
  } else {
    "F"
  }
}

///|
pub fn QualityReport::to_text(self : QualityReport) -> String {
  [
    "score\t\{self.score}",
    "grade\t\{self.grade()}",
    "features\t\{self.feature_count}",
    "genes\t\{self.gene_count}",
    "transcripts\t\{self.transcript_count}",
    "exons\t\{self.exon_count}",
    "validation_errors\t\{self.validation_errors}",
    "validation_warnings\t\{self.validation_warnings}",
    "has_required_hierarchy\t\{self.has_required_hierarchy}",
    "has_attributes\t\{self.has_attributes}",
    "has_multiple_seqids\t\{self.has_multiple_seqids}",
  ].join("\n") +
  "\n"
}