///|
pub enum IcdEdition {
  ICD10
  ICD11
} derive(Debug, Eq, ToJson)

///|
pub struct IcdCode {
  edition : IcdEdition
  raw : String
  stem : String
  category : String
  subcategory : String?
  numeric : Int
  extension : String?
} derive(Debug, Eq, ToJson)

///|
pub struct IcdChapter {
  id : String
  title : String
  start : String
  end : String
  note : String
} derive(Debug, Eq, ToJson)

///|
pub struct IcdEntry {
  code : String
  title : String
  chapter_id : String
  parent : String?
  excludes : Array[String]
  note : String
} derive(Debug, Eq, ToJson)

///|
pub fn IcdEntry::new(
  code : String,
  title : String,
  chapter_id : String,
  parent : String?,
  excludes : Array[String],
  note : String,
) -> IcdEntry {
  { code, title, chapter_id, parent, excludes, note }
}

///|
pub struct ValidationIssue {
  code : String
  message : String
  hint : String
} derive(Debug, Eq, ToJson)

///|
pub enum ValidationStatus {
  Valid
  Unknown
  Invalid
} derive(Debug, Eq, ToJson)

///|
pub struct ValidationReport {
  input : String
  normalized : String?
  status : ValidationStatus
  chapter : IcdChapter?
  entry : IcdEntry?
  issues : Array[ValidationIssue]
} derive(Debug, Eq, ToJson)

///|
pub fn IcdCode::canonical(self : IcdCode) -> String {
  match self.subcategory {
    Some(sub) => "\{self.category}.\{sub}"
    None => self.category
  }
}

///|
pub fn IcdChapter::contains(self : IcdChapter, code : IcdCode) -> Bool {
  code.numeric >= rank_code(self.start) && code.numeric <= rank_code(self.end)
}