///|
fn parse_error_report(
  input : String,
  error : IcdParseError,
) -> ValidationReport {
  match error {
    IcdParseError::EmptyInput =>
      {
        input,
        normalized: None,
        status: Invalid,
        chapter: None,
        entry: None,
        issues: [
          parse_issue(
            input, "empty ICD code", "Pass a category such as I10 or a subcategory such as A00.0.",
          ),
        ],
      }
    IcdParseError::InvalidCode(_) =>
      {
        input,
        normalized: None,
        status: Invalid,
        chapter: None,
        entry: None,
        issues: [
          parse_issue(
            input, "invalid ICD-10 syntax", "Expected one letter, two digits, and an optional decimal subcategory.",
          ),
        ],
      }
    IcdParseError::UnsupportedEdition(_) =>
      {
        input,
        normalized: None,
        status: Invalid,
        chapter: None,
        entry: None,
        issues: [
          parse_issue(
            input, "unsupported edition", "Use ICD-10 validation for this command.",
          ),
        ],
      }
  }
}

///|
pub fn validate_against(catalog : Catalog, input : String) -> ValidationReport {
  try parse_icd10(input) catch {
    error => parse_error_report(input, error)
  } noraise {
    code => {
      let normalized = code.canonical()
      let chapter = find_chapter(code)
      let entry = catalog.lookup(normalized)
      let issues = match entry {
        Some(item) =>
          item.excludes.map(fn(ex) {
            parse_issue(
              normalized,
              "exclusion hint: \{ex}",
              "Review whether \{ex} is a better fit for this diagnosis context.",
            )
          })
        None =>
          [
            parse_issue(
              normalized, "code is syntactically valid but not in the bundled sample catalog",
              "Load a full licensed ICD table or use chapter/range checks for structural validation.",
            ),
          ]
      }
      {
        input,
        normalized: Some(normalized),
        status: if entry is Some(_) {
          Valid
        } else {
          Unknown
        },
        chapter,
        entry,
        issues,
      }
    }
  }
}

///|
pub fn validate_icd10(input : String) -> ValidationReport {
  validate_against(bundled_catalog(), input)
}

///|
pub fn format_report(report : ValidationReport) -> String {
  let status = match report.status {
    Valid => "valid"
    Unknown => "unknown"
    Invalid => "invalid"
  }
  let code = report.normalized.unwrap_or(report.input)
  let chapter = match report.chapter {
    Some(c) => "chapter \{c.id}: \{c.title}"
    None => "chapter: not resolved"
  }
  let entry = match report.entry {
    Some(e) => "\{e.code} \{e.title}"
    None => "entry: not in bundled sample catalog"
  }
  let issues = if report.issues.is_empty() {
    "issues: none"
  } else {
    "issues:\n" +
    report.issues.map(fn(i) { "- \{i.message}; \{i.hint}" }).join("\n")
  }
  "ICD check \{status}: \{code}\n\{chapter}\n\{entry}\n\{issues}"
}