// Copyright 2015 Palantir Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0.

@use "sass:list";
@use "sass:map";
@use "sass:math";
@import "../../common/mixins";
@import "../../common/variables";
@import "../button/common";

$control-background-color: transparent !default;
$control-background-color-hover: $minimal-button-background-color-hover !default;
$control-background-color-active: $minimal-button-background-color-active !default;
$control-background-color-disabled: $minimal-button-background-color-hover !default;
$dark-control-background-color: transparent !default;
$dark-control-background-color-hover: $minimal-button-background-color-hover !default;
$dark-control-background-color-active: $minimal-button-background-color-active !default;
$dark-control-background-color-disabled: $minimal-button-background-color-hover !default;

$control-checked-background-color: list.nth(map.get($button-intents, "primary"), 1) !default;
$control-checked-background-color-hover: list.nth(map.get($button-intents, "primary"), 2) !default;
$control-checked-background-color-active: list.nth(map.get($button-intents, "primary"), 3) !default;
$control-checked-background-color-disabled: rgba($control-checked-background-color, 0.5) !default;

$control-box-shadow: inset 0 0 0 $button-border-width $gray2 !default;
$control-checked-box-shadow: inset 0 0 0 $button-border-width rgba($black, 0.2) !default;
$dark-control-box-shadow: inset 0 0 0 $button-border-width $gray3 !default;
$dark-control-checked-box-shadow: inset 0 0 0 $button-border-width rgba($white, 0.1) !default;

$control-indicator-size: $pt-icon-size-standard !default;
$control-indicator-size-large: $pt-icon-size-large !default;
$control-indicator-spacing: $pt-spacing * 2 !default;

@mixin control-checked-colors($selector: ":checked") {
  input#{$selector} ~ .#{$ns}-control-indicator {
    background-color: $control-checked-background-color;
    box-shadow: $control-checked-box-shadow;
    color: $white;

    @media (forced-colors: active) and (prefers-color-scheme: dark) {
      background-color: $pt-high-contrast-mode-active-background-color;
      // Windows High Contrast dark theme
      border: 1px solid $pt-high-contrast-mode-active-background-color;
    }
  }

  &:hover input#{$selector} ~ .#{$ns}-control-indicator {
    background-color: $control-checked-background-color-hover;

    @media (forced-colors: active) and (prefers-color-scheme: dark) {
      // Windows High Contrast dark theme
      background-color: $pt-high-contrast-mode-active-background-color;
    }
  }

  input:not(:disabled):active#{$selector} ~ .#{$ns}-control-indicator {
    background: $control-checked-background-color-active;
  }

  input:disabled#{$selector} ~ .#{$ns}-control-indicator {
    background: $control-checked-background-color-disabled;
    box-shadow: none;
    color: rgba($white, 0.6);

    @media (forced-colors: active) and (prefers-color-scheme: dark) {
      background-color: $pt-high-contrast-mode-disabled-border-color;
      border-color: $pt-high-contrast-mode-disabled-border-color;
    }
  }

  .#{$ns}-dark & {
    input#{$selector} ~ .#{$ns}-control-indicator {
      box-shadow: $dark-control-checked-box-shadow;

      @media (forced-colors: active) and (prefers-color-scheme: dark) {
        // Windows High Contrast dark theme
        border: 1px solid $pt-high-contrast-mode-border-color;
      }
    }

    &:hover input#{$selector} ~ .#{$ns}-control-indicator {
      background-color: $control-checked-background-color-hover;
      box-shadow: $dark-control-checked-box-shadow;
    }

    input:not(:disabled):active#{$selector} ~ .#{$ns}-control-indicator {
      background-color: $control-checked-background-color-active;
      box-shadow: $dark-control-checked-box-shadow;
    }

    input:disabled#{$selector} ~ .#{$ns}-control-indicator {
      background: $control-checked-background-color-disabled;
      box-shadow: none;
      color: rgba($white, 0.6);
    }
  }
}

