/*
 * EdGEL Mixins
 * --------------------------------------------------
 * All function prefixed "edgel-" when imported
 */

@use "sass:math";

@use "bootstrap" as bs;
@use "../settings" as edgel;

// Box shadows
@mixin shadow() {
  @include bs.box-shadow(edgel.$edgel-shadow);
}

@mixin shadow-light() {
  @include bs.box-shadow(edgel.$edgel-shadow-light);
}

@mixin shadow-inset-light() {
  $shadow: inset 0 2px 1px -1px rgba(0, 0, 0, .15);
  @include bs.box-shadow($shadow);
}

// Top line border
@mixin topline($width: 8px) {
  border-top: $width solid edgel.$brand-color;
}

// Brand background with special link text colour
@mixin brand-bg() {
  color: edgel.$brand-bg-text;
  background-color: edgel.$brand-color;
  --#{edgel.$prefix}link-color-rgb: #{edgel.to-rgb(edgel.$brand-link-color)};
  --#{edgel.$prefix}link-hover-color-rgb: #{edgel.to-rgb(edgel.$brand-link-hover)};
}

// Dark grey background with special link text colour
@mixin dark-bg() {
  color: edgel.$white;
  background-color: edgel.$dark;
  --#{edgel.$prefix}link-color-rgb: #{edgel.to-rgb(edgel.$white)};
  --#{edgel.$prefix}link-hover-color-rgb: #{edgel.to-rgb(edgel.$dark-link-hover-color)};
}

@function px-rem-val($px) {
  $px-val: 0;

  @if unitless($px) {
    $px-val: $px;
  } @else if unit($px) == px {
    $px-val: bs.divide($px, 1px);
  } @else {
    @error "`#{$px}` must be in pixels";
  }

  @return bs.divide($px-val, edgel.$rfs-rem-value);
}

@function px-rem($px) {
  @return #{px-rem-val($px)}rem;
}

@function rem-px-val($rem) {
  $rem-val: 0;

  @if unitless($rem)  {
    $rem-val: $rem;
  } @else if unit($rem) == rem {
    $rem-val: bs.divide($rem, 1rem);
  } @else {
    @error "`#{$rem}` must be in rems";
  }

  @return #{$rem-val * edgel.$rfs-rem-value};
}

@function rem-px($rem) {
  @return #{rem-px-val($rem)}px;
}

// Consistently constrain width
@mixin constrain-width($pad: 0) {
  max-width: (edgel.$font-size-base * (edgel.$base-page-char-width - ($pad * 2)));
  margin-right: auto;
  margin-left: auto;
}

// Width-restricting container
@mixin container($vertical-space-sm: null, $vertical-space: null, $top: true, $bottom: true, $pad: 0) {
  width: 100%;
  padding-top: if($top, edgel.space($vertical-space-sm), null);
  padding-right: edgel.space(3);
  padding-bottom: if($bottom, edgel.space($vertical-space-sm), null);
  padding-left: edgel.space(3);
  @include constrain-width($pad);

  @include bs.media-breakpoint-up(md) {
    padding-top: if($top, edgel.space($vertical-space), null);
    padding-right: edgel.space(5);
    padding-bottom: if($bottom, edgel.space($vertical-space), null);
    padding-left: edgel.space(5);
  }
}

// Scale images
@mixin scale($property, $x1, $x2, $x-unit: px, $v1: 500, $v2: 1500, $v-unit: px) {
  @if $v-unit != rem and $v-unit != px {
    @error "`#{$v-unit}` is not a valid unit. Use `px` or `rem`.";
  }

  @if $x-unit != rem and $x-unit != px {
    @error "`#{$x-unit}` is not a valid unit. Use `px` or `rem`.";
  }

  // Ensure we work to the x units
  $unit-map: (
    "px": 1px,
    "rem": 1rem,
  );
  $x-multiplier: map-get($unit-map, $x-unit);
  $v-multiplier: map-get($unit-map, $x-unit);
  @if $x-unit == px and $v-unit == em {
    $v-multiplier: $v-multiplier * edgel.$rfs-rem-value;
  }
  @if $x-unit == rem and $v-unit == px {
    $v-multiplier: bs.divide($v-multiplier, edgel.$rfs-rem-value);
  }

  @if $x2 <= $x1 {
    @error "$x2 must be greater than $x1";
  }
  @if $v2 <= $v1 {
    @error "$v2 must be greater than $v1";
  }

  $gradient: bs.divide($x2 - $x1, ($v2 - $v1) * $v-multiplier);
  $offset: ($x1 * $x-multiplier - $v1 * $v-multiplier * $gradient);

  // stylelint-disable-next-line function-disallowed-list
  #{$property}: calc(#{$offset} + #{$gradient * 100}vw);
  @media (min-width: $v2 * $v-multiplier) {
    #{$property}: $x2 * $x-multiplier;
  }
}

