use std::ops::{Bound, RangeBounds};

use lotus_script::rand::{gen_f64, gen_u64};

/// Returns a random element from a slice.
///
/// Selects a random element from the provided slice using uniform distribution.
/// The slice must not be empty.
///
/// # Arguments
///
/// * `vec` - A non-empty slice to select from
///
/// # Returns
///
/// A reference to a randomly selected element
///
/// # Panics
///
/// Panics if the slice is empty (when `vec.len()` is 0).
///
/// # Examples
///
/// ```
/// # use your_crate::helper::get_random_element;
/// let items = vec!["apple", "banana", "cherry"];
/// let random_fruit = get_random_element(&items);
/// assert!(items.contains(random_fruit));
/// ```
pub fn get_random_element<T>(vec: &[T]) -> &T {
    let index = gen_u64(0..(vec.len() as u64)) as usize;
    &vec[index]
}

/// Generates a random boolean value.
///
/// Returns `true` or `false` with equal probability (50% each).
///
/// # Returns
///
/// A randomly generated boolean value
///
/// # Examples
///
/// ```
/// # use your_crate::helper::gen_bool;
/// let random_decision = gen_bool();
/// // random_decision is either true or false
/// ```
#[must_use]
pub fn gen_bool() -> bool {
    gen_f64() > 0.5
}

/// Generates a random f32 value within the specified range.
///
/// Generates a uniformly distributed random floating-point number within the given range.
/// Supports inclusive and exclusive bounds, as well as unbounded ranges.
///
/// # Arguments
///
/// * `range` - A range specification (e.g., `0.0..1.0`, `0.0..=1.0`, `..`, etc.)
///
/// # Returns
///
/// A random f32 value within the specified range
///
/// # Examples
///
/// ```
/// # use your_crate::helper::gen_f32;
/// // Generate between 0.0 and 1.0 (exclusive)
/// let value1 = gen_f32(0.0..1.0);
/// assert!(value1 >= 0.0 && value1 < 1.0);
///
/// // Generate between -5.0 and 5.0 (inclusive)
/// let value2 = gen_f32(-5.0..=5.0);
/// assert!(value2 >= -5.0 && value2 <= 5.0);
/// ```
pub fn gen_f32(range: impl RangeBounds<f32>) -> f32 {
    let min = match range.start_bound() {
        Bound::Included(min) => *min,
        Bound::Excluded(min) => min + 1.0,
        Bound::Unbounded => 0.0,
    };

    let max = match range.end_bound() {
        Bound::Included(max) => *max,
        Bound::Excluded(max) => max - 1.0,
        Bound::Unbounded => f32::MAX,
    };

    min + ((gen_f64() as f32) * (max - min))
}
