////
///
/// Map Functions
/// ===========================================================================
///
/// Utility functions for map manipulation.
///
/// @group Functions
/// @author Scape Agency
/// @link https://scape.style
/// @since 0.1.0 initial release
/// @access public
///
////

// ============================================================================
// Use
// ============================================================================

@use "sass:map";
@use "sass:list";
@use "sass:meta";
@use "sass:string";

// ============================================================================
// Functions
// ============================================================================

/// Deep get a value from a nested map
/// @param {Map} $map - The map
/// @param {Arglist} $keys - Key path to the value
/// @return {*} - The value at the path, or null
@function map-deep-get($map, $keys...) {
    @each $key in $keys {
        @if meta.type-of($map) != "map" {
            @return null;
        }
        $map: map.get($map, $key);
    }
    @return $map;
}

/// Deep set a value in a nested map
/// @param {Map} $map - The original map
/// @param {List} $keys - Key path to the value
/// @param {*} $value - Value to set
/// @return {Map} - Updated map
@function map-deep-set($map, $keys, $value) {
    $length: list.length($keys);
    $result: ();

    @if $length == 1 {
        @return map.set($map, list.nth($keys, 1), $value);
    }

    $key: list.nth($keys, 1);
    $rest: ();

    @for $i from 2 through $length {
        $rest: list.append($rest, list.nth($keys, $i));
    }

    $nested: map.get($map, $key);
    @if meta.type-of($nested) != "map" {
        $nested: ();
    }

    @return map.set($map, $key, map-deep-set($nested, $rest, $value));
}

/// Merge maps recursively (deep merge)
/// @param {Map} $map1 - First map
/// @param {Map} $map2 - Second map (overrides first)
/// @return {Map} - Merged map
@function map-deep-merge($map1, $map2) {
    $result: $map1;

    @each $key, $value in $map2 {
        @if meta.type-of($value) ==
            "map" and
            meta.type-of(map.get($result, $key)) ==
            "map"
        {
            $result: map.set(
                $result,
                $key,
                map-deep-merge(map.get($result, $key), $value)
            );
        } @else {
            $result: map.set($result, $key, $value);
        }
    }

    @return $result;
}

/// Get all values from a map as a list
/// @param {Map} $map - The map
/// @return {List} - List of values
@function map-values($map) {
    $result: ();

    @each $key, $value in $map {
        $result: list.append($result, $value);
    }

    @return $result;
}

/// Invert a map (swap keys and values)
/// @param {Map} $map - The map to invert
/// @return {Map} - Inverted map
@function map-invert($map) {
    $result: ();

    @each $key, $value in $map {
        $result: map.set($result, $value, $key);
    }

    @return $result;
}

/// Filter a map by keys
/// @param {Map} $map - The original map
/// @param {List} $keys - Keys to keep
/// @return {Map} - Filtered map
@function map-filter-keys($map, $keys) {
    $result: ();

    @each $key, $value in $map {
        @if list.index($keys, $key) {
            $result: map.set($result, $key, $value);
        }
    }

    @return $result;
}

/// Convert a map to CSS custom properties string
/// @param {Map} $map - Map to convert
/// @param {String} $prefix [''] - Prefix for property names
/// @return {String} - CSS declarations
@function map-to-props($map, $prefix: "") {
    $result: "";

    @each $key, $value in $map {
        $prop-name: "";
        @if $prefix != "" {
            $prop-name: "#{$prefix}-#{$key}";
        } @else {
            $prop-name: "#{$key}";
        }

        @if meta.type-of($value) == "map" {
            $result: $result + map-to-props($value, $prop-name);
        } @else {
            $result: $result + "--#{$prop-name}: #{$value}; ";
        }
    }

    @return $result;
}

/// Check if a map has a key (including nested)
/// @param {Map} $map - The map
/// @param {Arglist} $keys - Key path to check
/// @return {Boolean} - True if key exists
@function map-has-deep-key($map, $keys...) {
    @each $key in $keys {
        @if meta.type-of($map) != "map" or not map.has-key($map, $key) {
            @return false;
        }
        $map: map.get($map, $key);
    }
    @return true;
}