// Our buttons for consistency
@mixin button-variant($border, $background: $border) {
  $colour: edgel.color-contrast($background);
  $hover-background: edgel.brand-highlight-colour($background, edgel.$btn-hover-bg-shade-amount, edgel.$btn-hover-bg-tint-amount);
  $hover-border: edgel.brand-highlight-colour($border, edgel.$btn-hover-border-shade-amount, edgel.$btn-hover-border-tint-amount);
  $hover-colour: edgel.color-contrast($hover-background);
  $active-background: edgel.brand-highlight-colour($background, edgel.$btn-active-bg-shade-amount, edgel.$btn-active-bg-tint-amount);
  $active-border: edgel.brand-highlight-colour($border, edgel.$btn-active-border-shade-amount, edgel.$btn-active-border-tint-amount);
  $active-colour: edgel.color-contrast($active-background);
  $focus-ring-colour: edgel.color-contrast(edgel.$gray-200, edgel.$dark, mix($colour, $border, 15%), 1.2);
  $disabled-background: edgel.$btn-disabled-background;
  $disabled-border: edgel.$btn-disabled-background;
  $disabled-color: edgel.color-contrast(edgel.$btn-disabled-background);
  $disabled-checked-background: edgel.brand-highlight-colour($disabled-background, edgel.$btn-active-bg-shade-amount, edgel.$btn-active-bg-tint-amount);
  $disabled-checked-border: edgel.brand-highlight-colour($disabled-border, edgel.$btn-active-border-shade-amount, edgel.$btn-active-border-tint-amount);
  $disabled-checked-color: edgel.color-contrast($disabled-checked-background);

  --#{edgel.$prefix}btn-color: #{$colour};
  --#{edgel.$prefix}btn-bg: #{$background};
  --#{edgel.$prefix}btn-border-color: #{$border};
  --#{edgel.$prefix}btn-hover-color: #{$hover-colour};
  --#{edgel.$prefix}btn-hover-bg: #{$hover-background};
  --#{edgel.$prefix}btn-hover-border-color: #{$hover-border};
  --#{edgel.$prefix}btn-focus-shadow-rgb: #{edgel.to-rgb($focus-ring-colour)};
  --#{edgel.$prefix}btn-active-color: #{$active-colour};
  --#{edgel.$prefix}btn-active-bg: #{$active-background};
  --#{edgel.$prefix}btn-active-border-color: #{$active-border};
  --#{edgel.$prefix}btn-active-shadow: #{edgel.$btn-active-box-shadow};
  --#{edgel.$prefix}btn-disabled-color: #{$disabled-color};
  --#{edgel.$prefix}btn-disabled-bg: #{$disabled-background};
  --#{edgel.$prefix}btn-disabled-border-color: #{$disabled-border};
  --#{edgel.$prefix}btn-disabled-checked-color: #{$disabled-checked-color};
  --#{edgel.$prefix}btn-disabled-checked-bg: #{$disabled-checked-background};
  --#{edgel.$prefix}btn-disabled-checked-border-color: #{$disabled-checked-border};
}

