// ============================================================================================= //
//                                            MIXINS                                             //
// ============================================================================================= //

@use "sass:list";
@use "sass:map";
@use "@unsass/breakpoint";
@use "@unsass/css";
@use "@unsass/selector";
@use "@unsass/string";
@use "@unsass/types" as type;
@use "./variables";
@use "./functions";

// ------------------------------------------------------------------------- //
// Private mixins
// ------------------------------------------------------------------------- //

///
/// Selector.
///
@mixin _selector($name, $prefix: null) {
    $separator: null;

    @if $prefix {
        $separator: "-";
    }

    @include selector.create($name, $prefix, $separator) {
        @content;
    }
}

///
/// Declaration.
///
@mixin _declaration($property, $value, $filter: false) {
    @if $filter {
        $value: #{$property}(string.unquote($value));
        $property: "filter";
    }

    @if type.is-string($value) {
        $value: string.unquote($value);
    }

    @include css.declaration($property, $value, variables.$important);
}

///
/// Breakpoint.
///
@mixin _breakpoint {
    @if functions.has-breakpoints() {
        @each $key, $value in breakpoint.get-screens() {
            @include breakpoint.up($key) {
                @include selector.create("#{list.nth(&, 1)}", $key, variables.$separator, $root: true) {
                    @content;
                }
            }
        }
    }
}

@mixin _between-breakpoint {
    $source-map: breakpoint.get-screens();
    $max-map: breakpoint.get-screens();

    @if functions.has-breakpoints() {
        @each $key, $value in $source-map {
            $index: list.index($source-map, $key $value);

            @each $key2, $value2 in $max-map {
                $index-max: list.index($max-map, $key2 $value2);

                @if $index-max >= $index {
                    @include breakpoint.between($key, breakpoint.get-next($key2)) {
                        @include selector.create("#{list.nth(&, 1)}", ($key, breakpoint.get-next($key2)), variables.$separator, $root: true) {
                            @content;
                        }
                    }
                }
            }
        }
    }
}

@mixin _responsive($property) {
    @if functions.has-declaration($property) {
        @content;

        @include _breakpoint {
            @content;
        }

        @include _between-breakpoint {
            @content
        }
    }
}

// ------------------------------------------------------------------------- //
// Public mixins
// ------------------------------------------------------------------------- //

@mixin createUtility($property, $utilities, $variation: ()) {
    $extend: ();
    $filter: false;

    @if type.is-list(map.get(variables.$extend, $property)) or type.is-string(map.get(variables.$extend, $property)) or type.is-number(map.get(variables.$extend, $property)) {
        @each $key in map.get(variables.$extend, $property) {
            $extend: map.set($extend, $key, map.get($utilities, $key));
        }
    } @else {
        $extend: functions.extend($utilities, $property);
    }

    ///
    /// Check if property is a filter.
    ///
    @if list.index(variables.$filters, $property) != null {
        $filter: true
    }

    ///
    /// Generate CSS declaration.
    ///
    @if $variation and type.is-map($variation) {
        @each $key, $value in $variation {
            $properties: $value;

            @include _selector($key, variables.$prefix) {
                @include _responsive($property) {
                    @each $key, $value in $extend {
                        @if type.is-string($key) {
                            $key: string.replace($key, "/", \/);
                        }

                        @if $key == "DEFAULT" {
                            @include _declaration($properties, $value, $filter);
                        } @else {
                            &-#{$key} {
                                @each $key in $properties {
                                    @include _declaration($key, $value, $filter);
                                }
                            }
                        }
                    }
                }
            }
        }
    } @else {
        @each $key, $value in $extend {
            @include _selector($key, variables.$prefix) {
                @include _responsive($property) {
                    @include _declaration($property, $value);
                }
            }
        }
    }
}
