@use 'sass:math';
@use 'sass:meta';
@use 'sass:map';
@use 'sass:list';
@use './functions' as functions;
@use '../settings/settings' as settings;

@mixin breakpoint($size, $width-type: min-width) {
  @if meta.type-of($size) != 'string' {
    @error 'NSW-DS Breakpoint mixin accepts only strings';
  }

  @if $size != 'xs' and $size != 'sm' and $size != 'md' and $size != 'lg' and $size != 'xl' {
    @error 'NSW-DS Breakpoint mixin allows the following breakpoint sizes xs, sm, md, lg';
  } @else {
    $px-size: map.get(settings.$nsw-breakpoints, $size);
    $rem-size: functions.rem($px-size);

    @media ($width-type: $rem-size) {
      @content;
    }
  }
}

// Default focus state
@mixin nsw-focus($offset: true, $color: var(--nsw-focus)) {
  @if meta.type-of($offset) != bool {
    @error 'NSW-DS nsw-focus mixin allows a boolean for $offset: You have used a type of "#{meta.type-of($offset)}" and a value of "#{$offset}"';
  }

  outline: solid 3px $color;
  outline-offset: 0;

  @if $offset == true {
    outline-offset: 3px;
  }
}

// Default hover state
@mixin nsw-hover {
  background-color: var(--nsw-hover);
}

@mixin nsw-hover-light {
  background-color: var(--nsw-hover-light);
}

//Links
@mixin link() {
  font-weight: var(--nsw-font-bold);
  color: var(--nsw-link);
  text-decoration: underline;
  text-underline-offset: functions.rem(4px);

  &:visited {
    color: var(--nsw-visited);
  }

  &:focus {
    @include nsw-focus($offset: false);
  }

  &:hover {
    @include nsw-hover;
    outline: 2px solid var(--nsw-hover);
  }

  &:active {
    background-color: var(--nsw-active);
    outline-color: var(--nsw-active);
  }
}

@mixin link-dark() {
  color: var(--nsw-link);

  &:visited {
    color: var(--nsw-visited);
  }

  &:focus {
    outline-color: var(--nsw-focus);
  }

  &:hover {
    background-color: var(--nsw-hover);
    outline-color: var(--nsw-hover);
  }

  &:active {
    background-color: var(--nsw-active);
    outline-color: var(--nsw-active);
  }
}

@mixin link-light() {
  color: var(--nsw-link-light);

  &:visited {
    color: var(--nsw-visited-light);
  }

  &:focus {
    outline-color: var(--nsw-focus-light);
  }

  &:hover {
    background-color: var(--nsw-hover-light);
    outline-color: var(--nsw-hover-light);
  }

  &:active {
    background-color: var(--nsw-active-light);
    outline-color: var(--nsw-active-light);
  }
}

@mixin link-button() {
  display: inline-block;
  cursor: pointer;
  background-color: transparent;
  border: 0;
  padding: 2px;
  -webkit-appearance: none; /* stylelint-disable-line property-no-vendor-prefix */
  
  @include link();
  @include font-size('sm');
}

// A block to click around the link
@mixin pseudo-clickable-block {
  &::after {
    @include z-index;
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
  }
}

// Z-index
@mixin z-index($index: 'base') {
  @if map.has-key(settings.$nsw-z-index, $index) == false {
    @error 'NSW-DS z-index mixin allows the following values for $index: #{map.keys(settings.$nsw-z-index)}. You have used "#{$index}"';
  } @else {
    z-index: map.get(settings.$nsw-z-index, $index);
  }
}

//Screen reader text
/* stylelint-disable declaration-no-important  */
@mixin sr-only() {
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;

  &:not(caption) {
    position: absolute !important;
  }
}

@mixin sr-only-focus() {
  &:not(:focus):not(:focus-within) {
    @include sr-only();
  }
}

/* stylelint-enable declaration-no-important  */

//Component spacing
@mixin component-spacing() {
  margin-top: functions.rem(24px);

  &:first-child {
    margin-top: 0;
  }

  @include breakpoint('md') {
    margin-top: functions.rem(32px);
  }
}