@mixin button-outline-variant($colour) {
  $background: #{edgel.color-contrast($colour)};
  $active-background: $colour;
  $active-border: $colour;
  $active-colour: #{edgel.color-contrast($active-background)};
  $focus-ring-colour: edgel.color-contrast(edgel.$gray-200, edgel.$dark, $colour, 1.2);
  $disabled-background: edgel.$btn-disabled-background;
  $disabled-border: edgel.color-contrast(edgel.$btn-disabled-background);
  $disabled-color: edgel.color-contrast(edgel.$btn-disabled-background);
  $disabled-checked-background: edgel.brand-highlight-colour($disabled-background, edgel.$btn-active-bg-shade-amount, edgel.$btn-active-bg-tint-amount);
  $disabled-checked-border: edgel.brand-highlight-colour($disabled-border, edgel.$btn-active-border-shade-amount, edgel.$btn-active-border-tint-amount);
  $disabled-checked-color: edgel.color-contrast($disabled-checked-background);

  --#{edgel.$prefix}btn-color: #{$colour};
  --#{edgel.$prefix}btn-bg: #{$background};
  --#{edgel.$prefix}btn-border-color: #{$colour};
  --#{edgel.$prefix}btn-hover-color: #{$active-colour};
  --#{edgel.$prefix}btn-hover-bg: #{$active-background};
  --#{edgel.$prefix}btn-hover-border-color: #{$active-border};
  --#{edgel.$prefix}btn-focus-shadow-rgb: #{edgel.to-rgb($focus-ring-colour)};
  --#{edgel.$prefix}btn-active-color: #{$active-colour};
  --#{edgel.$prefix}btn-active-bg: #{$active-background};
  --#{edgel.$prefix}btn-active-border-color: #{$active-border};
  --#{edgel.$prefix}btn-active-shadow: #{edgel.$btn-active-box-shadow};
  --#{edgel.$prefix}btn-disabled-color: #{$disabled-color};
  --#{edgel.$prefix}btn-disabled-bg: #{$disabled-background};
  --#{edgel.$prefix}btn-disabled-border-color: #{$disabled-border};
  --#{edgel.$prefix}btn-disabled-checked-color: #{$disabled-checked-color};
  --#{edgel.$prefix}btn-disabled-checked-bg: #{$disabled-checked-background};
  --#{edgel.$prefix}btn-disabled-checked-border-color: #{$disabled-checked-border};
  --#{edgel.$prefix}gradient: none;
}

