// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
fn should_ignore_glyph(
  glyph : UInt,
  lookup_flag : Int,
  gdef : GdefTable?,
  mark_filtering_set : Int?,
  masks? : Array[UInt] = [],
  index? : Int = -1,
  lookup_mask? : UInt = 0xFFFFFFFFU,
) -> Result[Bool, OtLayoutError] {
  if !masks.is_empty() && index >= 0 {
    if (masks[index] & lookup_mask) == 0U {
      return Ok(true)
    }
  }
  if lookup_flag == 0 {
    return Ok(false)
  }
  match gdef {
    None => Ok(false)
    Some(gdef) => {
      let glyph_class = gdef.glyph_class(glyph)
      match glyph_class {
        Err(err) => Err(err)
        Ok(glyph_class) => {
          if glyph_class == 1 && (lookup_flag & 0x0002) != 0 {
            return Ok(true)
          }
          if glyph_class == 2 && (lookup_flag & 0x0004) != 0 {
            return Ok(true)
          }
          if glyph_class == 3 {
            if (lookup_flag & 0x0008) != 0 {
              return Ok(true)
            }
            let attach_type = (lookup_flag >> 8) & 0xff
            if attach_type != 0 {
              let mark_class = gdef.mark_attach_class(glyph)
              match mark_class {
                Err(err) => return Err(err)
                Ok(mark_class) => if mark_class != attach_type { return Ok(true) }
              }
            }
            if (lookup_flag & 0x0010) != 0 {
              match mark_filtering_set {
                None => ()
                Some(set_index) => {
                  let in_set = gdef.mark_glyph_set_contains(set_index, glyph)
                  match in_set {
                    Err(err) => return Err(err)
                    Ok(false) => return Ok(true)
                    Ok(true) => ()
                  }
                }
              }
            }
          }
          Ok(false)
        }
      }
    }
  }
}

///|
fn collect_forward_indices(
  glyphs : ArrayView[UInt],
  start_index : Int,
  count : Int,
  lookup_flag : Int,
  gdef : GdefTable?,
  mark_filtering_set : Int?,
  masks? : Array[UInt] = [],
  lookup_mask? : UInt = 0xFFFFFFFFU,
  allow_ignored_start? : Bool = false,
) -> Result[Array[Int]?, OtLayoutError] {
  if count <= 0 {
    return Err(InvalidFormat)
  }
  if start_index < 0 || start_index >= glyphs.length() {
    return Ok(None)
  }
  let mut cursor = start_index
  if allow_ignored_start {
    while cursor < glyphs.length() {
      let ignored = should_ignore_glyph(
        glyphs[cursor],
        lookup_flag,
        gdef,
        mark_filtering_set,
        masks=masks,
        index=cursor,
        lookup_mask=lookup_mask,
      )
      match ignored {
        Err(err) => return Err(err)
        Ok(false) => break
        Ok(true) => cursor = cursor + 1
      }
    }
    if cursor >= glyphs.length() {
      return Ok(None)
    }
  }
  let first_ignored = should_ignore_glyph(
    glyphs[cursor],
    lookup_flag,
    gdef,
    mark_filtering_set,
    masks=masks,
    index=cursor,
    lookup_mask=lookup_mask,
  )
  match first_ignored {
    Err(err) => Err(err)
    Ok(true) => Ok(None)
    Ok(false) => {
      let indices : Array[Int] = []
      indices.push(cursor)
      cursor = cursor + 1
      while indices.length() < count {
        if cursor >= glyphs.length() {
          return Ok(None)
        }
        let ignored = should_ignore_glyph(
          glyphs[cursor],
          lookup_flag,
          gdef,
          mark_filtering_set,
          masks=masks,
          index=cursor,
          lookup_mask=lookup_mask,
        )
        match ignored {
          Err(err) => return Err(err)
          Ok(true) => cursor = cursor + 1
          Ok(false) => {
            indices.push(cursor)
            cursor = cursor + 1
          }
        }
      }
      Ok(Some(indices))
    }
  }
}

///|
fn collect_backward_indices(
  glyphs : ArrayView[UInt],
  start_index : Int,
  count : Int,
  lookup_flag : Int,
  gdef : GdefTable?,
  mark_filtering_set : Int?,
  masks? : Array[UInt] = [],
  lookup_mask? : UInt = 0xFFFFFFFFU,
) -> Result[Array[Int]?, OtLayoutError] {
  if count < 0 {
    return Err(InvalidFormat)
  }
  if count == 0 {
    return Ok(Some([]))
  }
  let indices : Array[Int] = []
  let mut cursor = start_index - 1
  while indices.length() < count {
    if cursor < 0 {
      return Ok(None)
    }
    let ignored = should_ignore_glyph(
      glyphs[cursor],
      lookup_flag,
      gdef,
      mark_filtering_set,
      masks=masks,
      index=cursor,
      lookup_mask=lookup_mask,
    )
    match ignored {
      Err(err) => return Err(err)
      Ok(true) => cursor = cursor - 1
      Ok(false) => {
        indices.push(cursor)
        cursor = cursor - 1
      }
    }
  }
  Ok(Some(indices))
}