/// Create a component based off the main module
///
/// @param {string|list} $components - The component or components to be used
/// @param {map} $content
/// @param {bool} $sub-component
/// @param {string} $glue
/// @param {bool} $cascade
@mixin component(
  $components: null,
  $content: (),
  $sub-component: false,
  $glue: $componentGlue,
  $cascade: true
) {
  $this: &;
  $module-map: selector-to-map($this);
  $selectors: '[class*="#{$module}#{$glue}"]';
  $namespace: map-get($module-map, 'module');

  @if str-index($namespace, '%') == 1 {
    $namespace: $module;
  }

  @if $sub-component {
    $namespace: nth(module-tree(&), length(module-tree(&)));
  }

  @if $components {
    $selectors: ();

    @each $component in $components {
      $selector: '.#{$namespace}#{$glue}#{$component}, [class*="#{$namespace}#{$glue}#{$component}#{$modifierGlue}"]';

      @if not $cascade {
        $selector: '> #{$selector}';
      }

      $selectors: join($selectors, $selector, comma);
    }
  }

  $parents: ();

  @each $selector in & {
    // spoof the selector into a list
    $selector: selector-parse(str-replace(inspect($selector), ' ', ', '));

    $is-modifier: str-index(inspect(nth($selector, length($selector))), '[class*="#{$modifierGlue}');
    $is-pseudo-state: str-index(inspect(nth($selector, length($selector))), ':');

    // if the last item isn't a modifier or pseudo state, remove it
    @if not ($is-modifier or $is-pseudo-state) {
      $selector: list-remove($selector, nth($selector, length($selector)));
    }

    @if length($selector) == 1 {
      $selector: nth($selector, 1);
    }

    // Re-build the parent selector
    $parents: append($parents, str-replace(inspect($selector), ', ', ' '), comma);
  }

  $parents: list-remove-duplicates($parents);

  @if length($parents) == 1 {
    $parents: nth($parents, 1);
  }

  @if ($parents == '()') {
    @at-root #{$selectors} {
      @content;

      @include parse-cq($content);
    }
  }
  @else {
    @at-root #{$parents} {
      #{$selectors} {
        @content;

        @include parse-cq($content);
      }
    }
  }
}

/// Alis for `component` mixin with $sub-component: true
///
/// @param {string|list} $components
/// @param {map} $content
/// @param {string} $glue
@mixin sub-component($components: null, $content: (), $glue: $componentGlue) {
  @include component($components, $content, true, $glue) {
    @content;
  }
}

/// Alias for component() mixin
///
/// @author [@esr360](http://twitter.com/esr360)
/// @access public
@mixin components($args...) {
  @include component($args...) {
    @content;
  }
}