@use 'sass:meta';
@use 'sass:math';
@use 'sass:string';
@use '../../functions/equals-false' as *;
@use '../../functions/equals-true' as *;
@use '../../functions/is-list' as *;
@use '../../functions/is-number' as *;
@use '../../functions/is-percentage' as *;
@use '../../functions/is-string' as *;
@use '../../functions/list-to-string' as *;
@use '../../functions/strip-unit' as *;

/// Makes an element cover 100% of the screen or cover 100% of the closet
/// stacking context.
///
/// @param {Number} $z-val [999] - A z-index number value
/// @param {Bool | String} $is-fullscreen [false] - A flag indicating whether
/// the element will attempt to cover the entire viewport rather than just
/// covering the nearest stacking context. This is not 100% reliable, depending
/// on the stacking context properties of the elements in the parent chain.
/// @param {Color | Mixed} $bg [null] - The shorthand `background` property's
/// value.
/// @param {Number} $opacity [null] - A decimal value between 0 and 1 or a
/// percentage value between 0% and 100%.
///
/// @group Utilities
///
/// @require {function} equals-false
/// @require {function} equals-true
/// @require {function} is-list
/// @require {function} is-number
/// @require {function} is-percentage
/// @require {function} is-string
/// @require {function} list-to-string
/// @require {function} strip-unit
///
/// @throw Invalid data type for $is-fullscreen error.
/// @throw Invalid data type for $z-val error.
/// @throw Invalid $opacity range error.
/// @throw Invalid $opacity data type error.
/// @throw Invalid $opacity unit type error.
@mixin cover(
  $z-val: 999,
  $is-fullscreen: false,
  $bg: null,
  $opacity: null
) {
  @if $is-fullscreen {
    @if is-list($is-fullscreen) {
      $is-fullscreen: list-to-string($is-fullscreen);
    }

    @if is-string($is-fullscreen) {
      $is-fullscreen: string.to-lower-case($is-fullscreen);
    }
  }

  @if equals-true($is-fullscreen) or
      $is-fullscreen == 'full-screen' or
      $is-fullscreen == 'full screen' or
      $is-fullscreen == 'fullscreen' or
      $is-fullscreen == 'full-s' or
      $is-fullscreen == 'fulls' or
      $is-fullscreen == 'full' or
      $is-fullscreen == 'ifs' or
      $is-fullscreen == 'f-s' or
      $is-fullscreen == 'f s' or
      $is-fullscreen == 'fs'
  {
    $is-fullscreen: true;
  } @else if equals-false($is-fullscreen) or is-alias('none', $is-fullscreen) {
    $is-fullscreen: false;
  } @else {
    @error 'Invalid $is-fullscreen value of `#{meta.inspect($is-fullscreen)}` ' +
        'passed to the [ cover() ] mixin. Value should either be `true` or ' +
        '`false`.';
  }

  position: absolute;
  top: 0;
  left: 0;

  @if is-number($z-val) and math.is-unitless($z-val) {
    z-index: $z-val;
  } @else {
    @error 'Invalid $z-val value of `#{meta.inspect($z-val)}` passed to the ' +
        '[ cover() ] mixin. Value must be a unitless number for z-index ' +
        'property.';
  }

  @if $is-fullscreen {
    right: 0;
    bottom: 0;
    width: 100vw;
    width: 100dvw;
    max-width: 100vw;
    max-width: 100dvw;
    height: 100vw;
    height: 100dvw;
    max-height: 100vw;
    max-height: 100dvw;
  } @else {
    width: 100%;
    max-width: 100%;
    height: 100%;
    max-height: 100%;
  }

  @if $bg {
    background: $bg;
  }

  @if is-number($opacity) {
    // Convert $opacity to a percentage if it is a unitless number in range
    @if math.is-unitless($opacity) and $opacity > 1 and opacity <= 100 {
      $opacity: $opacity * 1%;
    } @else if $opacity < 0 or $opacity > 100 {
      @error 'Invalid $opacity value of `#{meta.inspect($opacity)}` passed ' +
        'to the [ cover() ] mixin. The $opacity parameter  must be a decimal ' +
        'between 0 and 1 inclusive or a percentage value between 0% and ' +
        '100% inclusive.';
    }

    // If opacity is a percentage, convert it into a decimal value.
    @if is-percentage($opacity) {
      $opacity: strip-unit(math.div($opacity, 100));
    }

    @if not math.is-unitless($opacity) {
      @error 'Invalid unit type for $opacity passed to the [ cover() ] mixin. ' +
          'You passed `#{meta.inspect($opacity)}`. The $opacity parameter ' +
          'must be a decimal between 0 and 1 inclusive or a percentage ' +
          'value between 0% and 100% inclusive.';
    }
  } @else {
    @error 'Invalid $opacity data type. You passed `#{meta.inspect($opacity)}`' +
        ' as the $opacity value for the [ cover() ] mixin. Pleas use a decimal' +
        ' or percentage instead.';
  }
}
