///|
/// 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
  @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]
      match try_compose(starter, c) {
        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
        }
        None => ()
      }
    }

    // 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)
}