////
/// Copyright (c) 2016-2024 Martin Donath <martin.donath@squidfunk.com>
///
/// Permission is hereby granted, free of charge, to any person obtaining a
/// copy of this software and associated documentation files (the "Software"),
/// to deal in the Software without restriction, including without limitation
/// the rights to use, copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit persons to whom the
/// Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in
/// all copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS
////

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

// ----------------------------------------------------------------------------
// Variables
// ----------------------------------------------------------------------------

///
/// Device-specific breakpoints
///
/// @example
///   $break-devices: (
///     mobile: (
///       portrait:  220px  479px,
///       landscape: 480px  719px
///     ),
///     tablet: (
///       portrait:  720px  959px,
///       landscape: 960px  1219px
///     ),
///     screen: (
///       small:     1220px 1599px,
///       medium:    1600px 1999px,
///       large:     2000px
///     )
///   );
///
$break-devices: () !default;

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

///
/// Choose minimum and maximum device widths
///
@function break-select-min-max($devices) {
  $min: 1000000;
  $max: 0;
  @each $key, $value in $devices {
    @while type-of($value) == map {
      $value: break-select-min-max($value);
    }
    @if type-of($value) == list {
      @each $number in $value {
        @if type-of($number) == number {
          $min: math.min($number, $min);
          @if $max {
            $max: math.max($number, $max);
          }
        } @else {
          @error "Invalid number: #{$number}";
        }
      }
    } @else if type-of($value) == number {
      $min: math.min($value, $min);
      $max: null;
    } @else {
      @error "Invalid value: #{$value}";
    }
  }
  @return $min, $max;
}

///
/// Select minimum and maximum widths for a device breakpoint
///
@function break-select-device($device) {
  $current: $break-devices;
  @for $n from 1 through length($device) {
    @if type-of($current) == map {
      $current: map.get($current, list.nth($device, $n));
    } @else {
      @error "Invalid device map: #{$devices}";
    }
  }
  @if type-of($current) == list or type-of($current) == number {
    $current: (default: $current);
  }
  @return break-select-min-max($current);
}

// ----------------------------------------------------------------------------
// Mixins
// ----------------------------------------------------------------------------

///
/// A minimum-maximum media query breakpoint
///
@mixin break-at($breakpoint) {
  @if type-of($breakpoint) == number {
    @media screen and (min-width: $breakpoint) {
      @content;
    }
  } @else if type-of($breakpoint) == list {
    $min: list.nth($breakpoint, 1);
    $max: list.nth($breakpoint, 2);
    @if type-of($min) == number and type-of($max) == number {
      @media screen and (min-width: $min) and (max-width: $max) {
        @content;
      }
    } @else {
      @error "Invalid breakpoint: #{$breakpoint}";
    }
  } @else {
    @error "Invalid breakpoint: #{$breakpoint}";
  }
}

///
/// An orientation media query breakpoint
///
@mixin break-at-orientation($breakpoint) {
  @if type-of($breakpoint) == string {
    @media screen and (orientation: $breakpoint) {
      @content;
    }
  } @else {
    @error "Invalid breakpoint: #{$breakpoint}";
  }
}

///
/// A maximum-aspect-ratio media query breakpoint
///
@mixin break-at-ratio($breakpoint) {
  @if type-of($breakpoint) == number {
    @media screen and (max-aspect-ratio: $breakpoint) {
      @content;
    }
  } @else {
    @error "Invalid breakpoint: #{$breakpoint}";
  }
}

///
/// A minimum-maximum media query device breakpoint
///
@mixin break-at-device($device) {
  @if type-of($device) == string {
    $device: $device,;
  }
  @if type-of($device) == list {
    $breakpoint: break-select-device($device);
    @if list.nth($breakpoint, 2) {
      $min: list.nth($breakpoint, 1);
      $max: list.nth($breakpoint, 2);

      @media screen and (min-width: $min) and (max-width: $max) {
        @content;
      }
    } @else {
      @error "Invalid device: #{$device}";
    }
  } @else {
    @error "Invalid device: #{$device}";
  }
}

///
/// A minimum media query device breakpoint
///
@mixin break-from-device($device) {
  @if type-of($device) == string {
    $device: $device,;
  }
  @if type-of($device) == list {
    $breakpoint: break-select-device($device);
    $min: list.nth($breakpoint, 1);

    @media screen and (min-width: $min) {
      @content;
    }
  } @else {
    @error "Invalid device: #{$device}";
  }
}

///
/// A maximum media query device breakpoint
///
@mixin break-to-device($device) {
  @if type-of($device) == string {
    $device: $device,;
  }
  @if type-of($device) == list {
    $breakpoint: break-select-device($device);
    $max: list.nth($breakpoint, 2);

    @media screen and (max-width: $max) {
      @content;
    }
  } @else {
    @error "Invalid device: #{$device}";
  }
}