@mixin indicator-position($size) {
  $padding: $size + $control-indicator-spacing;

  &:not(.#{$ns}-align-right) {
    padding-inline-start: $padding;

    .#{$ns}-control-indicator {
      margin-inline-start: -$padding;
    }
  }

  &.#{$ns}-align-right {
    padding-right: $padding;

    .#{$ns}-control-indicator {
      margin-right: -$padding;
    }
  }

  // special handling for left-aligned indicators in RTL
  [dir="rtl"] &.#{$ns}-align-left {
    padding-inline-start: 0;
    padding-left: $padding;

    .#{$ns}-control-indicator {
      margin-left: -$padding;
    }
  }
}

.#{$ns}-control {
  @include control-checked-colors;
  @include indicator-position($control-indicator-size);
  cursor: pointer;

  display: block;
  margin-bottom: $pt-spacing * 2;
  position: relative;
  text-transform: none;

  &.#{$ns}-disabled {
    color: $pt-text-color-disabled;
    cursor: not-allowed;
  }

  &.#{$ns}-inline {
    display: inline-block;
    margin-inline-end: $pt-spacing * 5;
  }

  .#{$ns}-control-input {
    left: 0;
    opacity: 0;
    position: absolute;
    top: 0;
    z-index: -1; // don't let it intercept clicks
  }

  .#{$ns}-control-indicator {
    background-clip: padding-box;
    background-color: $control-background-color;
    border: none;
    box-shadow: $control-box-shadow;
    cursor: pointer;
    display: inline-block;
    // font-size is used to size indicator for all control types,
    // to reduce property changes needed across types and sizes (large).
    font-size: $control-indicator-size;
    height: 1em;
    margin-inline-end: $control-indicator-spacing;
    margin-top: $pt-spacing * -0.75;
    position: relative;
    user-select: none;
    vertical-align: middle;
    width: 1em;

    &::before {
      content: "";
      display: block;
      height: 1em;
      width: 1em;
    }

    @media (forced-colors: active) and (prefers-color-scheme: dark) {
      // Windows High Contrast dark theme
      border: 1px solid $pt-high-contrast-mode-border-color;

      &::before {
        // Because we're using a border in high contrast mode, we need to adjust the margins
        // to compensate for the space the border takes up
        margin-left: -1px;
        margin-top: -1px;
      }
    }
  }

  &:hover .#{$ns}-control-indicator {
    background-color: $control-background-color-hover;
  }

  input:not(:disabled):active ~ .#{$ns}-control-indicator {
    background: $control-background-color-active;
    box-shadow: $control-box-shadow;
  }

  input:disabled ~ .#{$ns}-control-indicator {
    background: $control-background-color-disabled;
    box-shadow: none;
    cursor: not-allowed;
  }

  input:focus ~ .#{$ns}-control-indicator {
    @include focus-outline;
  }

  // right-aligned indicator is glued to the right side of the container
  &.#{$ns}-align-right .#{$ns}-control-indicator {
    float: right;
    margin-left: $control-indicator-spacing;
    margin-top: 1px;
  }

  [dir="rtl"] &.#{$ns}-align-left .#{$ns}-control-indicator {
    float: left;
    margin-top: 1px;
  }

  &.#{$ns}-large {
    @include indicator-position($control-indicator-size-large);
    // larger text
    font-size: $pt-font-size-large;

    .#{$ns}-control-indicator {
      // em-based sizing
      font-size: $control-indicator-size-large;
    }

    &.#{$ns}-align-right .#{$ns}-control-indicator {
      margin-top: 0;
    }

    [dir="rtl"] &.#{$ns}-align-left .#{$ns}-control-indicator {
      margin-top: 0;
    }
  }

  &.#{$ns}-checkbox {
    @mixin indicator-inline-icon($icon, $fill-color: $white) {
      &::before {
        // embed SVG icon image as backgroud-image above gradient.
        // the SVG image content is inlined into the CSS, so use this sparingly.
        background-image: svg-icon(
          "16px/#{$icon}.svg",
          (
            path: (
              fill: $fill-color,
            ),
          )
        );
      }
    }

    // make :indeterminate look like :checked _for Checkbox only_
    @include control-checked-colors(":indeterminate");

    .#{$ns}-control-indicator {
      border-radius: $pt-border-radius;
    }

    input:checked ~ .#{$ns}-control-indicator {
      @include indicator-inline-icon("small-tick");
    }

    input:indeterminate ~ .#{$ns}-control-indicator {
      @include indicator-inline-icon("small-minus");
    }

    input:disabled ~ .#{$ns}-control-indicator::before {
      opacity: 0.5;
    }

    @media (forced-colors: active) and (prefers-color-scheme: dark) {
      input:checked:not(:disabled) ~ .#{$ns}-control-indicator {
        @include indicator-inline-icon("small-tick", $black);
      }

      input:indeterminate:not(:disabled) ~ .#{$ns}-control-indicator {
        @include indicator-inline-icon("small-minus", $black);
      }

      input:disabled ~ .#{$ns}-control-indicator {
        border-color: $pt-high-contrast-mode-disabled-border-color;
      }
    }
  }

  &.#{$ns}-radio {
    .#{$ns}-control-indicator {
      border-radius: 50%;
    }

    input:checked ~ .#{$ns}-control-indicator::before {
      background-image: radial-gradient($white, $white 28%, transparent 32%);

      @media (forced-colors: active) and (prefers-color-scheme: dark) {
        // Windows High Contrast dark theme
        background: $pt-high-contrast-mode-active-background-color;
        // Subtract border on either end, and then an extra 2px for space between the border
        height: $control-indicator-size - $pt-spacing;
        margin-left: 1px;
        margin-top: 1px;
        width: $control-indicator-size - $pt-spacing;
      }
    }

    input:checked:disabled ~ .#{$ns}-control-indicator::before {
      opacity: 0.5;

      @media (forced-colors: active) and (prefers-color-scheme: dark) {
        background: $pt-high-contrast-mode-disabled-background-color;
      }
    }

    input:focus ~ .#{$ns}-control-indicator {
      -moz-outline-radius: $control-indicator-size;
    }

    @media (forced-colors: active) and (prefers-color-scheme: dark) {
      input:disabled ~ .#{$ns}-control-indicator {
        border-color: $pt-high-contrast-mode-disabled-border-color;
      }
    }
  }

  /* stylelint-disable-next-line order/order */
  $switch-width: 1.75em !default;
  $switch-indicator-margin: $pt-spacing * 0.5 !default;
  $switch-indicator-size: calc(1em - #{$switch-indicator-margin * 2});

  $switch-indicator-child-height: 1em;
  $switch-indicator-child-outside-margin: 0.5em;
  $switch-indicator-child-inside-margin: 1.2em;

  $switch-indicator-text-font-size: 0.7em;

  $switch-text-color: $pt-text-color !default;
  $switch-text-color-disabled: $pt-text-color-disabled !default;
  $switch-checked-text-color: $white !default;
  $switch-checked-text-color-disabled: rgba($white, 0.6) !default;
  $switch-background-color: rgba($gray3, 0.3) !default;
  $switch-background-color-hover: rgba($gray3, 0.4) !default;
  $switch-background-color-active: rgba($gray3, 0.5) !default;
  $switch-background-color-disabled: rgba($gray3, 0.15) !default;
  $switch-checked-background-color: $control-checked-background-color !default;
  $switch-checked-background-color-hover: $control-checked-background-color-hover !default;
  $switch-checked-background-color-active: $control-checked-background-color-active !default;
  $switch-checked-background-color-disabled: rgba($blue3, 0.5) !default;

  $dark-switch-text-color: $pt-dark-text-color !default;
  $dark-switch-text-color-disabled: $pt-dark-text-color-disabled !default;
  $dark-switch-checked-text-color: $white !default;
  $dark-switch-checked-text-color-disabled: $pt-dark-text-color-disabled !default;

  $switch-indicator-background-color: rgba($gray3, 0.3) !default;
  $switch-indicator-box-shadow: 0 0 0 $button-border-width rgba($black, 0.5) !default;
  $switch-indicator-background-color-disabled: rgba($white, 0.8) !default;
  $switch-checked-indicator-background-color-disabled: rgba($white, 0.5) !default;

  &.#{$ns}-switch {
    @mixin indicator-colors(
      $selector,
      $text-color,
      $background-color,
      $hover-color,
      $active-color,
      $disabled-text-color,
      $disabled-background-color,
      $disabled-indicator-color
    ) {
      input#{$selector} ~ .#{$ns}-control-indicator {
        background: $background-color;
        color: $text-color;
      }

      &:hover input#{$selector} ~ .#{$ns}-control-indicator {
        background: $hover-color;
      }

      input#{$selector}:not(:disabled):active ~ .#{$ns}-control-indicator {
        background: $active-color;
      }

      input#{$selector}:disabled ~ .#{$ns}-control-indicator {
        background: $disabled-background-color;
        color: $disabled-text-color;

        &::before {
          background: $disabled-indicator-color;
          box-shadow: none;
        }
      }
    }

    @include indicator-colors(
      "",
      $switch-text-color,
      $switch-background-color,
      $switch-background-color-hover,
      $switch-background-color-active,
      $switch-text-color-disabled,
      $switch-background-color-disabled,
      $switch-indicator-background-color-disabled
    );
    @include indicator-colors(
      ":checked",
      $switch-checked-text-color,
      $switch-checked-background-color,
      $switch-checked-background-color-hover,
      $switch-checked-background-color-active,
      $switch-checked-text-color-disabled,
      $switch-checked-background-color-disabled,
      $switch-checked-indicator-background-color-disabled
    );
    // convert em variable to px value
    @include indicator-position(math.div($switch-width, 1em) * $control-indicator-size);

    // Add Windows high contrast mode styles
    @media (forced-colors: active) and (prefers-color-scheme: dark) {
      input:checked ~ .#{$ns}-control-indicator {
        background: $pt-high-contrast-mode-active-background-color;
        border: 1px solid $pt-high-contrast-mode-border-color;
      }

      input:checked:disabled ~ .#{$ns}-control-indicator {
        background-color: $pt-high-contrast-mode-disabled-background-color;
      }

      input:not(:checked):disabled ~ .#{$ns}-control-indicator {
        border-color: $pt-high-contrast-mode-disabled-border-color;

        &::before {
          border-color: $pt-high-contrast-mode-disabled-border-color;
        }
      }

      &:hover input:checked ~ .#{$ns}-control-indicator {
        background: $pt-high-contrast-mode-active-background-color;
      }
    }

    .#{$ns}-control-indicator {
      border: none;
      border-radius: $switch-width;
      // override default button styles, never have a box-shadow here.
      /* stylelint-disable-next-line declaration-no-important */
      box-shadow: none !important;
      min-width: $switch-width;
      transition: background-color $pt-transition-duration $pt-transition-ease;
      width: auto;

      &::before {
        background: $white;
        border-radius: 50%;
        box-shadow: $switch-indicator-box-shadow;
        height: $switch-indicator-size;
        left: $switch-indicator-margin;
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        transition: left $pt-transition-duration $pt-transition-ease;
        width: $switch-indicator-size;

        @media (forced-colors: active) and (prefers-color-scheme: dark) {
          // Windows High Contrast dark theme
          border: 1px solid $pt-high-contrast-mode-border-color;
          // Because we're using a border for the outline, we need to decrease the top margin
          margin-top: $switch-indicator-margin - 1px;
        }
      }

      @media (forced-colors: active) and (prefers-color-scheme: dark) {
        border: 1px solid $pt-high-contrast-mode-border-color;
      }
    }

    input:checked ~ .#{$ns}-control-indicator::before {
      // 1em is size of indicator
      left: calc($switch-indicator-margin + 100% - 1em);
    }

    &.#{$ns}-large {
      @include indicator-position(math.div($switch-width, 1em) * $control-indicator-size-large);
    }

    .#{$ns}-dark & {
      @include indicator-colors(
        "",
        $dark-switch-text-color,
        $switch-background-color,
        $switch-background-color-hover,
        $switch-background-color-active,
        $dark-switch-text-color-disabled,
        $switch-background-color-disabled,
        $switch-indicator-background-color-disabled
      );
      @include indicator-colors(
        ":checked",
        $dark-switch-checked-text-color,
        $switch-checked-background-color,
        $switch-checked-background-color-hover,
        $switch-checked-background-color-active,
        $dark-switch-checked-text-color-disabled,
        $switch-checked-background-color-disabled,
        $switch-checked-indicator-background-color-disabled
      );

      // Add Windows high contrast mode styles
      @media (forced-colors: active) and (prefers-color-scheme: dark) {
        input:checked ~ .#{$ns}-control-indicator {
          background: $pt-high-contrast-mode-active-background-color;
          border: 1px solid $pt-high-contrast-mode-border-color;
        }

        input:checked:disabled ~ .#{$ns}-control-indicator {
          background-color: $pt-high-contrast-mode-disabled-background-color;
        }

        input:not(:checked):disabled ~ .#{$ns}-control-indicator {
          border-color: $pt-high-contrast-mode-disabled-border-color;

          // stylelint-disable-next-line max-nesting-depth
          &::before {
            border-color: $pt-high-contrast-mode-disabled-border-color;
          }
        }

        &:hover input:checked ~ .#{$ns}-control-indicator {
          background: $pt-high-contrast-mode-active-background-color;
        }
      }
    }

    .#{$ns}-switch-inner-text {
      font-size: $switch-indicator-text-font-size;
      text-align: center;
    }

    .#{$ns}-control-indicator-child {
      &:first-child {
        line-height: 0;
        margin-left: $switch-indicator-child-outside-margin;
        margin-right: $switch-indicator-child-inside-margin;
        visibility: hidden;
      }

      &:last-child {
        line-height: $switch-indicator-child-height;
        margin-left: $switch-indicator-child-inside-margin;
        margin-right: $switch-indicator-child-outside-margin;
        visibility: visible;
      }
    }

    input:checked ~ .#{$ns}-control-indicator .#{$ns}-control-indicator-child {
      &:first-child {
        line-height: $switch-indicator-child-height;
        visibility: visible;
      }

      &:last-child {
        line-height: 0;
        visibility: hidden;
      }
    }
  }

  .#{$ns}-dark & {
    color: $pt-dark-text-color;

    &.#{$ns}-disabled {
      color: $pt-dark-text-color-disabled;
    }

    .#{$ns}-control-indicator {
      background-color: $dark-control-background-color;
      box-shadow: $dark-control-box-shadow;
    }

    &:hover .#{$ns}-control-indicator {
      background-color: $dark-control-background-color-hover;
    }

    input:not(:disabled):active ~ .#{$ns}-control-indicator {
      background: $dark-control-background-color-active;
      box-shadow: $dark-control-box-shadow;
    }

    input:disabled ~ .#{$ns}-control-indicator {
      background: $dark-control-background-color-disabled;
      box-shadow: none;
      cursor: not-allowed;
    }

    &.#{$ns}-checkbox input:disabled {
      &:checked,
      &:indeterminate {
        ~ .#{$ns}-control-indicator {
          background: $control-checked-background-color-disabled;
        }
      }
    }
  }
}
