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

///|
struct Loop(Bytes)

///|
extern "c" fn uv_loop_make() -> Loop = "moonbit_uv_loop_make"

///|
#owned(uv)
extern "c" fn uv_loop_init(uv : Loop) -> Int = "moonbit_uv_loop_init"

///|
/// Creates a new event loop instance.
///
/// Returns a new event loop that can be used for asynchronous I/O operations.
///
/// Throws an error of type `Errno` if the loop initialization fails due to
/// system resource constraints or other platform-specific issues.
///
/// Example:
///
/// ```moonbit nocheck
/// let uv = @uv.Loop::new()
/// uv.close()
/// ```
pub fn Loop::new() -> Loop raise Errno {
  let uv = uv_loop_make()
  let status = uv_loop_init(uv)
  if status < 0 {
    raise Errno::of_int(status)
  }
  return uv
}

///|
pub(all) enum LoopOption {
  BlockSignal(Signum)
  MeasureIdleTime
  UseIoUringSqPoll
}

///|
#owned(uv)
extern "c" fn uv_loop_configure_block_signal(uv : Loop, signum : Signum) -> Int = "moonbit_uv_loop_configure_block_signal"

///|
#owned(uv)
extern "c" fn uv_loop_configure(uv : Loop, option : Int) -> Int = "moonbit_uv_loop_configure"

///|
pub fn Loop::configure(self : Loop, option : LoopOption) -> Unit raise Errno {
  let status = match option {
    LoopOption::BlockSignal(signum) =>
      uv_loop_configure_block_signal(self, signum)
    LoopOption::MeasureIdleTime => uv_loop_configure(self, 1)
    LoopOption::UseIoUringSqPoll => uv_loop_configure(self, 2)
  }
  if status < 0 {
    raise Errno::of_int(status)
  }
}

///|
#owned(uv)
extern "c" fn uv_loop_close(uv : Loop) -> Int = "moonbit_uv_loop_close"

///|
/// Closes the event loop and releases its associated resources.
///
/// Parameters:
///
/// * `self` : The event loop to close.
///
/// Throws an error of type `Errno` if the loop cannot be closed properly, such
/// as when there are still active handles or requests associated with the loop.
///
/// Example:
///
/// ```moonbit nocheck
/// let uv = @uv.Loop::new()
/// uv.close()
/// ```
pub fn Loop::close(self : Loop) -> Unit raise Errno {
  let status = uv_loop_close(self)
  if status < 0 {
    raise Errno::of_int(status)
  }
}

///|
pub(all) enum RunMode {
  Default = 0
  Once = 1
  NoWait = 2
}

///|
#owned(uv)
extern "c" fn uv_run(uv : Loop, mode : RunMode) -> Int = "moonbit_uv_run"

///|
/// Runs the event loop with the specified mode.
///
/// Parameters:
///
/// * `self` : The event loop to run.
/// * `mode` : The run mode that determines how the loop executes. Can be
/// `Default` (runs until no more active handles), `Once` (runs once and
/// returns), or `NoWait` (polls for I/O once but doesn't block).
///
/// Throws an error of type `Errno` if the loop fails to run properly.
///
/// Example:
///
/// ```moonbit nocheck
/// let uv = @uv.Loop::new()
/// uv.run(Default)
/// uv.close()
/// ```
pub fn Loop::run(self : Loop, mode : RunMode) -> Unit raise Errno {
  let status = uv_run(self, mode)
  if status < 0 {
    raise Errno::of_int(status)
  }
}

///|
#owned(uv)
extern "c" fn uv_stop(uv : Loop) = "moonbit_uv_stop"

///|
pub fn Loop::stop(self : Loop) -> Unit {
  uv_stop(self)
}

///|
#owned(uv)
extern "c" fn uv_walk(uv : Loop, walk_cb : (Handle) -> Unit) = "moonbit_uv_walk"

///|
pub fn Loop::walk(self : Loop, walk_cb : (Handle) -> Unit) -> Unit {
  uv_walk(self, walk_cb)
}

///|
#owned(uv)
extern "c" fn uv_loop_alive(uv : Loop) -> Int = "moonbit_uv_loop_alive"

///|
pub fn Loop::alive(uv : Loop) -> Bool {
  return uv_loop_alive(uv) != 0
}

///|
#owned(uv)
extern "c" fn uv_loop_fork(uv : Loop) -> Int = "moonbit_uv_loop_fork"

///|
pub fn Loop::fork(uv : Loop) -> Unit raise Errno {
  let status = uv_loop_fork(uv)
  if status < 0 {
    raise Errno::of_int(status)
  }
}

///|
#owned(uv)
extern "c" fn uv_backend_fd(uv : Loop) -> Int = "moonbit_uv_backend_fd"

///|
pub fn Loop::backend_fd(uv : Loop) -> Int raise Errno {
  let status = uv_backend_fd(uv)
  if status < 0 {
    raise Errno::of_int(status)
  }
  return status
}

///|
#owned(uv)
extern "c" fn uv_backend_timeout(uv : Loop) -> Int = "moonbit_uv_backend_timeout"

///|
pub fn Loop::backend_timeout(uv : Loop) -> Int raise Errno {
  let status = uv_backend_timeout(uv)
  if status < 0 {
    raise Errno::of_int(status)
  }
  return status
}