// 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.

///|
/// A `MutArrayView` represents a view into a section of an array without copying the data.
/// The view provides read-write access to elements of the underlying array.
///
/// # Example
///
/// ```mbt check
/// test {
///   let arr = [1, 2, 3, 4, 5]
///   let view = arr.mut_view(start=1, end=4) // Creates a view of elements at indices 1,2,3
///   @test.assert_eq(view[0], 2)
///   @test.assert_eq(view.length(), 3)
/// }
/// ```
#builtin.valtype
type MutArrayView[T]

///|
fn[T] MutArrayView::buf(self : MutArrayView[T]) -> UninitializedArray[T] = "%arrayview.buf"

///|
fn[T] MutArrayView::start(self : MutArrayView[T]) -> Int = "%arrayview.start"

///|
fn[T] MutArrayView::len(self : MutArrayView[T]) -> Int = "%arrayview.len"

///|
fn[T] MutArrayView::make(
  buf : UninitializedArray[T],
  start : Int,
  len : Int,
) -> MutArrayView[T] = "%arrayview.make"

///|
/// Returns the length (number of elements) of a mutable array view.
///
/// Parameters:
///
/// * `array_view` : The mutable array view whose length is to be determined.
///
/// Returns an integer representing the number of elements in the mutable array view.
///
/// Example:
///
/// ```mbt check
/// test {
///   let arr = [1, 2, 3, 4, 5]
///   let view = arr.mut_view(start=2, end=4)
///   inspect(view.length(), content="2")
/// }
/// ```
#intrinsic("%mutarrayview.length")
pub fn[T] MutArrayView::length(self : MutArrayView[T]) -> Int {
  self.len()
}

///|
/// Returns whether the mutable array view is empty.
///
/// Example:
///
/// ```mbt check
/// test {
///   let view = [1, 2, 3].mut_view(start=1, end=1)
///   inspect(view.is_empty(), content="true")
/// }
/// ```
pub fn[T] MutArrayView::is_empty(self : MutArrayView[T]) -> Bool {
  self.length() == 0
}

///|
/// Returns the start offset of the mutable array view in its backing array.
pub fn[T] MutArrayView::start_offset(self : MutArrayView[T]) -> Int {
  self.start()
}

///|
/// Retrieves an element at the specified index from the mutable array view.
///
/// Parameters:
///
/// * `self` : The mutable array view to access.
/// * `index` : The position in the array view from which to retrieve the
/// element.
///
/// Returns the element at the specified index.
///
/// Throws a runtime error if the index is out of bounds (less than 0 or greater
/// than or equal to the length of the array view).
///
/// Example:
///
/// ```mbt check
/// test {
///   let arr = [1, 2, 3, 4, 5]
///   let view = arr.mut_view(start=2, end=4)
///   inspect(view[0], content="3")
///   inspect(view[1], content="4")
/// }
/// ```
#intrinsic("%mutarrayview.get")
#alias("_[_]")
pub fn[T] MutArrayView::at(self : MutArrayView[T], index : Int) -> T {
  guard index >= 0 && index < self.len() else {
    index_out_of_bounds(self.len(), index)
  }
  self.buf().unsafe_get(self.start() + index)
}

///|
/// Retrieves an element from the mutable array view at the specified index without
/// performing bounds checking.
///
/// Parameters:
///
/// * `array_view` : The mutable array view to retrieve the element from.
/// * `index` : The position in the array view from which to retrieve the
/// element.
///
/// Returns the element at the specified index in the array view.
///
/// Example:
///
/// ```mbt check
/// test {
///   let arr = [1, 2, 3, 4, 5]
///   let view = arr.mut_view(start=1, end=4)
///   inspect(view.unsafe_get(1), content="3")
/// }
/// ```
#intrinsic("%mutarrayview.unsafe_get")
#internal(unsafe, "Panic if index is out of bounds")
pub fn[T] MutArrayView::unsafe_get(self : MutArrayView[T], index : Int) -> T {
  self.buf()[self.start() + index]
}

