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

///|
type Random

///|
pub impl ToReq for Random with to_req(self : Random) -> Req = "%identity"

///|
extern "c" fn uv_random_make() -> Random = "moonbit_uv_random_make"

///|
#owned(uv, req, buffer)
extern "c" fn uv_random(
  uv : Loop,
  req : Random,
  buffer : Bytes,
  buffer_offset : Int,
  buffer_length : Int,
  flags : Int,
  random_cb : (Random, Int, Bytes, Int, Int) -> Unit,
) -> Int = "moonbit_uv_random"

///|
#as_free_fn
pub fn Loop::random(
  self : Loop,
  buffer : BytesView,
  flags : Int,
  random_cb : (BytesView) -> Unit,
  error_cb : (Errno) -> Unit,
) -> Random raise Errno {
  fn uv_random_cb(_, status, buffer : Bytes, offset, length) {
    if status < 0 {
      error_cb(Errno::of_int(status))
    } else {
      random_cb(buffer[offset:offset + length])
    }
  }

  let req = uv_random_make()
  let buffer_offset = buffer.start_offset()
  let buffer_length = buffer.length()
  let buffer = buffer.data()
  let status = uv_random(
    self, req, buffer, buffer_offset, buffer_length, flags, uv_random_cb,
  )
  if status < 0 {
    raise Errno::of_int(status)
  }
  return req
}

///|
#owned(uv, req, buffer)
extern "c" fn uv_random_sync(
  uv : Loop,
  req : Random,
  buffer : Bytes,
  buffer_offset : Int,
  buffer_length : Int,
  flags : Int,
) -> Int = "moonbit_uv_random_sync"

///|
/// Synchronously generates random data.
///
/// The synchronous version may block indefinitely when not enough entropy is
/// available. This function blocks the current thread until the random data
/// generation completes. Unlike the asynchronous `random` function, this 
/// operation does not require callbacks and returns immediately upon successful 
/// completion or failure.
///
/// Parameters:
///
/// * `self` : The event loop instance to perform the operation on.
/// * `buffer` : A view of the buffer to fill with random data.
/// * `flags` : Flags to control the random data generation (typically 0).
///
/// Throws an error of type `Errno` if random data cannot be generated (e.g.,
/// insufficient entropy or system resource exhaustion).
///
/// Example:
///
/// ```moonbit nocheck
/// let uv = @uv.Loop::new()
/// let buffer = Bytes::make(16, 0)
/// uv.random_sync(buffer[:], 0)
/// // buffer now contains random data
/// uv.close()
/// ```
#as_free_fn
pub fn Loop::random_sync(
  self : Loop,
  buffer : BytesView,
  flags : Int,
) -> Unit raise Errno {
  let req = uv_random_make()
  let buffer_offset = buffer.start_offset()
  let buffer_length = buffer.length()
  let buffer_data = buffer.data()
  let status = uv_random_sync(
    self, req, buffer_data, buffer_offset, buffer_length, flags,
  )
  if status < 0 {
    raise Errno::of_int(status)
  }
}