///|
/// Moves the focus to the first element (start of the list).
pub fn[T] Zipper::move_to_start(self : Zipper[T]) -> Zipper[T] {
  match self.move_left() {
    Some(next) => next.move_to_start()
    None => self
  }
}

///|
/// Moves the focus to the last element (end of the list).
pub fn[T] Zipper::move_to_end(self : Zipper[T]) -> Zipper[T] {
  match self.move_right() {
    Some(next) => next.move_to_end()
    None => self
  }
}
// Helper function to create a list from an array for easy testing.

///|
pub fn[T] MList::from_array(arr : Array[T]) -> MList[T] {
  arr.rev_fold(init=Nil, fn(acc, x) { Cons(x, acc) })
}

///|
/// Creates a zipper from a list, focusing on the first element.
/// Returns `None` if the list is empty.
pub fn[T] Zipper::from_list(list : MList[T]) -> Zipper[T]? {
  match list {
    Nil => None
    Cons(head, tail) => Some({ left: Nil, focus: head, right: tail })
  }
}

///|
/// Converts a zipper back into a list.
pub fn[T] Zipper::to_list(self : Zipper[T]) -> MList[T] {
  loop (self.left.reverse(), Cons(self.focus, self.right)) {
    (Nil, acc) => acc
    (Cons(head, tail), acc) => continue (tail, Cons(head, acc))
  }
}

///|
/// Returns the element currently in focus.
pub fn[T] Zipper::current(self : Zipper[T]) -> T {
  self.focus
}

///|
/// Moves the focus one step to the right.
/// Returns `None` if already at the end of the list.
pub fn[T] Zipper::move_right(self : Zipper[T]) -> Zipper[T]? {
  match self.right {
    Nil => None
    Cons(new_focus, new_right) => {
      let new_left = Cons(self.focus, self.left)
      Some({ left: new_left, focus: new_focus, right: new_right })
    }
  }
}

///|
/// Moves the focus one step to the left.
/// Returns `None` if already at the beginning of the list.
pub fn[T] Zipper::move_left(self : Zipper[T]) -> Zipper[T]? {
  match self.left {
    Nil => None
    Cons(new_focus, new_left) => {
      let new_right = Cons(self.focus, self.right)
      Some({ left: new_left, focus: new_focus, right: new_right })
    }
  }
}

///|
/// Replaces the focused element with a new value.
pub fn[T] Zipper::update(self : Zipper[T], new_focus : T) -> Zipper[T] {
  { ..self, focus: new_focus }
}

///|
/// Inserts an element to the left of the focus. The new element remains on the left.
pub fn[T] Zipper::insert_left(self : Zipper[T], value : T) -> Zipper[T] {
  { ..self, left: Cons(value, self.left) }
}

///|
/// Inserts an element to the right of the focus. The new element remains on the right.
pub fn[T] Zipper::insert_right(self : Zipper[T], value : T) -> Zipper[T] {
  { ..self, right: Cons(value, self.right) }
}

///|
/// Deletes the focused element.
/// Focus moves to the right if possible, otherwise to the left.
/// Returns `None` if the deletion results in an empty list.
pub fn[T] Zipper::delete(self : Zipper[T]) -> Zipper[T]? {
  match self.right {
    Cons(new_focus, new_right) =>
      Some({ ..self, focus: new_focus, right: new_right })
    Nil =>
      match self.left {
        Cons(new_focus, new_left) =>
          Some({ left: new_left, focus: new_focus, right: Nil })
        Nil => None
      }
  }
}