/* 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,
  $media-prefix
) {
  $important: if($utilities-use-important, " !important", null);
  $this-mq: null;

  .#{$media-prefix}#{$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-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,
  $media-key
) {
  $important: if($utilities-use-important, " !important", null);
  $media-prefix: null;
  $value-is-map: if(type-of($val-props) == "map", true, false);

  @if $media-key {
    $media-prefix: #{$media-key}\:;
  }

  .#{$media-prefix}#{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,
      $media-prefix
    );
  }

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

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

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

  // 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 these-utilities($utilities, $media-key: false) {
  // loop through the $utilities
  @each $utility-name, $utility in $utilities {
    // Only do this if the the utility is meant to output

    @if not($media-key) or
      ($media-key and map-deep-get($utility, settings, responsive))
    {
      @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;

        $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,
                $media-key
              );
            } // end the modifier loop
          } // end the null value conditional
        } // end the value loop
      } // end the output conditional
    }
  } // end the utility loop
  // (ﾉ◕ヮ◕)ﾉ*:･ﾟ✧
}

@mixin render-utilities-in($utilities) {
  @include these-utilities($utilities);

  $our-breakpoints: map-deep-get($system-properties, breakpoints, standard);
  @each $media-key, $media-value in $our-breakpoints {
    @if map-get($theme-utility-breakpoints, $media-key) {
      @include at-media($media-key) {
        @include these-utilities($utilities, $media-key);
      }
    }
  }
}

/* stylelint-enable */
