/* stylelint-disable max-nesting-depth */

/*
----------------------------------------
@render-pseudoclass
----------------------------------------
Build a pseucoclass utiliy from values
calculated in the @render-utilities-in
loop
----------------------------------------
*/

@mixin render-pseudoclass($utility, $pseudoclass, $selector, $property, $value, $mq) {
  $important: if(
    $utilities-use-important,
    ' !important',
    null
  );
  $this-mq: null;

  @if $mq {
    $this-mq: '#{$mq}\\:';
  }
  .#{$this-mq}#{$pseudoclass}\:#{ns('utility')}#{$selector}:#{$pseudoclass} {
    @each $this-property in $property {
      #{$this-property}: unquote('#{$value}#{$important}');
    }
  }
}

// utility-feature? utility-property
@mixin add-utility-declaration($declaration, $utility-type, $important) {
  @each $ext-prop, $ext-value in map-get($declaration, $utility-type) {
    #{strunquote($ext-prop)}: unquote('#{strunquote($ext-value)}#{$important}');
  }
}

/*
----------------------------------------
@render-media-queries
----------------------------------------
Build @media media queries from values
calculated in the @render-utilities-in
loop
----------------------------------------
*/

@mixin render-media-queries($utility, $selector, $property, $value, $val-props) {
  $important: if(
    $utilities-use-important,
    ' !important',
    null
  );
  $our-breakpoints: map-deep-get($system-properties, breakpoints, standard);
  $mq: null;
  $value-is-map: if(
    type-of($val-props) == 'map',
    true,
    false
  );

  @each $media-key, $media-value in $our-breakpoints {
    $mq: unquote($media-key);
    $media-value-px: rem-to-px($media-value);

    @if map-get($theme-utility-breakpoints, $media-key) {
      @include at-media($media-key) {
        .#{$mq}\:#{ns('utility')}#{$selector} {
          @if $value-is-map and map-has-key($val-props, extend) {
            @include add-utility-declaration($val-props, extend, $important);
          }

          @each $this-property in $property {
            #{$this-property}: unquote('#{$value}#{$important}');
          }

          @if map-has-key($utility, extend) {
            @include add-utility-declaration($utility, extend, $important);
          }
          @if map-deep-get($utility, settings, hover) {
            @include render-pseudoclass($utility, hover, $selector, $property, $value, $mq);
          }
          @if map-deep-get($utility, settings, visited) {
            @include render-pseudoclass($utility, visited, $selector, $property, $value, $mq);
          }
        }
      }
    }
  }
}

/*
----------------------------------------
@render-utility
----------------------------------------
Build a utility from values calculated
in the @render-utilities-in loop
----------------------------------------
TODO: Determine the proper use of
unquote() in the following. Changed to
account for a 'interpolation near
operators will be simplified in a
future version of Sass' warning.
----------------------------------------
*/

@mixin render-utility($utility, $selector, $property, $value, $val-props) {
  $important: if(
    $utilities-use-important,
    ' !important',
    null
  );
  $mq: null;
  $value-is-map: if(
    type-of($val-props) == 'map',
    true,
    false
  );

  .#{ns('utility')}#{$selector} {
    @if $value-is-map and map-has-key($val-props, extend) {
      @include add-utility-declaration($val-props, extend, $important);
    }

    @if $value-is-map and map-has-key($val-props, extends) {
      @extend %#{map-get($val-props, extends)};
    }

    @each $this-property in $property {
      #{$this-property}: unquote('#{$value}#{$important}');
    }

    @if map-has-key($utility, extend) {
      @include add-utility-declaration($utility, extend, $important);
    }
  }

  // Add the pseudoclass variants, if applicable

  @if map-deep-get($utility, settings, hover) {
    @include render-pseudoclass($utility, hover, $selector, $property, $value, $mq);
  }

  @if map-deep-get($utility, settings, active) {
    @include render-pseudoclass($utility, active, $selector, $property, $value, $mq);
  }

  @if map-deep-get($utility, settings, visited) {
    @include render-pseudoclass($utility, visited, $selector, $property, $value, $mq);
  }

  @if map-deep-get($utility, settings, focus) {
    @include render-pseudoclass($utility, focus, $selector, $property, $value, $mq);
  }

  // And add the responsive prefixes, if applicable

  @if map-deep-get($utility, settings, responsive) {
    @include render-media-queries($utility, $selector, $property, $value, $val-props);
  }
}

/*
----------------------------------------
@render-utilities-in
----------------------------------------
The master loop that sets the building
blocks of utilities from the values
in individual rule settings and loops
through all possible variants
----------------------------------------
*/

