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

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

///
/// 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 {
            $included: not $include or list.index($include, $key) != null;
            $excluded: $exclude and list.index($exclude, $key) != null;

            @if $included and not $excluded and $value != null {
                $name: functions.name($namespace, $key);

                @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).
/// @param {String} $layer - A CSS cascade layer name. Default: `null`.
///
@mixin theme($refs, $tokens, $namespace: null, $include: null, $exclude: null, $layer: null) {
    $tokens: functions.validation($refs, $tokens);

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

///
/// 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;
        }
    }
}
