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

@function map-deep-get($map, $keys...) {
  $scope: $map;
  $i: 1;
  @while (meta.type-of($scope) == map) and ($i <= list.length($keys)) {
    $scope: map.get($scope, list.nth($keys, $i));
    $i: $i + 1;
  }
  @return $scope;
}


/// Deep set function to set a value in nested maps
/// @author Kitty Giraudel
/// @access public
/// @param {Map} $map - Map
/// @param {List} $keys -  Key chaine
/// @param {*} $value - Value to assign
/// @return {Map}

@function map-deep-set($map, $keys, $value) {
  $maps: ($map,);
  $result: null;
  
  // If the last key is a map already
  // Warn the user we will be overriding it with $value
  @if type-of(nth($keys, -1)) == "map" {
    @warn "The last key you specified is a map; it will be overrided with `#{$value}`.";
  }
  
  // If $keys is a single key
  // Just merge and return
  @if length($keys) == 1 {
    @return map-merge($map, ($keys: $value));
  }
  
  // Loop from the first to the second to last key from $keys
  // Store the associated map to this key in the $maps list
  // If the key doesn't exist, throw an error
  @for $i from 1 through length($keys) - 1 {
    $current-key: nth($keys, $i);
    $current-map: nth($maps, -1);
    $current-get: map-get($current-map, $current-key);
    @if $current-get == null {
      @error "Key `#{$key}` doesn't exist at current level in map.";
    }
    $maps: append($maps, $current-get);
  }
  
  // Loop from the last map to the first one
  // Merge it with the previous one
  @for $i from length($maps) through 1 {
    $current-map: nth($maps, $i);
    $current-key: nth($keys, $i);
    $current-val: if($i == length($maps), $value, $result);
    $result: map-merge($current-map, ($current-key: $current-val));
  }
  
  // Return result
  @return $result;
}


@function map-index($map, $key) {
  $index: -1;

  $i: 0;
  @each $k, $v in $map {
    @if $k == $key {
      @return $i;
    }
    $i: $i + 1;
  }
  @return $index;
}


@function map-set($map, $key, $value) {
  $new: (
    $key: $value,
  );
  @return map-merge($map, $new);
}
