///|
/// One typed command from a Cairo path snapshot.
pub(all) enum PathSegment {
  PathSegmentMoveTo(Double, Double)
  PathSegmentLineTo(Double, Double)
  PathSegmentCurveTo(Double, Double, Double, Double, Double, Double)
  PathSegmentClosePath
} derive(Debug, Eq)

///|
/// An independently owned snapshot of Cairo path data.
type Path

///|
#borrow(path)
extern "c" fn cairo_path_status(path : Path) -> Int = "moonbit_cairo_path_status"

///|
/// Returns the status stored in this path snapshot.
pub fn Path::status(self : Path) -> Status {
  Status(cairo_path_status(self))
}

///|
#borrow(path)
extern "c" fn cairo_path_num_data(path : Path) -> Int = "moonbit_cairo_path_num_data"

///|
#borrow(path, type_, length, x1, y1, x2, y2, x3, y3)
extern "c" fn cairo_path_get_segment(
  path : Path,
  index : Int,
  type_ : Ref[Int],
  length : Ref[Int],
  x1 : Ref[Double],
  y1 : Ref[Double],
  x2 : Ref[Double],
  y2 : Ref[Double],
  x3 : Ref[Double],
  y3 : Ref[Double],
) -> Bool = "moonbit_cairo_path_get_segment"

///|
/// Copies the native path data into typed MoonBit segments.
///
/// A path with a non-success status produces an empty array; inspect
/// `Path::status` before consuming its segments when errors are possible.
pub fn Path::segments(self : Path) -> Array[PathSegment] {
  let data_count = cairo_path_num_data(self)
  let segments : Array[PathSegment] = []
  let mut index = 0
  while index < data_count {
    let type_ = Ref(0)
    let length = Ref(0)
    let x1 = Ref(0.0)
    let y1 = Ref(0.0)
    let x2 = Ref(0.0)
    let y2 = Ref(0.0)
    let x3 = Ref(0.0)
    let y3 = Ref(0.0)
    if !cairo_path_get_segment(
        self, index, type_, length, x1, y1, x2, y2, x3, y3,
      ) ||
      length.val <= 0 {
      break
    }
    match type_.val {
      0 => segments.push(PathSegmentMoveTo(x1.val, y1.val))
      1 => segments.push(PathSegmentLineTo(x1.val, y1.val))
      2 =>
        segments.push(
          PathSegmentCurveTo(x1.val, y1.val, x2.val, y2.val, x3.val, y3.val),
        )
      3 => segments.push(PathSegmentClosePath)
      _ => break
    }
    index += length.val
  }
  segments
}