///|
/// Sets an element at the specified index in the mutable array view.
///
/// Parameters:
///
/// * `self` : The mutable array view to modify.
/// * `index` : The position in the array view at which to set the element.
/// * `value` : The value to set at the specified index.
///
/// Throws a runtime error if the index is out of bounds (less than 0 or greater
/// than or equal to the length of the array view).
///
/// Example:
///
/// ```mbt check
/// test {
///   let arr = [1, 2, 3, 4, 5]
///   let view = arr.mut_view(start=2, end=4)
///   view[0] = 10
///   inspect(view[0], content="10")
///   inspect(arr[2], content="10")
/// }
/// ```
#intrinsic("%mutarrayview.set")
#alias("_[_]=_")
#owned(value)
pub fn[T] MutArrayView::set(
  self : MutArrayView[T],
  index : Int,
  value : T,
) -> Unit {
  guard index >= 0 && index < self.len() else {
    index_out_of_bounds(self.len(), index)
  }
  self.buf().unsafe_set(self.start() + index, value)
}

///|
/// Sets an element at the specified index in the mutable array view without
/// performing bounds checking.
///
/// Parameters:
///
/// * `self` : The mutable array view to modify.
/// * `index` : The position in the array view at which to set the element.
/// * `value` : The value to set at the specified index.
///
/// Example:
///
/// ```mbt check
/// test {
///   let arr = [1, 2, 3, 4, 5]
///   let view = arr.mut_view(start=1, end=4)
///   view.unsafe_set(1, 10)
///   inspect(view[1], content="10")
/// }
/// ```
#intrinsic("%mutarrayview.unsafe_set")
#internal(unsafe, "Panic if index is out of bounds")
#owned(value)
pub fn[T] MutArrayView::unsafe_set(
  self : MutArrayView[T],
  index : Int,
  value : T,
) -> Unit {
  self.buf()[self.start() + index] = value
}

///|
/// Creates a mutable view of a portion of the array. The view provides read-write access
/// to the underlying array without copying the elements.
///
/// Parameters:
///
/// * `array` : The array to create a view from.
/// * `start` : The starting index of the view (inclusive). Defaults to 0.
/// * `end` : The ending index of the view (exclusive). If not provided, defaults
/// to the length of the array.
///
/// Returns a `MutArrayView` that provides a window into the specified portion of
/// the array.
///
/// Throws a panic if the indices are invalid (i.e., `start` is negative, `end`
/// is greater than the array length, or `start` is greater than `end`).
///
/// Example:
///
/// ```mbt check
/// test {
///   let arr = [1, 2, 3, 4, 5]
///   let view = arr.mut_view(start=1, end=4) // Create a view of elements at indices 1, 2, and 3
///   inspect(view[0], content="2") // First element of view is arr[1]
///   inspect(view.length(), content="3") // View contains 3 elements
/// }
/// ```
pub fn[T] Array::mut_view(
  self : Array[T],
  start? : Int = 0,
  end? : Int,
) -> MutArrayView[T] {
  let len = self.length()
  let end = match end {
    Some(end) | (None with end = len) => end
  }
  guard start >= 0 && start <= end && end <= len else {
    abort("View index out of bounds")
  }
  MutArrayView::make(self.buffer(), start, end - start)
}

///|
/// Creates a new mutable view into a portion of the mutable array view.
///
/// Parameters:
///
/// * `self` : The mutable array view to create a new view from.
/// * `start` : The starting index in the current view (inclusive). Defaults to
/// 0.
/// * `end` : The ending index in the current view (exclusive). Defaults to the
/// length of the current view.
///
/// Returns a new `MutArrayView` that provides a window into the specified portion
/// of the original mutable array view. The indices are relative to the start of the
/// current view.
///
/// Throws a panic if:
///
/// * `start` is negative
/// * `end` is greater than the length of the current view
/// * `start` is greater than `end`
///
/// Example:
///
/// ```mbt check
/// test {
///   let arr = [1, 2, 3, 4, 5]
///   let view = arr.mut_view(start=1, end=4) // view = [2, 3, 4]
///   let subview = view.mut_view(start=1, end=2) // subview = [3]
///   inspect(subview[0], content="3")
/// }
/// ```
// TODO: rename does not work with docstring test
pub fn[T] MutArrayView::mut_view(
  self : MutArrayView[T],
  start? : Int = 0,
  end? : Int,
) -> MutArrayView[T] {
  let len = self.length()
  let end = match end {
    Some(end) | (None with end = len) => end
  }
  guard start >= 0 && start <= end && end <= len else {
    abort("View index out of bounds")
  }
  MutArrayView::make(self.buf(), self.start() + start, end - start)
}

