/*
 * @license Private Source License v1.0.0
 * @copyright 2023 Reinhardt Weyers
 *
 * @author Reinhardt Weyers
 *
 * @version 0.1.0
 * 
 * Created On: 04/12/25
 * Last edited: 04/12/25
 */

using UnityEngine;

namespace RetroDev.Random
{
    public static class RandomUtil
    {
        /// <summary>
        /// Returns a random boolean value with an optional probability of being true.
        /// </summary>
        /// <param name="probability">Probability of returning true (default is 0.5).</param>
        /// <returns>Random boolean value.</returns>
        public static bool RandomBool(double probability = 0.5)
        {
            return UnityEngine.Random.value < probability;
        }

        /// <summary>
        /// Returns a random integer between the specified range (inclusive on the min and exclusive on the max).
        /// </summary>
        /// <param name="min">Minimum value (inclusive).</param>
        /// <param name="max">Maximum value (exclusive).</param>
        /// <returns>Random integer.</returns>
        public static int RandomNumber(int min, int max)
        {
            return UnityEngine.Random.Range(min, max);
        }

        /// <summary>
        /// Returns a random float between the specified range (inclusive on the min and exclusive on the max).
        /// </summary>
        /// <param name="min">Minimum value (inclusive).</param>
        /// <param name="max">Maximum value (exclusive).</param>
        /// <returns>Random float.</returns>
        public static float RandomFloat(float min, float max)
        {
            return UnityEngine.Random.Range(min, max);
        }

        /// <summary>
        /// Returns a random element from an array.
        /// </summary>
        /// <typeparam name="T">Type of the array elements.</typeparam>
        /// <param name="array">Array from which to select a random element.</param>
        /// <returns>Random element from the array.</returns>
        public static T RandomElement<T>(T[] array)
        {
            if (array == null || array.Length == 0)
                return default;

            return array[UnityEngine.Random.Range(0, array.Length)];
        }

        /// <summary>
        /// Returns a random color.
        /// </summary>
        /// <returns>Random color.</returns>
        public static Color RandomColor()
        {
            // Generate random integer values for RGB components
            int r = UnityEngine.Random.Range(0, 256);
            int g = UnityEngine.Random.Range(0, 256);
            int b = UnityEngine.Random.Range(0, 256);

            // Convert integers to floats between 0 and 1
            float floatR = r / 255f;
            float floatG = g / 255f;
            float floatB = b / 255f;

            // Create and return the color
            return new Color(floatR, floatG, floatB);
        }

        /// <summary>
        /// Returns a random 3D vector within specified ranges.
        /// </summary>
        /// <param name="min">Minimum values for each axis.</param>
        /// <param name="max">Maximum values for each axis.</param>
        /// <returns>Random 3D vector.</returns>
        public static Vector3 RandomVector3D(Vector3 min, Vector3 max)
        {
            return new Vector3(
                UnityEngine.Random.Range(min.x, max.x),
                UnityEngine.Random.Range(min.y, max.y),
                UnityEngine.Random.Range(min.z, max.z)
                );
        }

        /// <summary>
        /// Returns a random 2D vector within specified ranges.
        /// </summary>
        /// <param name="min">Minimum values for each axis.</param>
        /// <param name="max">Maximum values for each axis.</param>
        /// <returns>Random 2D vector.</returns>
        public static Vector2 RandomVector2D(Vector2 min, Vector2 max)
        {
            return new Vector2(
                UnityEngine.Random.Range(min.x, max.x),
                UnityEngine.Random.Range(min.y, max.y)
                );
        }


        /// <summary>
        /// Returns a random 3D rotation.
        /// </summary>
        /// <returns>Random 3D rotation.</returns>
        public static Quaternion RandomRotation3D()
        {
            return Quaternion.Euler(
                UnityEngine.Random.Range(0f, 360f),
                UnityEngine.Random.Range(0f, 360f),
                UnityEngine.Random.Range(0f, 360f)
            );
        }

        /// <summary>
        /// Returns a random 2D rotation around the Z-axis.
        /// </summary>
        /// <returns>Random 2D rotation.</returns>
        public static Quaternion RandomRotation2D()
        {
            return Quaternion.Euler(0f, 0f, UnityEngine.Random.Range(0f, 360f));
        }

        /// <summary>
        /// Returns a random angle in radians.
        /// </summary>
        /// <returns>Random angle in radians.</returns>
        public static float RandomAngle()
        {
            return UnityEngine.Random.Range(0f, 2f * Mathf.PI);
        }


        /// <summary>
        /// Returns a random direction on the unit circle (2D).
        /// </summary>
        /// <returns>Random 2D vector on the unit circle.</returns>
        public static Vector2 RandomOnUnitCircle()
        {
            float angle = UnityEngine.Random.Range(0f, 2f * Mathf.PI);
            return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
        }

        /// <summary>
        /// Returns a random value from a normal distribution.
        /// </summary>
        /// <param name="mean">Mean value of the distribution.</param>
        /// <param name="standardDeviation">Standard deviation of the distribution.</param>
        /// <returns>Random value from a normal distribution.</returns>
        public static float RandomNormalDistribution(float mean, float standardDeviation)
        {
            return mean + UnityEngine.Random.Range(-1f, 1f) * standardDeviation;
        }

        /// <summary>
        /// Returns a random audio clip from an array of audio clips.
        /// </summary>
        /// <param name="audioClips">Array of audio clips.</param>
        /// <returns>Random audio clip.</returns>
        public static AudioClip RandomAudioClip(AudioClip[] audioClips)
        {
            return RandomElement(audioClips);
        }


        /// <summary>
        /// Returns a random element from a list.
        /// </summary>
        /// <typeparam name="T">Type of the list elements.</typeparam>
        /// <param name="list">List from which to select a random element.</param>
        /// <returns>Random element from the list.</returns>
        public static T RandomElement<T>(System.Collections.Generic.List<T> list)
        {
            if (list == null || list.Count == 0)
                return default;

            return list[UnityEngine.Random.Range(0, list.Count)];
        }
    }
}
