// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2026 clbbbb

///|
pub struct AuditEvidence {
  project : ProjectAudit
  third_party_errors : Array[String]
  baseline_new : Array[AuditFinding]
  generated_files : Array[String]
} derive(Debug, Eq)

///|
pub fn audit_evidence(
  project : ProjectAudit,
  packages : Array[ThirdPartyPackage],
  current_findings : Array[AuditFinding],
  baseline : Array[AuditFinding],
  policy : Policy,
) -> AuditEvidence {
  {
    project,
    third_party_errors: third_party_errors(packages, policy),
    baseline_new: new_findings(current_findings, baseline),
    generated_files: evidence_file_names(),
  }
}

///|
pub fn evidence_file_names() -> Array[String] {
  [
    "license-audit.txt", "license-audit.md", "third-party-licenses.md", "audit-baseline.txt",
  ]
}

///|
pub fn evidence_passes(evidence : AuditEvidence) -> Bool {
  audit_passes(evidence.project) &&
  evidence.third_party_errors.is_empty() &&
  evidence.baseline_new.is_empty()
}

///|
pub fn evidence_status(evidence : AuditEvidence) -> String {
  if evidence_passes(evidence) {
    "pass"
  } else {
    "fail"
  }
}

///|
pub fn evidence_error_count(evidence : AuditEvidence) -> Int {
  evidence.project.policy_errors.length() +
  evidence.third_party_errors.length() +
  evidence.baseline_new.length()
}

///|
pub fn evidence_warning_count(evidence : AuditEvidence) -> Int {
  evidence.project.warnings.length()
}

///|
pub fn evidence_summary(evidence : AuditEvidence) -> String {
  join_lines([
    "status: " + evidence_status(evidence),
    "grade: " + audit_grade(evidence.project),
    "errors: " + evidence_error_count(evidence).to_string(),
    "warnings: " + evidence_warning_count(evidence).to_string(),
    "artifacts: " + join_with(evidence.generated_files, ","),
  ])
}

///|
pub fn evidence_failures(evidence : AuditEvidence) -> Array[String] {
  let rows : Array[String] = []
  for error in evidence.project.policy_errors {
    rows.push("project: " + error)
  }
  for error in evidence.third_party_errors {
    rows.push("third-party: " + error)
  }
  for finding in evidence.baseline_new {
    rows.push("new finding: " + finding_key(finding))
  }
  rows
}

///|
pub fn evidence_warnings(evidence : AuditEvidence) -> Array[String] {
  evidence.project.warnings
}

///|
pub fn evidence_report(evidence : AuditEvidence) -> String {
  let rows : Array[String] = [
    "MoonBit license audit evidence",
    evidence_summary(evidence),
    "",
    project_audit_report(evidence.project),
    "",
  ]
  push_section(rows, "failures", evidence_failures(evidence))
  push_section(rows, "warnings", evidence_warnings(evidence))
  join_lines(rows)
}

///|
pub fn evidence_markdown(evidence : AuditEvidence) -> String {
  let rows : Array[String] = [
    "# License audit evidence",
    "",
    "- status: " + evidence_status(evidence),
    "- grade: " + audit_grade(evidence.project),
    "- errors: " + evidence_error_count(evidence).to_string(),
    "- warnings: " + evidence_warning_count(evidence).to_string(),
    "",
  ]
  push_markdown_section(rows, "Failures", evidence_failures(evidence))
  push_markdown_section(rows, "Warnings", evidence_warnings(evidence))
  rows.push("## Expected artifacts")
  rows.push("")
  for file in evidence.generated_files {
    rows.push("- " + file)
  }
  rows.push("")
  join_lines(rows)
}

///|
pub fn ci_annotation(evidence : AuditEvidence) -> String {
  if evidence_passes(evidence) {
    "license audit passed: " + audit_grade(evidence.project)
  } else {
    "license audit failed: " +
    evidence_error_count(evidence).to_string() +
    " issue(s)"
  }
}

///|
pub fn ci_should_fail(evidence : AuditEvidence) -> Bool {
  !evidence_passes(evidence)
}

///|
pub fn evidence_for_inputs(
  moon_mod : String,
  readme : String,
  paths : Array[String],
  sources : Array[String],
  packages_text : String,
  baseline_text : String,
  policy : Policy,
) -> AuditEvidence {
  let project = project_audit(moon_mod, readme, paths, sources, policy)
  let findings = findings_from_sources(paths, sources, policy)
  let evidence = audit_evidence(
    project,
    parse_third_party_manifest(packages_text),
    findings,
    parse_baseline(baseline_text),
    policy,
  )
  {
    project: evidence.project,
    third_party_errors: evidence.third_party_errors +
    third_party_manifest_errors(packages_text),
    baseline_new: evidence.baseline_new,
    generated_files: evidence.generated_files,
  }
}

///|
pub fn evidence_inputs_report(
  moon_mod : String,
  readme : String,
  paths : Array[String],
  sources : Array[String],
  packages_text : String,
  baseline_text : String,
  policy : Policy,
) -> String {
  evidence_report(
    evidence_for_inputs(
      moon_mod, readme, paths, sources, packages_text, baseline_text, policy,
    ),
  )
}