///|
/// 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)
  if try_compose_hangul(first, second) is Some(h) {
    return Some(h)
  }

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

///|
/// Compose a sequence of canonically ordered characters
/// Compact in place, reusing the decomposition buffer for NFC and NFKC.
fn canonical_compose(chars : Array[Char]) -> Unit {
  let len = chars.length()
  if len == 0 {
    return
  }
  let mut written = 1

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

  // Track CCC of the last character we processed
  // Used to detect "blocked" combining marks
  let mut last_ccc = first_ccc
  // written never exceeds i: compaction cannot overwrite unread input.
  for i in 1..= 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 = chars[last_starter_idx]
      if try_compose(starter, c) is Some(composed) {
        // Successfully composed - update the starter in the compacted prefix
        chars[last_starter_idx] = composed
        // The composed character is still a starter, don't update last_ccc
        // This allows further composition with subsequent marks
        continue
      }
    }

    // Could not compose, keep the character in the compacted prefix
    chars[written] = c
    written += 1
    if ccc == 0 {
      // This is a new starter
      last_starter_idx = written - 1
      last_ccc = 0
    } else {
      // This is a combining mark, update last_ccc
      last_ccc = ccc
    }
  }
  chars.truncate(written)
}