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

@use "sass:list";
@use "@unsass/css";
@use "@unsass/css/custom-properties";
@use "@unsass/string";
@use "@unsass/types" as type;
@use "./functions";
@use "./variables";

///
/// Emits CSS custom properties declarations from a tokens map.
///
/// @param {Map} $tokens - The tokens map.
/// @param {String} $namespace - The namespace (without prefix). Default: `null`.
/// @param {List} $include - A list of token keys to include. Default: `null` (include all).
/// @param {List} $exclude - A list of token keys to exclude. Default: `null` (exclude none).
/// @param {String} $layer - A CSS cascade layer name. Default: `null`.
///
@mixin emit($tokens, $namespace: null, $include: null, $exclude: null, $layer: null) {
    @if $layer {
        @layer #{$layer} {
            @include emit($tokens, $namespace, $include, $exclude);
        }
    } @else {
        @each $key, $value in $tokens {
            @if ($include and list.index($include, $key) == null) or ($exclude and list.index($exclude, $key) != null) {

                // Skip filtered tokens.
            } @else {
                $name: string.combine(variables.$prefix, $namespace, $key);

                @if $value != null {
                    @if type.is-map($value) {
                        @include emit($value, string.combine($namespace, $key));
                    } @else {
                        @include css.declaration(custom-properties.create($name, $value));
                    }
                }
            }
        }
    }
}

///
/// Validates tokens then emits CSS custom properties in one call.
///
/// @param {List|Map} $refs - A list or map of supported tokens.
/// @param {Map} $tokens - The user-provided tokens map.
/// @param {String} $namespace - The namespace (without prefix). Default: `null`.
/// @param {List} $include - A list of token keys to include. Default: `null` (include all).
/// @param {List} $exclude - A list of token keys to exclude. Default: `null` (exclude none).
///
@mixin theme($refs, $tokens, $namespace: null, $include: null, $exclude: null) {
    $tokens: functions.validation($refs, $tokens);

    @include emit($tokens, $namespace: $namespace, $include: $include, $exclude: $exclude);
}

///
/// Emits scoped CSS declarations for a color scheme.
/// With `$selector`, wraps in a selector rule; otherwise uses `@media (prefers-color-scheme)`.
/// With `$layer`, wraps the whole output in a named cascade layer.
///
/// @param {String} $scheme   - The color scheme (`"light"` or `"dark"`). Default: `"light"`.
/// @param {String} $selector - A CSS selector to scope the declarations. Default: `null`.
/// @param {String} $layer    - A CSS cascade layer name. Default: `null`.
///
@mixin scheme($scheme: "light", $selector: null, $layer: null) {
    @if $layer {
        @layer #{$layer} {
            @include scheme($scheme, $selector) {
                @content;
            }
        }
    } @else if $selector {
        #{$selector} {
            @content;
        }
    } @else {
        $valid: ("light", "dark");

        @if list.index($valid, $scheme) == null {
            @error "Invalid color scheme '#{$scheme}'. Choose one of '#{$valid}'.";
        }

        @media (prefers-color-scheme: $scheme) {
            @content;
        }
    }
}