// Font-size mixin - returns the font size for mobile and desktop based of the values in $font-sizes map
@mixin font-size($size) {
  @if $size != 'xxs' and $size != 'xs' and $size != 'sm' and $size != 'md' and $size != 'lg' and $size != 'xl' and $size != 'xxl' {
    @error 'NSW-DS font-size mixin allows the following values for $sizes: xxs, xs, sm, md, lg, xl, xxl. You have used "#{$size}"';
  }

  @if $size {
    // Mobile styles – these declarations appear before any nested rules.

    & {
      font-size: var(--nsw-font-size-#{$size}-mobile);
      line-height: var(--nsw-line-height-#{$size}-mobile);
    }

    // Desktop styles – wrap in & {} to opt into new Sass behavior.
    @include breakpoint(settings.$nsw-font-size-reponsive-breakpoint) {
      & {
        font-size: var(--nsw-font-size-#{$size}-desktop);
        line-height: var(--nsw-line-height-#{$size}-desktop);
      }
    }
  }
}

// Material icons mixin - to add icons to pseudo elements
@mixin material-icons() {
  font-family: 'Material Icons';
  -webkit-font-feature-settings: 'liga'; /* stylelint-disable-line property-no-vendor-prefix */
}

//Grid
@mixin container($offset: settings.$grid-gutters*2) {
  max-width: var(--nsw-container-width);
  padding-left: functions.rem($offset);
  padding-right: functions.rem($offset);
  margin-left: auto;
  margin-right: auto;
}

@mixin grid() {
  display: flex;
  flex-wrap: wrap;
  margin-left: functions.rem(-(settings.$grid-gutters));
  margin-right: functions.rem(-(settings.$grid-gutters));

  @include breakpoint('md') {
    margin-left: functions.rem(-(settings.$grid-gutters)*2);
    margin-right: functions.rem(-(settings.$grid-gutters)*2);
  }
}

@mixin row() {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
}

@mixin column-default() {
  width: 100%;
  padding: functions.rem(settings.$grid-gutters);

  @include breakpoint('md') {
    padding: functions.rem(settings.$grid-gutters*2);
  }
}

@mixin column($size, $breakpoint: null, $offset: null) {
  @if ($breakpoint) {
    @include breakpoint($breakpoint) {
      width: math.percentage(math.div($size, 12));
      max-width: math.percentage(math.div($size, 12));

      @if ($offset) {
        margin-left: math.percentage(math.div($offset, 12));
      }
    }

  } @else {
    width: math.percentage(math.div($size, 12));
    max-width: math.percentage(math.div($size, 12));

    @if ($offset) {
      margin-left: math.percentage(math.div($offset, 12));
    }
  }
}

@mixin media-breakpoint-up($name, $breakpoints: settings.$nsw-breakpoints) {
  $min: functions.breakpoint-min($name, $breakpoints);
  @if $min {
    @media (min-width: $min) {
      @content;
    }
  } @else {
    @content;
  }
}

@mixin text-truncate() {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

// Utility generator
// Used to generate utilities & print utilities
/* stylelint-disable string-quotes, number-leading-zero */
@mixin generate-utility($utility, $infix: "", $is-rfs-media-query: false) {
  $values: map.get($utility, values);

  // If the values are a list or string, convert it into a map
  @if meta.type-of($values) == "string" or meta.type-of(list.nth($values, 1)) != "list" {
    $values: list.zip($values, $values);
  }

  @each $key, $value in $values {
    $properties: map.get($utility, property);

    // Multiple properties are possible, for example with vertical or horizontal margins or paddings
    @if meta.type-of($properties) == "string" {
      $properties: list.append((), $properties);
    }

    // Use custom class if present
    $property-class: if(map.has-key($utility, class), map.get($utility, class), list.nth($properties, 1));
    $property-class: if($property-class == null, "", $property-class);

    // Use custom CSS variable name if present, otherwise default to `class`
    $css-variable-name: if(map.has-key($utility, css-variable-name), map.get($utility, css-variable-name), map.get($utility, class));

    // State params to generate pseudo-classes
    $state: if(map.has-key($utility, state), map.get($utility, state), ());

    $infix: if($property-class == "" and str-slice($infix, 1, 1) == "-", str-slice($infix, 2), $infix);

    // Don't prefix if value key is null (e.g. with shadow class)
    $property-class-modifier: if($key, if($property-class == "" and $infix == "", "", "-") + $key, "");

    @if map.get($utility, rfs) {
      // Inside the media query
      @if $is-rfs-media-query {
        $val: rfs-value($value);

        // Do not render anything if fluid and non fluid values are the same
        $value: if($val == rfs-fluid-value($value), null, $val);
      }
      @else {
        $value: rfs-fluid-value($value);
      }
    }

    $is-css-var: map.get($utility, css-var);
    $is-local-vars: map.get($utility, local-vars);
    $is-rtl: map.get($utility, rtl);

    @if $value != null {
      @if $is-rtl == false {
        /* rtl:begin:remove */
      }

      @if $is-css-var {
        .#{$property-class + $infix + $property-class-modifier} {
          --#{settings.$prefix}#{$css-variable-name}: #{$value};
        }

        @each $pseudo in $state {
          .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {
            --#{settings.$prefix}#{$css-variable-name}: #{$value};
          }
        }
      } @else {
        .#{$property-class + $infix + $property-class-modifier} {
          @each $property in $properties {
            @if $is-local-vars {
              @each $local-var, $variable in $is-local-vars {
                --#{settings.$prefix}#{$local-var}: #{$variable};
              }
            }
            #{$property}: $value if(settings.$enable-important-utilities, !important, null);
          }
        }

        @each $pseudo in $state {
          .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {
            @each $property in $properties {
              @if $is-local-vars {
                @each $local-var, $variable in $is-local-vars {
                  --#{settings.$prefix}#{$local-var}: #{$variable};
                }
              }
              #{$property}: $value if(settings.$enable-important-utilities, !important, null);
            }
          }
        }
      }

      @if $is-rtl == false {
        /* rtl:end:remove */
      }
    }
  }
}
