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

/// Default value for error function
/// By default, we fail during build time when encountering an error.
/// true value should only be used for testing purposes
/// @type bool
$test-mode-enabled: false !default;

/// Override @error directive with [Error] $message text not to fail during testing
/// @param {string} $message - error message displayed in console
/// @param {bool} $fail-graciously [$test-mode-enabled] - if enabled, do not fail on errors at build time.
/// @throw Error with message provided as parameter if the test mode is not enabled (default)
/// @return {string} Error message
@function error($message) {
  @if ($test-mode-enabled) {
    @return '[Error] #{$message}';
  }
  @error $message;
}

/// Return the tail of a list
/// @param {list} $list - List to get teh tail
@function tail($list) {
  @if (meta.type-of($list) == 'list') {
    @if (list.length($list) > 1) {
      $result: [];
      @for $i from 2 through list.length($list) {
        $result: list.append($result, list.nth($i, $list));
      }
    } @else {
      @return [];
    }
  } @else {
    @return [];
  }
};

/// Return mandatory parameter if it exists. Else, throw an error
/// @access public
/// @param {map} $map - where to look for the key
/// @param {string|list} $key
/// @param {string} $map-name - for debug purposes
/// @return {any} Map variable value or throw
@function get-mandatory($map, $key, $map-name: 'unknown') {
  @if (meta.type-of($key) == 'list') {
    @if (list.length($key) > 0) {
      @return get-mandatory(get-mandatory($map, list.nth($key, 1)), tail($key));
    } @else {
      @return $map;
    }
  }
  @if (map.has-key($map, $key)) {
    @return map.get($map, $key);
  }
  @return error('Missing mandatory `#{$key}` in `#{$map-name}`');
}

/// Merge a list of maps. The first one is overridden with the second one etc.
/// @access public
/// @param {list} $map-list - list of maps separated via commas
/// @return {map} merged map
@function multi-map-merge($map-list...) {
  $result: ();
  @each $map in $map-list {
    $result: map.merge($result, $map);
  }
  @return $result;
}

/// Report variable creation for metadata
/// @access private
@function log-variable($name, $value: null, $details: null, $metadata-black-list-pattern: ()) {
  $metadata-debug: false !default;
  $is-blacked-listed-property: false;

  @if list.length($metadata-black-list-pattern) > 0 {
    @for $i from 1 to list.length($metadata-black-list-pattern) + 1 {
      $pattern: list.nth($metadata-black-list-pattern, $i);
      $is-blacked-listed-property: $is-blacked-listed-property or string.index($name, $pattern) != null;
    }
  }

  @if (meta.function-exists('metadata-report') and not $is-blacked-listed-property) {
    $metadata-debug: metadata-report($name, $value, $details);
  }
  @return $metadata-debug;
}

/// Retrieve variable key from the variable name
/// @access private
/// @param {string} $name Name of the variable
/// @return {string} formatted key
@function get-var-key($name) {
  $key: $name;

  @if (string.slice($name, 1, 2) == '--') {
    $key: string.slice($name, 3);
  }

  @return $key;
}
