////
/// @group utils
////

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

@import './variables';

/// Replace `$search` with `$replace` in `$string`
///
/// @author Hugo Giraudel
/// @access private
/// @param {String} string - Initial string
/// @param {String} search - Substring to replace
/// @param {String} replace - New value
/// @return {String} - Updated string
/// @link https://css-tricks.com/snippets/sass/str-replace-function Source from CSS Tricks
@function str-replace($string, $search, $replace) {
  $index: string.index($string, $search);

  @if $index {
    @return string.slice($string, 1, $index - 1) + $replace +
      str-replace(
        string.slice($string, $index + string.length($search)),
        $search,
        $replace
      );
  }

  @return $string;
}

/// This function is used to validate a list or map to make sure they contain
/// the provided key or value. This should mostly really only be internal use.
///
/// @access private
/// @param {List|Map} list-or-map - The list or map to validate
/// @param {Color|String|Number} key-or-value - Either the value to check for in
/// a list or a Map's key.
/// @param {String} error-message - The prop name that was being used for the
/// validation. This is mostly for a more helpful error message when a
/// developer/user provided the wrong input.
/// @return {String|Null} - Either the map's value for the provided key or the
/// provided value for a list when there is no error.
@function rmd-utils-validate($list-or-map, $key-or-value, $error-message) {
  $type: meta.type-of($list-or-map);
  $is-map: $type == map;
  $is-list: $type == list;

  @if $rmd-utils-skip-validation {
    @return if($is-list, $key-or-value, map-get($list-or-map, $key-or-value));
  }

  @if not $is-map and not $is-list {
    @error 'Unable to validate anything except for lists and maps at this time. Received: #{$list-or-map}.';
  }

  $choices: if($is-map, map.keys($list-or-map), $list-or-map);
  @if not index($choices, $key-or-value) {
    @error "Invalid #{$error-message}: '#{$key-or-value}'. Choose one of: #{$choices}";
  }

  @return if($is-list, $key-or-value, map-get($list-or-map, $key-or-value));
}

/// A utility function that can swap the position of different css styles. This
/// is useful for RTL switching.
/// @param {String} style - The style to swap. This should be one of
/// `$rmd-utils-swappable-positions`.
/// @return {String} a swapped style attribute string.
@function rmd-utils-swap-position($style) {
  $prefix: '';
  $position: $style;
  @each $valid-prefix in $rmd-utils-swappable-position-prefixes {
    @if string.index($style, '#{$valid-prefix}-') {
      $prefix: '#{$valid-prefix}-';
      $position: str-replace($style, $prefix, '');
    }
  }

  $current: rmd-utils-validate(
    $rmd-utils-swappable-positions,
    $position,
    'swappable position'
  );

  $next-position: bottom;
  @if $position == left {
    $next-position: right;
  } @else if $position == right {
    $next-position: left;
  } @else if $position == bottom {
    $next-position: top;
  }

  @return '#{$prefix}#{$next-position}';
}

/// This function can be used to negate the value of a css variable. It just
/// really wraps the variable with `calc(-1 * #{$variable})`.
///
/// @param {String} css-variable - The css variable string to negate.
/// @return {String} a calc string that negates a css variable.
@function rmd-utils-negate-var($css-variable) {
  @return calc(-1 * #{$css-variable});
}
