@use 'sass:list';
@use 'sass:meta';
@use 'sass:math';
@use 'sass:string';

$interactionStates: hover, focused, focused-visible, active;
$propertyOptions:
    background-color, background, border, border-bottom-color, border-color, border-left-color,
    border-right-color, border-top-color, box-shadow, caret-color, color, column-rule,
    column-rule-color, filter, opacity, outline-color, outline, text-decoration,
    text-decoration-color, text-shadow;

@mixin validateColorProperty($color) {
    @if meta.type-of($color) != color {
        @if meta.type-of($color) == string {
            @if string.index($color, 'var(--') != 1 {
                @error "#{$color} is not a valid color. Expected a variable or a color.";
            }
        } @else {
            @error "#{$color} is not a valid color. Expected a variable or a color.";
        }
    }
}

@mixin validatePropType($prop) {
    @if not list.index($propertyOptions, $prop) and string.index($prop, '--') != 1 {
        @error "#{$prop} is not a valid property. Expected a variable or one of #{$propertyOptions}.";
    }
}

$stepLevelOptions: 3, 6;
@mixin validateStepLevel($stepLevel) {
    @if meta.type-of($stepLevel) != number {
        @if meta.type-of($stepLevel) == string {
            @if string.index($stepLevel, 'var(--') != 1 {
                @error "#{$stepLevel} is not a valid step level. Expected a variable or one of #{$stepLevelOptions}.";
            }
        } @else {
            @error "#{$stepLevel} is not a valid step level. Expected a variable or one of #{$stepLevelOptions}.";
        }
    } @else {
        @if not list.index($stepLevelOptions, $stepLevel) {
            @error "#{$stepLevel} is not a valid step level. Expected one of #{$stepLevelOptions}.";
        }
    }
}

@mixin interactionStates($prop, $color, $allStates, $stepLevel: 6) {
    // Verify that all states passed are valid
    @each $state in $allStates {
        @if not list.index($interactionStates, $state) {
            @error "#{$state} is not a valid interaction state. Expected one of #{$interactionStates}.";
        }
    }

    & {
        #{$prop}: $color;
    }

    @each $state in $allStates {
        @if $state == 'hover' {
            &:hover:not([disabled]):not([aria-disabled='true']) {
                #{$prop}: hsl(from $color h s calc(l + $stepLevel));
            }
        } @else if $state == 'focused' {
            &:focus:not([disabled]):not([aria-disabled='true']) {
                #{$prop}: hsl(from $color h s calc(l + $stepLevel));
            }
        } @else if $state == 'focused-visible' {
            &:focus-visible:not([disabled]):not([aria-disabled='true']) {
                #{$prop}: hsl(from $color h s calc(l + $stepLevel));
            }
        } @else if $state == 'active' {
            &:active:not([disabled]):not([aria-disabled='true']) {
                #{$prop}: hsl(from $color h s calc(l - 3));
            }
        }
    }

    @supports (color: hsl(from red h s calc(l + 1%))) {
        @each $state in $allStates {
            @if $state == 'hover' {
                &:hover:not([disabled]):not([aria-disabled='true']) {
                    @if meta.type-of($stepLevel) == string and str-index($stepLevel, 'var(--') == 1
                    {
                        #{$prop}: hsl(from $color h s calc(l + #{$stepLevel} * 1%));
                    } @else {
                        #{$prop}: hsl(from $color h s calc(l + calc($stepLevel / 100)));
                    }
                }
            } @else if $state == 'focused' {
                &:focus:not([disabled]):not([aria-disabled='true']) {
                    @if meta.type-of($stepLevel) == string and str-index($stepLevel, 'var(--') == 1
                    {
                        #{$prop}: hsl(from $color h s calc(l + #{$stepLevel} * 1%));
                    } @else {
                        #{$prop}: hsl(from $color h s calc(l + calc($stepLevel / 100)));
                    }
                }
            } @else if $state == 'focused-visible' {
                &:focus-visible:not([disabled]):not([aria-disabled='true']) {
                    @if meta.type-of($stepLevel) == string and str-index($stepLevel, 'var(--') == 1
                    {
                        #{$prop}: hsl(from $color h s calc(l + #{$stepLevel} * 1%));
                    } @else {
                        #{$prop}: hsl(from $color h s calc(l + calc($stepLevel / 100)));
                    }
                }
            } @else if $state == 'active' {
                &:active:not([disabled]):not([aria-disabled='true']) {
                    #{$prop}: hsl(from $color h s calc(l - 3%));
                }
            }
        }
    }

    @include validateColorProperty($color);
    @include validatePropType($prop);
    @include validateStepLevel($stepLevel);
}

@mixin hoverColor($prop, $color, $stepLevel: 3) {
    & {
        #{$prop}: hsl(from $color h s calc(l + $stepLevel));
    }

    @supports (color: hsl(from red h s calc(l + 1%))) {
        @if meta.type-of($stepLevel) == string and string.index($stepLevel, 'var(--') == 1 {
            #{$prop}: hsl(from $color h s calc(l + #{$stepLevel} * 1%));
        } @else {
            #{$prop}: hsl(from $color h s calc(l + calc($stepLevel / 100)));
        }
    }

    @include validateColorProperty($color);
    @include validatePropType($prop);
    @include validateStepLevel($stepLevel);
}

@mixin pressedColor($prop, $color) {
    & {
        #{$prop}: hsl(from $color h s calc(l - 3));
    }

    @supports (color: hsl(from red h s calc(l + 1%))) {
        #{$prop}: hsl(from $color h s calc(l - 3%));
    }

    @include validateColorProperty($color);
    @include validatePropType($prop);
}

@mixin backgroundColor($prop, $color) {
    & {
        #{$prop}: hsl(from $color h s 15%);
    }

    @include validateColorProperty($color);
    @include validatePropType($prop);
}
