///|
fn usage() -> String {
  (
    #|MoonCollate — Unicode 17.0.0 collation toolkit
    #|
    #|Usage:
    #|  moon run cmd/main -- compare [options] LEFT RIGHT
    #|  moon run cmd/main -- key [options] TEXT
    #|  moon run cmd/main -- explain [options] TEXT
    #|  moon run cmd/main -- sort [options] TEXT...
    #|  moon run cmd/main -- version
    #|
    #|Options:
    #|  --strength primary|secondary|tertiary|quaternary|identical
    #|  --shifted                  Ignore variables before quaternary level
    #|  --numeric                  Compare ASCII digit runs numerically
    #|  --upper-first              Sort uppercase before lowercase
    #|  --lower-first              Sort lowercase before uppercase
    #|  --backwards-secondary      Compare secondary weights in reverse
  )
}

///|
fn parse_strength(value : String) -> @collate.Strength? {
  match value {
    "primary" => Some(@collate.Strength::Primary)
    "secondary" => Some(@collate.Strength::Secondary)
    "tertiary" => Some(@collate.Strength::Tertiary)
    "quaternary" => Some(@collate.Strength::Quaternary)
    "identical" => Some(@collate.Strength::Identical)
    _ => None
  }
}

///|
fn parse_options(
  args : Array[String],
  start : Int,
) -> (@collate.Collator, Array[String])? {
  let mut collator = @collate.default_collator()
  let operands : Array[String] = []
  let mut index = start
  while index < args.length() {
    match args[index] {
      "--strength" => {
        if index + 1 >= args.length() {
          return None
        }
        match parse_strength(args[index + 1]) {
          Some(strength) => collator = collator.with_strength(strength)
          None => return None
        }
        index = index + 2
      }
      "--shifted" => {
        collator = collator.with_alternate(@collate.AlternateHandling::Shifted)
        index = index + 1
      }
      "--numeric" => {
        collator = collator.with_numeric(true)
        index = index + 1
      }
      "--upper-first" => {
        collator = collator.with_case_first(@collate.CaseFirst::UpperFirst)
        index = index + 1
      }
      "--lower-first" => {
        collator = collator.with_case_first(@collate.CaseFirst::LowerFirst)
        index = index + 1
      }
      "--backwards-secondary" => {
        collator = collator.with_backwards_secondary(true)
        index = index + 1
      }
      value => {
        operands.push(value)
        index = index + 1
      }
    }
  }
  Some((collator, operands))
}

///|
fn ordering_number(ordering : @collate.Ordering) -> Int {
  match ordering {
    Less => -1
    Equal => 0
    Greater => 1
  }
}

///|
fn command_compare(
  collator : @collate.Collator,
  operands : Array[String],
) -> Bool {
  if operands.length() != 2 {
    return false
  }
  let result = collator.compare(operands[0], operands[1])
  println(
    (
      {
        "left": operands[0].to_json(),
        "right": operands[1].to_json(),
        "ordering": result.to_string().to_json(),
        "value": ordering_number(result).to_json(),
      } : Json).stringify(indent=2),
  )
  true
}

///|
fn command_key(collator : @collate.Collator, operands : Array[String]) -> Bool {
  if operands.length() != 1 {
    return false
  }
  println(collator.sort_key(operands[0]).to_json().stringify(indent=2))
  true
}

///|
fn command_explain(
  collator : @collate.Collator,
  operands : Array[String],
) -> Bool {
  if operands.length() != 1 {
    return false
  }
  println(collator.explain(operands[0]).to_json().stringify(indent=2))
  true
}

///|
fn command_sort(collator : @collate.Collator, operands : Array[String]) -> Bool {
  if operands.length() == 0 {
    return false
  }
  operands.sort_by((left, right) => {
    ordering_number(collator.compare(left, right))
  })
  println(operands.to_json().stringify(indent=2))
  true
}

///|
fn main {
  let args = @env.args()
  if args.length() < 2 {
    println(usage())
    return
  }
  if args[1] == "version" || args[1] == "--version" {
    println(
      "moon-collate {@collate.library_version()} (Unicode {@collate.unicode_version()}, UCA {@collate.uca_version()})",
    )
    return
  }
  match parse_options(args, 2) {
    None => println(usage())
    Some((collator, operands)) => {
      let accepted = match args[1] {
        "compare" => command_compare(collator, operands)
        "key" => command_key(collator, operands)
        "explain" => command_explain(collator, operands)
        "sort" => command_sort(collator, operands)
        _ => false
      }
      if !accepted {
        println(usage())
      }
    }
  }
}