using System;
using System.Numerics;
namespace Engine.Core;
public static class Math
{
    /// 
    /// The value of Pi (π).
    /// 
    public const float Pi = 3.1415926535897932f;
    /// 
    /// The value of Tau (τ), mathematical constant equal to 2π.
    /// 
    public const float Tau = 2f * Pi;
    /// 
    /// The base of the natural logarithm.
    /// 
    public const float E = 2.718281828459045f;
    /// 
    /// The conversion factor from radians to degrees.
    /// 
    public const float RadianToDegree = 180f / Pi;
    /// 
    /// The conversion factor from degrees to radians.
    /// 
    public const float DegreeToRadian = Pi / 180f;
    /// 
    /// Gets one minus of given .
    /// 
    /// The value .
    /// One minus of given .
    public static T OneMinus(T value) where T : INumber => T.One - value;
    /// 
    /// Adds two s.
    /// 
    /// The first .
    /// The second .
    /// The sum of the two s.
    public static T Add(T left, T value) where T : INumber => left + value;
    /// 
    /// Subtracts one  from another.
    /// 
    /// The  to subtract from.
    /// The  to subtract.
    /// The result of subtracting the second  from the first.
    public static T Subtract(T left, T value) where T : INumber => left - value;
    /// 
    /// Multiplies a  by a scalar value.
    /// 
    /// The .
    /// The scalar value.
    /// The result of multiplying the  by the scalar value.
    public static T Multiply(T left, T multiplier) where T : INumber => left * multiplier;
    /// 
    /// Divides a  by a scalar value.
    /// 
    /// The .
    /// The scalar value.
    /// The result of dividing the  by the scalar value.
    public static T Divide(T left, T divider) where T : INumber => left / divider;
    /// 
    /// Returns the true mathematical modulus of a  value. 
    /// Unlike the remainder operator (%), this result is always non-negative,
    /// even when the  operand is negative.
    /// 
    /// A numeric type that implements .
    /// The dividend  value.
    /// The modulus  value (must be non-zero).
    /// 
    /// The non-negative remainder of  divided by .
    /// 
    public static T Mod(T value, T modulus) where T : INumber
    {
        T result = value % modulus;
        if (result < T.Zero)
            result += modulus;
        return result;
    }
    /// 
    /// Returns the absolute value of a number.
    /// 
    /// The type of the number.
    /// The number.
    /// The absolute value of .
    public static T Abs(T x) where T : INumber => x > T.Zero ? x : -x;
    /// 
    /// Returns the cosine of a number.
    /// 
    /// The number.
    /// The cosine of .
    public static float Cos(float x) => MathF.Cos(x);
    /// 
    /// Returns the sine of a number.
    /// 
    /// The number.
    /// The sine of .
    public static float Sin(float x) => MathF.Sin(x);
    /// 
    /// Returns the tangent of a number.
    /// 
    /// The angle, in radians.
    /// The tangent of .
    public static float Tan(float x) => MathF.Tan(x);
    /// 
    /// Returns the arccosine of a number.
    /// 
    /// The number.
    /// The arccosine of .
    public static float Acos(float x) => MathF.Acos(x);
    /// 
    /// Returns the arcsine of a number.
    /// 
    /// The number.
    /// The arcsine of .
    public static float Asin(float x) => MathF.Asin(x);
    /// 
    /// Returns the angle whose tangent is the specified number.
    /// 
    /// The tangent value.
    /// The angle, in radians.
    public static float Atan(float x) => MathF.Atan(x);
    /// 
    /// Returns the angle whose tangent is the quotient of two specified numbers.
    /// 
    /// The y-coordinate of a point.
    /// The x-coordinate of a point.
    /// The angle, measured in radians.
    public static float Atan2(float y, float x) => MathF.Atan2(y, x);
    /// 
    /// Returns the hyperbolic arctangent of a number.
    /// 
    /// The number.
    /// The hyperbolic arctangent of .
    public static float Atanh(float x) => MathF.Atanh(x);
    /// 
    /// Clamps a number between a minimum and maximum value.
    /// 
    /// The type of the number.
    /// The number to clamp.
    /// The minimum value.
    /// The maximum value.
    /// The clamped value.
    public static T Clamp(T x, T min, T max) where T : INumber => (x < min) ? min : (x > max) ? max : x;
    /// 
    /// Returns the smallest integral value that is greater than or equal to the specified number.
    /// 
    /// The number.
    /// The smallest integral value that is greater than or equal to .
    public static float Ceiling(float x) => MathF.Ceiling(x);
    /// 
    /// Returns a value with the magnitude of  and the sign of .
    /// 
    /// The magnitude value.
    /// The sign value.
    /// A value with the magnitude of  and the sign of .
    public static float CopySign(float x, float y) => MathF.CopySign(x, y);
    /// 
    /// Returns the largest integral value that is less than or equal to the specified number.
    /// 
    /// The number.
    /// The largest integral value that is less than or equal to .
    public static float Floor(float x) => MathF.Floor(x);
    /// 
    /// Returns the remainder of the division of two specified numbers.
    /// 
    /// The dividend.
    /// The divisor.
    /// The remainder of the division of  by .
    public static float IEEERemainder(float x, float y) => MathF.IEEERemainder(x, y);
    /// 
    /// Returns the natural (base e) logarithm of a specified number.
    /// 
    /// The number.
    /// The base.
    /// The natural logarithm of  with base .
    public static float Log(float x, float y) => MathF.Log(x, y);
    /// 
    /// Returns the larger of two numbers.
    /// 
    /// The type of the numbers.
    /// The first number.
    /// The second number.
    /// The larger of  and .
    public static T Max(T x, T y) where T : INumber => (x > y) ? x : y;
    /// 
    /// Returns the number whose absolute value is larger.
    /// 
    /// The first number.
    /// The second number.
    /// The number whose absolute value is larger.
    public static T AbsMax(T x, T y) where T : INumber => (Abs(x) > Abs(y)) ? x : y;
    /// 
    /// Returns the smaller of two numbers.
    /// 
    /// The type of the numbers.
    /// The first number.
    /// The second number.
    /// The smaller of  and .
    public static T Min(T x, T y) where T : INumber => (x < y) ? x : y;
    /// 
    /// Returns the number whose absolute value is smaller.
    /// 
    /// The first number.
    /// The second number.
    /// The number whose absolute value is smaller.
    public static T AbsMin(T x, T y) where T : INumber => (Abs(x) < Abs(y)) ? x : y;
    /// 
    /// Returns a specified number raised to the specified power.
    /// 
    /// The number to raise to a power.
    /// The power to raise  to.
    /// The number  raised to the power .
    public static float Pow(float x, float y) => MathF.Pow(x, y);
    /// 
    /// Performs linear interpolation between two specified values.
    /// 
    /// The type of the values, which must implement .
    /// The starting value of the interpolation.
    /// The ending value of the interpolation.
    /// The interpolation factor, typically in the range [0, 1].
    /// A value that represents the linear interpolation between  and .
    public static T Lerp(T x, T y, T t) where T : IFloatingPoint => x + (y - x) * t;
    /// 
    /// Rounds a number to the closest integer.
    /// 
    /// The number to round.
    /// Specification for how to round  if it is midway between two other numbers.
    /// The number  rounded to the closest integer.
    public static float Round(float x, RoundMode roundMode) => RoundToInt(x, roundMode);
    /// 
    /// Rounds a number to the closest integer.
    /// 
    /// The number to round.
    /// Specification for how to round  if it's midway between two numbers
    /// The number  rounded to the closest integer.
    public static int RoundToInt(float x, RoundMode roundMode = RoundMode.Ceil)
    {
        float remainder = x.Mod(1f);
        if (remainder == .5f)
            if (roundMode == RoundMode.Floor)
                return (int)x;
            else
                return (int)(x + .5f);
        if (x < 0f)
            return (int)(x - .5f);
        return (int)(x + .5f);
    }
    public enum RoundMode { Ceil, Floor };
    /// 
    /// Returns the square of a number.
    /// 
    /// The type of the number.
    /// The number to square.
    /// The square of .
    public static T Sqr(T x) where T : INumber => x * x;
    /// 
    /// Returns the square root of a specified number.
    /// 
    /// The number.
    /// The square root of .
    public static float Sqrt(float x) => MathF.Sqrt(x);
    /// 
    /// Calculates the integral part of a number.
    /// 
    /// The number.
    /// The integral part of .
    public static float Truncate(float x) => MathF.Truncate(x);
}