// Custom button for when we don't want to rely on the .btn class - ie Cookie Banner
@mixin custom-button(
  $background,
  $border: $background,
  $color: edgel.color-contrast($background),
  $hover-background: edgel.brand-highlight-colour($background, $btn-hover-bg-shade-amount, $btn-hover-bg-tint-amount),
  $hover-border: edgel.brand-highlight-colour($border, $btn-hover-border-shade-amount, $btn-hover-border-tint-amount),
  $hover-color: edgel.color-contrast($hover-background),
  $active-background: edgel.brand-highlight-colour($background, $btn-active-bg-shade-amount, $btn-active-bg-tint-amount),
  $active-border: edgel.brand-highlight-colour($border, $btn-active-border-shade-amount, $btn-active-border-tint-amount),
  $active-color: edgel.color-contrast($active-background),
) {
  display: inline-block;
  padding: var(--#{edgel.$prefix}btn-padding-y) var(--#{edgel.$prefix}btn-padding-x);
  @include bs.font-size(var(--#{edgel.$prefix}btn-font-size));
  font-family: edgel.$btn-font-family;
  font-weight: edgel.$btn-font-weight;
  line-height: edgel.$btn-line-height;
  color: $color;
  text-align: center;
  text-decoration: if(edgel.$link-decoration == none, null, none);
  white-space: edgel.$btn-white-space;
  vertical-align: middle;
  cursor: if(edgel.$enable-button-pointers, pointer, null);
  user-select: none;
  background-color: $background;
  border: edgel.$btn-border-width solid $border;
  @include bs.border-radius(var(--#{edgel.$prefix}btn-border-radius));
  @include bs.box-shadow(edgel.$btn-box-shadow);
  @include bs.transition(edgel.$btn-transition);
  @include link-hover-decoration();

  &:hover {
    color: $hover-color;
    @include bs.gradient-bg($hover-background);
    border-color: $hover-border;
  }

  &:focus-visible {
    color: $hover-color;
    border-color: $hover-border;
    outline: 0;
    @if edgel.$enable-shadows {
      @include bs.box-shadow(edgel.$btn-box-shadow, 0 0 0 edgel.$btn-focus-width rgba(mix($hover-color, $hover-border, 15%), edgel.$focus-ring-opacity));
    } @else {
      // Avoid using mixin so we can pass custom focus shadow properly
      box-shadow: 0 0 0 edgel.$btn-focus-width rgba(mix($hover-color, $hover-border, 15%), edgel.$focus-ring-opacity);
    }
  }

  &:active {
    color: $active-color;
    background-color: $active-background;
    // Remove CSS gradients if they're enabled
    background-image: if(edgel.$enable-gradients, none, null);
    border-color: $active-border;

    &:focus-visible {
      @if edgel.$enable-shadows {
        @include bs.box-shadow(edgel.$btn-active-box-shadow, 0 0 0 edgel.$btn-focus-width rgba(mix($active-color, $active-border, 15%), edgel.$focus-ring-opacity));
      } @else {
        // Avoid using mixin so we can pass custom focus shadow properly
        box-shadow: 0 0 0 edgel.$btn-focus-width rgba(mix($active-color, $active-border, 15%), edgel.$focus-ring-opacity);
      }
    }
  }

  &:disabled {
    pointer-events: none;
    opacity: edgel.$btn-disabled-opacity;
    @include bs.box-shadow(none);
  }
}

@mixin toggler-button() {
  @include bs.transition(edgel.$navbar-toggler-transition);
  --#{edgel.$prefix}btn-hover-border-color: currentcolor;
  --#{edgel.$prefix}btn-active-border-color: currentcolor;

  &:focus-visible {
    text-decoration: none;
    outline: 0;
    box-shadow: var(--#{edgel.$prefix}btn-focus-box-shadow);
  }
}

@mixin hamburger-button() {
  @include bs.transition(edgel.$navbar-toggler-transition);
  --#{edgel.$prefix}btn-border-color: currentcolor;
  --#{edgel.$prefix}btn-hover-border-color: currentcolor;
  --#{edgel.$prefix}btn-active-border-color: currentcolor;
}

@mixin reset-button() {
  // Explicitly remove focus outline in Chromium when it shouldn't be
  // visible (e.g. as result of mouse click or touch tap). It already
  // should be doing this automatically, but seems to currently be
  // confused and applies its very visible two-tone outline anyway.
  button:focus:not(:focus-visible) {
    outline: 0;
  }

  input,
  button {
    font-family: inherit;
    @include bs.font-size(inherit);
    line-height: inherit;
  }

  // Remove the inheritance of text transform in Firefox
  button,
  select {
    text-transform: none;
  }

  // Set the cursor for non-`<button>` buttons
  //
  // Details at https://github.com/twbs/bootstrap/pull/30562
  [role="button"] {
    cursor: pointer;
  }
}

@mixin base-link-decoration() {
  font-weight: var(--#{edgel.$prefix}link-font-weight);
  text-decoration-line: underline;
  text-decoration-thickness: edgel.$link-decoration-thickness;
  text-decoration-color: rgba(var(--#{edgel.$prefix}link-color-rgb), var(--#{edgel.$prefix}link-decoration-opacity, 1));
  text-decoration-skip-ink: edgel.$link-decoration-skip-ink;
  text-underline-offset: edgel.$link-underline-offset;
}

// Pseudo link hover
@mixin link-hover-decoration() {
  &:hover,
  &:active {
    text-decoration-line: underline;
    text-decoration-thickness: edgel.$link-decoration-hover-thickness;
    text-decoration-skip-ink: edgel.$link-decoration-skip-ink;
    text-underline-offset: edgel.$link-underline-offset;
  }
}

@mixin link-states() {
  &:hover {
    --#{edgel.$prefix}link-decoration-opacity: #{edgel.$link-decoration-hover-opacity};
    text-decoration-thickness: edgel.$link-decoration-hover-thickness;
  }

  &:focus-visible {
    position: relative;
    z-index: edgel.$zindex-focus;
    outline: 0;
    box-shadow: 0 0 edgel.$focus-ring-blur edgel.$focus-ring-width rgba(var(--#{edgel.$prefix}link-hover-color-rgb), edgel.$focus-ring-opacity);
  }
}
