////
/// @group utils.math
////
///built in math module
@use 'sass:math';

/// Calculate a number raised to the power of the provided exponent.
/// @param {*} $base The base number
/// @param {*} $exp The exponent used to raise the base
///
///@example pow(2, 3)

@function pow($base, $exp) {
    $value: 1;
    @if $exp > 0 {
        @for $i from 1 through $exp {
            $value: $value * $base;
        }
    }
    @return $value;
}

/// Round a number using the specified number of decimals.
/// @param {number} $n The number to be rounded
/// @param {number} $dec [2] The number of decimals in the output
///
///@example $val: round-d(3.33333333, 2) // => 3.33

@function round-d($n, $dec: 2) {
    $p: pow(10, $dec);
    $r: round($n * $p);
    @warn $n $dec $p $r;
    @return math.div(round($n * $p), $p);
}

/// Round a number with the specified fraction (e.g. 4 will produce 1.0, 1.25, 1.5, etc.)
/// @param {number} $n The number to be rounded
/// @param {number} $frac [8] The denominator of the fractional portion of the result
///
///@example $val: round-f(3.3333, 2) // => 3.5
@function round-f($n, $frac: 8) {
    @if ($frac) {
        @return math.div(round($n * $frac), $frac);
    } @else {
        @return round($n);
    }
}

/// Interpolate between two values.
///
/// @param {number} $prog The progress between the two values, provided as a value between 0 and 1.
///
/// @param {number} $range The range of interpolation. This can be provided as a single value which
/// represents the upper range from 0 or as two values which represent the lower and upper range.
///
/// @param {string} $ease A reference to an easing function. See the ease function for details
///
/// @example
/// intp(0.5, 4) // => 2
///
/// @example
/// intp(0.5, (1, 3) // => 2

@function intp($prog, $range, $ease: false, $round: false) {
    $from: 0;
    $to: $range;

    @if (type-of($to) == 'list') {
        $from: nth($to, 1);
        $to: nth($to, 2);
    }

    @if ($ease) {
        $prog: ease($prog, $ease);
    }

    $result: $from + ($prog * ($to - $from));

    @if ($round) {
        @return round-f($result, $round);
    }
    @return $result;
}

// Easing functions based on these normalized versions of Penner:
// https://github.com/CharlotteGore/functional-easing/blob/master/penner-easing.js

/// Interpolate a value between 0 and 1 using the easing function with the given name
/// @param {number} $t The input value between 0 and 1
/// @param {String} $easing The name of the easing function that should be used for interpolation
/// @return {number} The eased equivalent of the input (also between 0 and 1).
///
///@example ease(0.5, 'out-quad') // => 0.75

@function ease($t, $easing: 'out-quad') {
    @if $easing == 'in-quad' {
        @return ease-in-quad($t);
    }
    @if $easing == 'out-quad' {
        @return ease-out-quad($t);
    }
    @if $easing == 'in-quart' {
        @return ease-in-quart($t);
    }
    @if $easing == 'out-quart' {
        @return ease-out-quart($t);
    }
    @if $easing == 'in-cubic' {
        @return ease-in-cubic($t);
    }
    @if $easing == 'out-cubic' {
        @return ease-out-cubic($t);
    }
    @return $t;
}

/// Interpolate a value between 0 and 1 using the Penner ease-in quad function.
/// @param {number} $t The input value between 0 and 1
/// @return {number} The eased equivalent of the input (also between 0 and 1).
///
///@example ease-in-quad(0.5) // => 0.25

@function ease-in-quad($t) {
    @return $t * $t;
}

/// Interpolate a value between 0 and 1 using the Penner ease-out quad function.
/// @param {number} $t The input value between 0 and 1
/// @return {number} The eased equivalent of the input (also between 0 and 1).
///
///@example ease-out-quad(0.25) // => 0.4375;

@function ease-out-quad($t) {
    @return -1 * $t * ($t - 2);
}

/// Interpolate a value between 0 and 1 using the Penner ease-in cubic function.
/// @param {number} $t The input value between 0 and 1
/// @return {number} The eased equivalent of the input (also between 0 and 1).
///
///@example ease-in-cubic(0.5) // => 0.125;
@function ease-in-cubic($t) {
    @return $t * $t * $t;
}

/// Interpolate a value between 0 and 1 using the Penner ease-out cubic function.
/// @param {number} $t The input value between 0 and 1
/// @return {number} The eased equivalent of the input (also between 0 and 1).
///
///@example ease-out-cubic(0.25) // => 0.578125
@function ease-out-cubic($t) {
    $t: $t - 1;
    @return $t * $t * $t + 1;
}

/// Interpolate a value between 0 and 1 using the Penner ease-in quart function.
/// @param {number} $t The input value between 0 and 1
/// @return {number} The eased equivalent of the input (also between 0 and 1).
///
///@example ease-in-quart(0.3) // => 0.0081

@function ease-in-quart($t) {
    @return $t * $t * $t * $t;
}

/// Interpolate a value between 0 and 1 using the Penner ease-out quart function.
/// @param {number} $t The input value between 0 and 1
/// @return {number} The eased equivalent of the input (also between 0 and 1).
///
///@example ease-out-quart(0.5) // => 0.9375

@function ease-out-quart($t) {
    $t: $t - 1;
    @return -1 * ($t * $t * $t * $t - 1);
}

/// Clamp a number (keep it within the confines of min/max). Note: the weird
/// name is to differentiate from the clamp() css function.
///
/// @param {*} $number The number to be clampled
/// @param {*} $min Min allowed value
/// @param {*} $max Max allowed value
///
///@example clamp-number(4, 3, 10) // => 4 is above the min

@function clamp-number($number, $min, $max) {
    @return min(max($number, $min), $max);
}

/// Provides a wrapper for the standard sass divide function (math.div) to make imports a little
/// simpler. Returns the result of dividing $num1 by $num2.
///
/// @param {number} $num1 The first number in the division operation (the numerator)
/// @param {number} $num2 The first number in the division operation (the numerator)
///
///@example divide(10, 2) // => 5
@function divide($num1, $num2) {
    @return math.div($num1, $num2);
}

/// Convience function that divides two numbers and the multiples the result by 100%
///
/// @param {number} $num1 The first number in the division operation (the numerator)
/// @param {number} $num2 The first number in the division operation (the numerator)
/// @param {number} $round The number of digits to use when rounding the output
///
///@example percent(10, 3, 2) // => 333.33%
@function percent($num1, $num2, $round: 3) {
    @return round-d(math.div($num1, $num2) * 100%, $round);
}
