@use 'sass:math';
@use 'sass:map';
@use 'sass:list';

$breakpoints: (
  mobile:  320px,
  phablet: 500px,
  tablet:  740px,
  desktop: 980px,
  wide:    1300px,
  xlwide:  1850px
) !default;

$bp-mobile:  320px;
$bp-phablet: 500px;
$bp-tablet:  740px;
$bp-desktop: 980px;
$bp-wide:    1300px;
$bp-xlwide:  1850px;


$show-breakpoints: (mobile, phablet, tablet, desktop, wide, xlwide) !default;

$media-type: all !default;

@function px2em($px) {
  @if math.is-unitless($px) {
    @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels.";
    @return px2em($px * 1px);
  }

  @if math.compatible($px, 1em) {
    @return $px;
  }
  @return math.div($px, 16px) * 1em;
}

@function get-breakpoint-width($name, $breakpoints: $breakpoints) {
  @if map.has-key($breakpoints, $name) {
    @return map.get($breakpoints, $name);
  } @else {
    @warn "Breakpoint #{$name} wasn't found in $breakpoints.";
    @return null;
  }
}

@mixin mq(
  $from: false,
  $until: false,
  $and: false,
  $media-type: $media-type,
  $breakpoints: $breakpoints
) {
  $min-width: 0;
  $max-width: 0;
  $media-query: '';

  @if $from {
    @if type-of($from) == number {
      $min-width: px2em($from);
    } @else {
      $min-width: px2em(get-breakpoint-width($from, $breakpoints));
    }
  }

  @if $until {
    @if type-of($until) == number {
      $max-width: px2em($until);
    } @else {
      $max-width: px2em(get-breakpoint-width($until, $breakpoints)) - 0.01em;
    }
  }

  @if $min-width != 0 {
    $media-query: '#{$media-query} and (min-width: #{$min-width})';
  }
  @if $max-width != 0 {
    $media-query: '#{$media-query} and (max-width: #{$max-width})';
  }
  @if $and {
    $media-query: '#{$media-query} and #{$and}';
  }

  @if ($media-type == 'all' and $media-query != '') {
    $media-type: '';
    $media-query: str-slice(unquote($media-query), 6);
  }

  @media #{$media-type + $media-query} {
    @content;
  }
}

@function _quick-sort($list) {
  $less: ();
  $equal: ();
  $large: ();

  @if length($list) > 1 {
    $seed: list.nth($list, math.ceil(math.div(length($list), 2)));

    @each $item in $list {
      @if ($item == $seed) {
        $equal: list.append($equal, $item);
      } @else if ($item < $seed) {
        $less: list.append($less, $item);
      } @else if ($item > $seed) {
        $large: list.append($large, $item);
      }
    }

    @return join(join(_quick-sort($less), $equal), _quick-sort($large));
  }

  @return $list;
}

@function _map-sort-by-value($map) {
  $map-sorted: ();
  $map-keys: map.keys($map);
  $map-values: map.values($map);
  $map-values-sorted: _quick-sort($map-values);

  @each $value in $map-values-sorted {
    $index: index($map-values, $value);
    $key: list.nth($map-keys, $index);
    $map-sorted: map.merge(
      $map-sorted,
      (
        $key: $value,
      )
    );

    $map-values: list.set-nth($map-values, $index, 0);
  }

  @return $map-sorted;
}

@mixin add-breakpoint($name, $width) {
  $new-breakpoint: (
    $name: $width,
  );
  $breakpoints: map.merge($breakpoints, $new-breakpoint) !global;
  $breakpoints: _map-sort-by-value($breakpoints) !global;
}