@mixin render-utilities-in($utilities) {

  // loop through the $utilities
  @each $utility-name, $utility in $utilities {

    // Only do this if the the utility is meant to output

    @if map-deep-get($utility, settings, output) or
      $output-all-utilities {

      // set intital variants
      // $property-default is a single value for all these utilities

      $base-props: null;
      $modifier: null;
      $selector: null;
      $property-default: map-get($utility, property);
      $property: null;
      $value: null;
      $our-modifiers: ();
      $b: null;
      $v: null;
      $mv: null;
      $val-props: ();
      $no-value: false;
      $mq: null;

      $b: map-get($utility, base);

      // Each utility rule takes a value, so let's start here
      // and begin building.

      // -------- For each value in utility.values ----------

      @each $val-key, $val-value in map-get($utility, values) {

        // If $val-value == null, or if $val-value is a map and
        // the content key or the dependency key has a null value
        // set $val-value to `false`...

        @if type-of($val-value) == 'map' {
          @if not map-get($val-value, content) {
            $val-value: false;
          }
          @else if map-has-key($val-value, dependency)
            and not map-get($val-value, dependency) {
            $val-value: false;
          }
        }

        // ...so we can skip building this rule altogether.
        // So, if $val-value is _not_ false...

        @if $val-value {

          // Set the value of our rule.
          // If its a map, use val-value.content.

          $val-slug: if(
            type-of($val-value) == 'map',
            map-get($val-value, 'slug'),
            $val-key
          );

          $value: if(
            type-of($val-value) == 'map',
            map-get($val-value, 'content'),
            $val-value
          );

          @if $val-slug == ''
            or smart-quote($val-slug) == 'noValue' {
            $no-value: true;
          }

          // Add any appended values...

          @if map-get($utility, valueAppend) {
            $value: $value + map-get($utility, valueAppend);
          }

          // ...or prepended values.

          @if map-get($utility, valuePrepend) {
            $value: map-get($utility, valuePrepend) + $value;
          }

          // Then unquote the entire value string.

          $value: strunquote($value);

          // And we'll set the $v as $val-slug for use in
          // constructing the selector (.$b-$m-$v).

          $v: $val-slug;

          // -------- Start of Modifiers ----------

          // Now we'll check for modifiers and loop through them
          // to get the props we need to build our rule.

          // Modifiers are held in a MAP,
          // where each individual modifer has the keypair
          // [slug]:[value]

          // So, check for modifiers.

          @if map-get($utility, modifiers) != null {

            // If there are modifiers, capture them as $our-modifiers.

            $our-modifiers: map-get($utility, modifiers);
          }
          @else {

            // If there aren't, build a dummy so we can keep
            // all our build in the same loop.

            $our-modifiers: (
              'slug': null,
            );
          }

          // OK! C'mon, let's loop!
          // https://www.youtube.com/watch?v=X9i2i07wPUw

          // -------- For each modifier in $our-modifiers ----------

          @each $mod-key, $mod-val in $our-modifiers {

            $property: if(
              $mod-val == null or $mod-val == '',
              $property-default,
              multi-cat($property-default, $mod-val)
            );

            // Now we go through to set the $selector.

            // If mod-props.slug is noModifier...

            @if $mod-key == ''
              or $mod-key == slug
              or smart-quote($mod-key) == 'noModifier' {

              // First, we can test to see if the base $b is null

              @if $b == null {

                // If it _is_ null, the rule's selector is $v.

                $selector: $v;

                // if the value is noValue ('')

              }
              @else if $no-value {

                // selector is the base only

                $selector: $b;
              }
              @else {

                // otherwise, selctor is joined with a hyphen.

                $selector: $b + '-' + $v;

                // Nice! We just took care of the non-modifier cases!

              }
            }

            // If there _is_ a modifier...

            @else {

              $mv: if(
                $no-value,
                $mod-key,
                $mod-key + '-' + $v
              );

              // Once we have $mv, test for $b
              // and build the selector as before.

              $selector: if(
                $b == null,
                $mv,
                $b + '-' + $mv
              );
            }

            // finished setting modifier vars

            // Hey. Did we just finish $selector?
            // And do we also have $property and $value?
            // We do?!?!?! We do!

            // FINALLY, 'BUILD THE RULE, MAX!'
            // https://www.youtube.com/watch?v=R3Igz5SfBCE

            @include render-utility($utility, $selector, $property, $value, $val-value);

          } // end the modifier loop
        } // end the null value conditional
      } // end the value loop
    } // end the output conditional
  } // end the utility loop
  // (ﾉ◕ヮ◕)ﾉ*:･ﾟ✧
}

// Helper to generate an @font-face declaration

/* stylelint-enable */
