@use 'sass:map';
@use 'sass:list';

////
/// @package theming
/// @group utilities
////

/// Removes all null key-value pairs from a map
/// @access public
/// @param {Map} $map - The target map to be cleaned.
/// @returns {Map} Returns a map with null key-value pairs removed.
@function clean($map) {
    $result: ();

    @each $key, $value in $map {
        @if $value {
            $result: map.deep-merge($result, (#{$key}: $value));
        }
    }

    @return $result;
}

/// Extends a Map with the values of another Map, disregarding null values in the process.
/// @access public
/// @param {Map...} $maps - The maps to get extended.
/// @requires {function} clean
/// @returns {Map} Returns the merged maps.
@function extend($maps...) {
    $result: ();

    @each $map in $maps {
        $cleaned: clean($map);

        @if map.has-key($cleaned, '_meta') {
            $_meta: map.get($result, '_meta') or ();
            $result: map.merge($result, $cleaned);
            $result: map.set($result, '_meta', map.deep-merge($_meta, map.get($cleaned, '_meta')));
        } @else {
            $result: map.merge($result, $cleaned);
        }
    }

    @return $result;
}

/// Extracts the differences between two or more maps, comparing the first map against the rest.
/// @access public
/// @param {Map...} $maps - A list of maps that will be diffed.
/// @example scss - Pull out the unique properties of the second map when compared to the first.
///   $map-1: (
///     color: orange,
///     background: black,
///   );
///
///   $map-2: (
///     color: red,
///     background: black,
///   );
///
///   $diffed: diff($map-1, $map-2); // returns (color: red);
/// @returns {Map} Returns a map of the unique properties.
@function diff($maps...) {
    $result: ();

    @for $i from 1 through list.length($maps) {
        $base: list.nth($maps, 1);

        @each $key, $value in list.nth($maps, $i) {
            $match: map.get($base, $key) == $value;

            @if not($match) {
                $result: map.merge(
                    $result,
                    (
                        $key: $value,
                    )
                );
            }
        }
    }

    @return $result;
}

/// Prefixes the keys in a map with the specified prefix and separator.
/// @access private
/// @param {Map} $map - The target map.
/// @param {String} $prefix - The string used to prefix all keys in the map.
/// @param {String} $separator [-] - The string used as a separator between the prefix and the key.
/// @returns {Map} Returns the modified map with all keys prefixed.
@function map-keys-prefix($map, $prefix, $separator: '-') {
    $keys: map.keys($map);
    $len: list.length($keys);
    $result: ();

    @for $i from 1 through $len {
        $key: list.nth($keys, $i);
        $result: map.merge(
            $result,
            (
                '#{$prefix}#{$separator}#{$key}': map.get($map, $key),
            )
        );
    }

    @return $result;
}
