//
// Deep Get/Set in Maps
//

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

// Map deep get
// @author Hugo Giraudel
// @access public
// @param {Map} $map - Map
// @param {Arglist} $keys - Key chain
// @return {*} - Desired value

@function map-deep-get($map, $keys...) {
	@each $key in $keys {
		$map: map.get($map, $key);
	}

	@return $map;
}

// Deep set function to set a value in nested maps
// @author Hugo 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: list.nth($keys, $i);
		$current-map: list.nth($maps, -1);
		$current-get: map.get($current-map, $current-key);

		@if not $current-get {
			@error "Key `#{ $keys }` doesn't exist at current level in map.";
		}
		$maps: list.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: list.nth($maps, $i);
		$current-key: list.nth($keys, $i);
		$current-val: if($i == list.length($maps), $value, $result);
		$result: map.merge(
			$current-map,
			(
				$current-key: $current-val,
			)
		);
	}

	// Return result
	@return $result;
}
