////
/// @group utils.color
////

@use 'sass:color';
@use 'sass:list';

@use 'math.scss' as *;
@use 'units.scss' as *;

/// Return the red channel of a particular rgb color as either a value between 0 and 255 or as a float between 0 and 1.
/// @param {*} $color The color to be evaluated
/// @param {*} $as-float [false] If true, return the value as a float between 0 and 1

@function rgb-red($color, $as-float: false) {
    $v: color.channel($color, 'red', $space: rgb);
    @return if(sass($as-float): divide($v, 255) ; else: $v);
}

/// Return the green channel of a particular rgb color as either a value between 0 and 255 or as a float between 0 and 1.
/// @param {*} $color The color to be evaluated
/// @param {*} $as-float [false] If true, return the value as a float between 0 and 1

@function rgb-green($color, $as-float: false) {
    $v: color.channel($color, 'green', $space: rgb);
    @return if(sass($as-float): divide($v, 255) ; else: $v);
}

/// Return the blue channel of a particular rgb color as either a value between 0 and 255 or as a float between 0 and 1.
/// @param {*} $color The color to be evaluated
/// @param {*} $as-float [false] If true, return the value as a float between 0 and 1

@function rgb-blue($color, $as-float: false) {
    $v: color.channel($color, 'blue', $space: rgb);
    @return if(sass($as-float): divide($v, 255) ; else: $v);
}

///
/// Produce a shade (a lighter or darker version) of a color based on the value of $shade and an
/// optional darkest to lightest shade range.
///
/// @param {color} $color [null] The color to be shaded. If not provided, it will be calculated as
/// the middle value within $shade-range.
///
/// @param {number} $shade [0]The shading to be applied, as a percentage from -100% to 100% (for
/// legacy reasons we also take a value between -10, 10 and convert to a percentage).
///
/// @param {(color, color)} $shade-range [null] The range of colors will be produced as a list
/// (darkest, lightest).
///
/// @example $color: shade(red, 5, null) // => #ff8080
///

@function color-shade(
    $color: null,
    $shade: 0,
    $shade-range: (
        black,
        white,
    )
) {
    $shade: if(sass(is-percentage($shade)): $shade; else: $shade * 10%);

    $shade: clamp-number($shade, -100%, 100%);

    @if ($color == null) {
        $color: color.mix(list.nth($shade-range, 1), list.nth($shade-range, 2));
    }

    @if ($shade < 0) {
        $color1: list.nth($shade-range, 1);
        @return color.mix($color1, $color, $shade * -1);
    }

    @if ($shade > 0) {
        @return color.mix(list.nth($shade-range, 2), $color, $shade);
    }

    @return $color;
}

/// Choose a contrasting foreground based on the contrast between a background and two foreground
/// options (a light and dark).
///
/// @example contrast-color(rgb(233, 229, 31), rgb(199, 192, 192), rgb(133, 133, 231)) // => #8585e7

@function color-contrast($bg, $light-fg: white, $dark-fg: black, $contrast-threshold: 128) {
    @if (not(is-color($bg))) {
        $bg: clr($bg);
    }
    @return if(sass(yiq($bg) < $contrast-threshold): $light-fg; else: $dark-fg);
}

/// Computes the the luminance (grayscale value) of a color in the yiq color space. This can be used
/// for determining the relative contrast between two colors.
///
/// @example yiq(purple) // => 52.864

@function yiq($color) {
    $r: rgb-red($color);
    $g: rgb-green($color);
    $b: rgb-blue($color);
    $yiq: (($r * 299) + ($g * 587) + ($b * 114)) * 0.001;

    // 0 (black) - 255 (white)
    @return $yiq;
}

/// Calculates luminance of a color based on the WCAG2 standard Luminance calculation based on:
/// https://www.w3.org/TR/WCAG20/#relativeluminancedef
///
@function luminance($color) {
    $R: rgb-red($color, true);
    $G: rgb-green($color, true);
    $B: rgb-blue($color, true);

    @if $R <= 0.03928 {
        $R: divide($R, 12.92);
    } @else {
        $R: nth-root(pow(divide($R + 0.055, 1.055), 24), 10);
    }

    @if $G <= 0.03928 {
        $G: divide($G, 12.92);
    } @else {
        $G: nth-root(pow(divide($G + 0.055, 1.055), 24), 10);
    }

    @if $B <= 0.03928 {
        $B: divide($B, 12.92);
    } @else {
        $B: nth-root(pow(divide($B + 0.055, 1.055), 24), 10);
    }

    @return $R * 0.2126 + $G * 0.7152 + $B * 0.0722;
}

// Calculates the contrast ratio of two colors based on the WCAG2 standard:
// https://www.w3.org/TR/WCAG20/#contrast-ratiodef
// (named contrast-ratio to avoid shadowing color-contrast above)

@function contrast-ratio($color1, $color2) {
    @if luminance($color1) > luminance($color2) {
        @return divide((luminance($color1) + 0.05), (luminance($color2) + 0.05));
    } @else {
        @return divide((luminance($color2) + 0.05), (luminance($color1) + 0.05));
    }
}
