///|
/// Canonical Composition Algorithm
/// Composes adjacent starter + non-blocked combining marks into precomposed characters

///|
/// Try to compose two characters into one
/// Handles both Hangul and general composition
fn try_compose(first : Char, second : Char) -> Char? {
  // Try Hangul composition first (algorithmic, no table lookup)
  match try_compose_hangul(first, second) {
    Some(h) => return Some(h)
    None => ()
  }

  // Look up in composition table
  @ucd.lookup_composition(first, second)
}

///|
/// Compose a sequence of canonically ordered characters
/// This is the final step for NFC and NFKC
fn canonical_compose(chars : Array[Char]) -> Array[Char] {
  let len = chars.length()
  if len == 0 {
    return []
  }
  let result : Array[Char] = []
  result.push(chars[0])

  // Track the last starter position in result (-1 if no starter yet)
  let mut last_starter_idx = if @ucd.lookup_ccc(chars[0]) == 0 { 0 } else { -1 }

  // Track CCC of the last character we processed
  // Used to detect "blocked" combining marks
  let mut last_ccc = @ucd.lookup_ccc(chars[0])
  for i = 1; i < len; i = i + 1 {
    let c = chars[i]
    let ccc = @ucd.lookup_ccc(c)

    // A combining mark is "blocked" from composing with a starter if
    // there's an intervening combining mark with the same or higher CCC
    // (since marks are canonically ordered by CCC)
    //
    // We can compose if:
    // 1. There is a last starter (last_starter_idx >= 0)
    // 2. Either this is right after the starter (last_ccc == 0)
    //    OR this mark's CCC is greater than the previous mark's CCC
    let not_blocked = last_ccc == 0 || (ccc != 0 && last_ccc < ccc)
    if last_starter_idx >= 0 && not_blocked {
      let starter = result[last_starter_idx]
      match try_compose(starter, c) {
        Some(composed) => {
          // Successfully composed - update the starter in result
          result[last_starter_idx] = composed
          // The composed character is still a starter, don't update last_ccc
          // This allows further composition with subsequent marks
          continue i + 1
        }
        None => ()
      }
    }

    // Could not compose, add to result
    result.push(c)
    if ccc == 0 {
      // This is a new starter
      last_starter_idx = result.length() - 1
      last_ccc = 0
    } else {
      // This is a combining mark, update last_ccc
      last_ccc = ccc
    }
  }
  result
}