@use 'sass:meta';
@use 'sass:math';
@use 'sass:list';
@use 'strip-unit' as *;
@use 'is-number' as *;
@use '../variables/misc' as *;

/// Converts $values into `rem` units. Can be a single value or a list of values.
/// Unitless values are assumed to be in pixels. Default base font size is 16px,
/// but can be changed with the $base-font-size variable.
///
/// @param {Number | List} $values - The value(s) to convert to `rem` units.
/// Can be a single value or a List containing `px`, `em`, `rem`, `%`, or
/// unitless values.
/// @param {Number} $base [null] - The base font-size. If none specified, defers
/// to the $base-font-size variable. If that is not found, defaults to 16px.
///
/// @return {Number | List} The value(s) in `rem` units.
///
/// @access public
/// @group Utilities
/// @require {function} strip-unit
/// @require {function} is-number
/// @require {variable} $base-font-size
@function conv-to-rem($values, $base: null) {
  $rem-values: ();
  $count: list.length($values);

  @each $value in $values {
    @if not is-number($value) or
      (not math.is-unitless($value) and not list.index(('%' 'px' 'rem' 'em'), math.unit($value)))
    {
      @error 'Invalid $values unit of `#{meta.inspect($value)}` passed to ' +
            'the [ conv-to-rem() ] function. You must pass a valid length in ' +
            'px, rem, or em units, or a List containing only such values.';
    }
  }

  // If no base font-size is passsed to the function as $base,
  // use the $base-font-size variable. If that does not exist, default to 16
  @if not $base {
    $base: if(
      meta.variable-exists('base-font-size') or
      meta.global-variable-exists('base-font-size'),
      $base-font-size,
      16
    );
  }

  // If the base font size is a %, then multiply it by 16px
  // This is because 100% font size = 16px by default
  @if math.unit($base) == '%' {
    $base: math.div($base, 100%) * 16;
  } @else if math.unit($base) == 'rem' or math.unit($base) == 'em' {
    $base: strip-unit($base) * 16;
  } @else if math.unit($base) == 'px' {
    $base: strip-unit($base);
  }

  @if $count == 1 {
    @return _unit-to-rem($values, $base);
  }

  @for $i from 1 through $count {
    $rem-values: list.append(
      $rem-values,
      _unit-to-rem(list.nth($values, $i), $base)
    );
  }

  @return $rem-values;
}

/// Converts $values into `rem` units. Can be a single value or a list of values.
/// Unitless values are assumed to be in pixels. Default base font size is 16px,
/// but can be changed with the $base-font-size variable.
///
/// @param {Number | List} $values - The value(s) to convert to `rem` units.
/// Can be a single value or a List containing `px`, `em`, `rem`, `%`, or
/// unitless values.
/// @param {Number} $base [null] - The base font-size. If none specified, defers
/// to the $base-font-size variable. If that is not found, defaults to 16px.
///
/// @return {Number | List} The value(s) in `rem` units.
///
/// @access public
/// @group Utilities
/// @require {function} conv-to-rem
///
/// @alias conv-to-rem
@function rem($values, $base: null) {
  @return conv-to-rem($values, $base);
}

/// Converts a value to matching rem value. By default, the base pixel value
/// used to calculate the rem value is taken from the `$base-font-size` variable.
///
/// @param {Number} $value - Value to convert. Can be `px`, `em`, `%`, or `rem`
/// @param {Number} $base - Base for pixel conversion.
///
/// @return {Number} A number in `rem`s, calculated based on the given value and
/// the `$base-font-size` value. Values in `rem` are passed through as is.
/// Values of `0rem` are passed back without any unit as `0`,
///
/// @access private
/// @group Utilities
/// @require {function} strip-unit
@function _unit-to-rem($value, $base) {
  @if not is-number($value) {
    @error 'Invalid $value of #{meta.inspect($value)} was passed ' +
        'to the [ conv-to-rem() ] function. You must use a valid number.';
  }

  // Transform em into rem if someone hands over 'em's
  @if math.unit($value) == 'em' {
    $value: strip-unit($value) * 1rem;
  } @else if math.unit($value) == '%' {
    $value: math.div($value, 100%) * 16px;
  }

  // At this point, if unit is not 'rem', assume it is in 'px'
  @if math.unit($value) != 'rem' {
    $value: math.div(strip-unit($value), strip-unit($base)) * 1rem;
  }

  // Eliminate units for 0rem values
  @if $value == 0rem {
    $value: 0;
  }

  @return $value;
}