///|
/// Creates a new mutable `ArrayView` from a `FixedArray`.
///
/// Parameters:
///
/// * `self` : The fixed array to create a new view from.
/// * `start` : The starting index in the array (inclusive). Defaults to 0.
/// * `end` : The ending index in the array (exclusive). Defaults to the
/// length of the array.
///
/// Returns a new `MutArrayView` that provides a window into the specified portion
/// of the original fixed array.
///
/// Throws a panic if:
///
/// * `start` is negative
/// * `end` is greater than the length of the array
/// * `start` is greater than `end`
///
/// Example:
///
/// ```mbt check
/// test {
///   let arr : FixedArray[Int] = [1, 2, 3, 4, 5]
///   let view = arr.mut_view(start=1, end=4) // view = [2, 3, 4]
///   inspect(view[0], content="2")
/// }
/// ```
pub fn[T] FixedArray::mut_view(
  self : FixedArray[T],
  start? : Int = 0,
  end? : Int,
) -> MutArrayView[T] {
  let len = self.length()
  let end = match end {
    Some(end) | (None with end = len) => end
  }
  guard start >= 0 && start <= end && end <= len else {
    abort("View index out of bounds")
  }
  MutArrayView::make(
    unsafe_cast_fixedarray_to_uninitializedarray(self),
    start,
    end - start,
  )
}

///|
/// Creates a new `ArrayView` from a `MutArrayView`.
///
/// Parameters:
///
/// * `self` : The mutable array view to create a new view from.
/// * `start` : The starting index in the array (inclusive). Defaults to 0.
/// * `end` : The ending index in the array (exclusive). Defaults to the
/// length of the array.
#alias("_[_:_]")
#alias(sub, deprecated="Use _[_:_] instead")
pub fn[T] MutArrayView::view(
  self : MutArrayView[T],
  start? : Int = 0,
  end? : Int,
) -> ArrayView[T] {
  let len = self.length()
  let end = match end {
    Some(end) | (None with end = len) => end
  }
  guard start >= 0 && start <= end && end <= len else {
    abort("View index out of bounds")
  }
  ArrayView::make(self.buf(), self.start() + start, end - start)
}

///|
/// Copies the elements of the mutable array view into a newly allocated `Array`.
#alias(to_array, deprecated)
pub fn[T] MutArrayView::to_owned(self : MutArrayView[T]) -> Array[T] {
  self[:].to_owned()
}

// 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.

///|
/// Return an iterator via `iter`.
#alias(iterator, deprecated)
pub fn[X] MutArrayView::iter(self : MutArrayView[X]) -> Iter[X] {
  let mut i = 0
  let len = self.length()
  Iter::new(
    fn() {
      guard i < len else { None }
      let elem = self.unsafe_get(i)
      i += 1
      Some(elem)
    },
    size_hint=len,
  )
}

///|
/// Function `rev_iter`.
#alias(rev_iterator, deprecated)
pub fn[X] MutArrayView::rev_iter(self : MutArrayView[X]) -> Iter[X] {
  let len = self.length()
  let mut i = len
  Iter::new(
    fn() {
      guard i > 0 else { None }
      i -= 1
      Some(self.unsafe_get(i))
    },
    size_hint=len,
  )
}

///|
/// Return an iterator via `iter2`.
#alias(iterator2, deprecated)
pub fn[X] MutArrayView::iter2(self : MutArrayView[X]) -> Iter2[Int, X] {
  let mut i = 0
  let len = self.length()
  Iter2::new(
    fn() {
      guard i < len else { None }
      let result = Some((i, self.unsafe_get(i)))
      i += 1
      result
    },
    size_hint=len,
  )
}

///|
#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
pub impl[X : Show] Show for MutArrayView[X]

///|
#warnings("-deprecated")
pub impl[X : Show] Show for MutArrayView[X] with fn output(self, logger) {
  self[:].output(logger)
}

///|
pub impl[T : Eq] Eq for MutArrayView[T] with fn equal(self, other) -> Bool {
  self[:] == other
}

///|
pub impl[T : Compare] Compare for MutArrayView[T] with fn compare(self, other) -> Int {
  self[:].compare(other)
}

///|
pub impl[A : Hash] Hash for MutArrayView[A] with fn hash_combine(self, hasher) {
  self[:].hash_combine(hasher)
}