@use '@angular/cdk';
@use '../core/style/layout-common';
@use '../core/tokens/m2/mat/switch' as tokens-mat-switch;
@use '../core/tokens/m2/mdc/switch' as tokens-mdc-switch;
@use '../core/tokens/token-utils';
@use '../core/style/vendor-prefixes';

$_mdc-slots: (tokens-mdc-switch.$prefix, tokens-mdc-switch.get-token-slots());
$_mat-slots: (tokens-mat-switch.$prefix, tokens-mat-switch.get-token-slots());
$_interactive-disabled-selector: '.mat-mdc-slide-toggle-disabled-interactive.mdc-switch--disabled';

.mdc-switch {
  align-items: center;
  background: none;
  border: none;
  cursor: pointer;
  display: inline-flex;
  flex-shrink: 0;
  margin: 0;
  outline: none;
  overflow: visible;
  padding: 0;
  position: relative;

  @include token-utils.use-tokens($_mdc-slots...) {
    @include token-utils.create-token-slot(width, track-width);
  }

  &.mdc-switch--disabled {
    cursor: default;
    pointer-events: none;
  }

  &.mat-mdc-slide-toggle-disabled-interactive {
    pointer-events: auto;
  }
}

.mdc-switch__track {
  overflow: hidden;
  position: relative;
  width: 100%;

  @include token-utils.use-tokens($_mdc-slots...) {
    @include token-utils.create-token-slot(height, track-height);
    @include token-utils.create-token-slot(border-radius, track-shape);

    .mdc-switch--disabled.mdc-switch & {
      @include token-utils.create-token-slot(opacity, disabled-track-opacity);
    }
  }

  &::before,
  &::after {
    border: 1px solid transparent;
    border-radius: inherit;
    box-sizing: border-box;
    content: '';
    height: 100%;
    left: 0;
    position: absolute;
    width: 100%;

    @include token-utils.use-tokens($_mat-slots...) {
      @include token-utils.create-token-slot(border-width, track-outline-width);
      @include token-utils.create-token-slot(border-color, track-outline-color);

      .mdc-switch--selected & {
        @include token-utils.create-token-slot(border-width, selected-track-outline-width);
        @include token-utils.create-token-slot(border-color, selected-track-outline-color);
      }

      .mdc-switch--disabled & {
        @include token-utils.create-token-slot(border-width,
          disabled-unselected-track-outline-width);
        @include token-utils.create-token-slot(border-color,
          disabled-unselected-track-outline-color);
      }
    }
  }

  @include cdk.high-contrast {
    border-color: currentColor;
  }

  &::before {
    transition: transform 75ms 0ms cubic-bezier(0, 0, 0.2, 1);
    transform: translateX(0);

    @include token-utils.use-tokens($_mdc-slots...) {
      @include token-utils.create-token-slot(background, unselected-track-color);
    }

    .mdc-switch--selected & {
      transition: transform 75ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
      transform: translateX(100%);

      [dir='rtl'] .mdc-switch--selected & {
        transform: translateX(-100%);
      }
    }

    @include token-utils.use-tokens($_mat-slots...) {
      .mdc-switch--selected & {
        @include token-utils.create-token-slot(opacity, hidden-track-opacity);
        @include token-utils.create-token-slot(transition, hidden-track-transition);
      }

      .mdc-switch--unselected & {
        @include token-utils.create-token-slot(opacity, visible-track-opacity);
        @include token-utils.create-token-slot(transition, visible-track-transition);
      }
    }

    @include token-utils.use-tokens($_mdc-slots...) {
      .mdc-switch:enabled:hover:not(:focus):not(:active) & {
        @include token-utils.create-token-slot(background, unselected-hover-track-color);
      }

      .mdc-switch:enabled:focus:not(:active) & {
        @include token-utils.create-token-slot(background, unselected-focus-track-color);
      }

      .mdc-switch:enabled:active & {
        @include token-utils.create-token-slot(background, unselected-pressed-track-color);
      }

      #{$_interactive-disabled-selector}:hover:not(:focus):not(:active) &,
      #{$_interactive-disabled-selector}:focus:not(:active) &,
      #{$_interactive-disabled-selector}:active &,
      .mdc-switch.mdc-switch--disabled & {
        @include token-utils.create-token-slot(background, disabled-unselected-track-color);
      }
    }
  }

  &::after {
    transform: translateX(-100%);

    @include token-utils.use-tokens($_mdc-slots...) {
      @include token-utils.create-token-slot(background, selected-track-color);
    }

    [dir='rtl'] & {
      transform: translateX(100%);
    }

    .mdc-switch--selected & {
      transform: translateX(0);
    }

    @include token-utils.use-tokens($_mat-slots...) {
      .mdc-switch--selected & {
        @include token-utils.create-token-slot(opacity, visible-track-opacity);
        @include token-utils.create-token-slot(transition, visible-track-transition);
      }

      .mdc-switch--unselected & {
        @include token-utils.create-token-slot(opacity, hidden-track-opacity);
        @include token-utils.create-token-slot(transition, hidden-track-transition);
      }
    }

    @include token-utils.use-tokens($_mdc-slots...) {
      .mdc-switch:enabled:hover:not(:focus):not(:active) & {
        @include token-utils.create-token-slot(background, selected-hover-track-color);
      }

      .mdc-switch:enabled:focus:not(:active) & {
        @include token-utils.create-token-slot(background, selected-focus-track-color);
      }

      .mdc-switch:enabled:active & {
        @include token-utils.create-token-slot(background, selected-pressed-track-color);
      }

      #{$_interactive-disabled-selector}:hover:not(:focus):not(:active) &,
      #{$_interactive-disabled-selector}:focus:not(:active) &,
      #{$_interactive-disabled-selector}:active &,
      .mdc-switch.mdc-switch--disabled & {
        @include token-utils.create-token-slot(background, disabled-selected-track-color);
      }
    }
  }
}

.mdc-switch__handle-track {
  height: 100%;
  pointer-events: none;
  position: absolute;
  top: 0;
  transition: transform 75ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
  left: 0;
  right: auto;
  transform: translateX(0);

  @include token-utils.use-tokens($_mdc-slots...) {
    width: calc(100% - #{token-utils.get-token-variable(handle-width)});
  }

  [dir='rtl'] & {
    left: auto;
    right: 0;
  }

  .mdc-switch--selected & {
    transform: translateX(100%);

    [dir='rtl'] & {
      transform: translateX(-100%);
    }
  }
}

.mdc-switch__handle {
  display: flex;
  pointer-events: auto;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  right: auto;

  // Used for M3 animations. Does not affect the M2 slide-toggle
  // because the width and height are static, and the margin is unused.
  transition:
    width 75ms cubic-bezier(0.4, 0, 0.2, 1),
    height 75ms cubic-bezier(0.4, 0, 0.2, 1),
    margin 75ms cubic-bezier(0.4, 0, 0.2, 1);

  @include token-utils.use-tokens($_mdc-slots...) {
    @include token-utils.create-token-slot(width, handle-width);
    @include token-utils.create-token-slot(height, handle-height);
    @include token-utils.create-token-slot(border-radius, handle-shape);
  }

  [dir='rtl'] & {
    left: auto;
    right: 0;
  }

  @include token-utils.use-tokens($_mat-slots...) {
    .mat-mdc-slide-toggle .mdc-switch--unselected & {
      @include token-utils.create-token-slot(width, unselected-handle-size);
      @include token-utils.create-token-slot(height, unselected-handle-size);
      @include token-utils.create-token-slot(margin, unselected-handle-horizontal-margin);

      &:has(.mdc-switch__icons) {
        @include token-utils.create-token-slot(margin,
          unselected-with-icon-handle-horizontal-margin);
      }
    }

    .mat-mdc-slide-toggle .mdc-switch--selected & {
      @include token-utils.create-token-slot(width, selected-handle-size);
      @include token-utils.create-token-slot(height, selected-handle-size);
      @include token-utils.create-token-slot(margin, selected-handle-horizontal-margin);

      &:has(.mdc-switch__icons) {
        @include token-utils.create-token-slot(margin, selected-with-icon-handle-horizontal-margin);
      }
    }

    .mat-mdc-slide-toggle &:has(.mdc-switch__icons) {
      @include token-utils.create-token-slot(width, with-icon-handle-size);
      @include token-utils.create-token-slot(height, with-icon-handle-size);
    }

    .mat-mdc-slide-toggle .mdc-switch:active:not(.mdc-switch--disabled) & {
      @include token-utils.create-token-slot(width, pressed-handle-size);
      @include token-utils.create-token-slot(height, pressed-handle-size);
    }

    .mat-mdc-slide-toggle .mdc-switch--selected:active:not(.mdc-switch--disabled) & {
      @include token-utils.create-token-slot(margin, selected-pressed-handle-horizontal-margin);
    }

    .mat-mdc-slide-toggle .mdc-switch--unselected:active:not(.mdc-switch--disabled) & {
      @include token-utils.create-token-slot(margin, unselected-pressed-handle-horizontal-margin);
    }

    .mdc-switch--disabled.mdc-switch--selected &::after {
      @include token-utils.create-token-slot(opacity, disabled-selected-handle-opacity);
    }

    .mdc-switch--disabled.mdc-switch--unselected &::after {
      @include token-utils.create-token-slot(opacity, disabled-unselected-handle-opacity);
    }
  }

  &::before,
  &::after {
    border: 1px solid transparent;
    border-radius: inherit;
    box-sizing: border-box;
    content: '';
    width: 100%;
    height: 100%;
    left: 0;
    position: absolute;
    top: 0;
    transition: background-color 75ms 0ms cubic-bezier(0.4, 0, 0.2, 1),
      border-color 75ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
    z-index: -1;

    @include cdk.high-contrast {
      border-color: currentColor;
    }
  }

  @include token-utils.use-tokens($_mdc-slots...) {
    &::after {
      .mdc-switch--selected:enabled & {
        @include token-utils.create-token-slot(background, selected-handle-color);
      }

      .mdc-switch--selected:enabled:hover:not(:focus):not(:active) & {
        @include token-utils.create-token-slot(background, selected-hover-handle-color);
      }

      .mdc-switch--selected:enabled:focus:not(:active) & {
        @include token-utils.create-token-slot(background, selected-focus-handle-color);
      }

      .mdc-switch--selected:enabled:active & {
        @include token-utils.create-token-slot(background, selected-pressed-handle-color);
      }

      #{$_interactive-disabled-selector}.mdc-switch--selected:hover:not(:focus):not(:active) &,
      #{$_interactive-disabled-selector}.mdc-switch--selected:focus:not(:active) &,
      #{$_interactive-disabled-selector}.mdc-switch--selected:active &,
      .mdc-switch--selected.mdc-switch--disabled & {
        @include token-utils.create-token-slot(background, disabled-selected-handle-color);
      }

      .mdc-switch--unselected:enabled & {
        @include token-utils.create-token-slot(background, unselected-handle-color);
      }

      .mdc-switch--unselected:enabled:hover:not(:focus):not(:active) & {
        @include token-utils.create-token-slot(background, unselected-hover-handle-color);
      }

      .mdc-switch--unselected:enabled:focus:not(:active) & {
        @include token-utils.create-token-slot(background, unselected-focus-handle-color);
      }

      .mdc-switch--unselected:enabled:active & {
        @include token-utils.create-token-slot(background, unselected-pressed-handle-color);
      }

      .mdc-switch--unselected.mdc-switch--disabled & {
        @include token-utils.create-token-slot(background, disabled-unselected-handle-color);
      }
    }

    &::before {
      @include token-utils.create-token-slot(background, handle-surface-color);
    }
  }
}

.mdc-switch__shadow {
  border-radius: inherit;
  bottom: 0;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;

  @include token-utils.use-tokens($_mdc-slots...) {
    .mdc-switch:enabled & {
      @include token-utils.create-token-slot(box-shadow, handle-elevation-shadow);
    }

    #{$_interactive-disabled-selector}:hover:not(:focus):not(:active) &,
    #{$_interactive-disabled-selector}:focus:not(:active) &,
    #{$_interactive-disabled-selector}:active &,
    .mdc-switch.mdc-switch--disabled & {
      @include token-utils.create-token-slot(box-shadow, disabled-handle-elevation-shadow);
    }
  }
}

.mdc-switch__ripple {
  left: 50%;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: -1;

  @include token-utils.use-tokens($_mdc-slots...) {
    @include token-utils.create-token-slot(width, state-layer-size);
    @include token-utils.create-token-slot(height, state-layer-size);
  }

  &::after {
    content: '';
    opacity: 0;

    .mdc-switch--disabled & {
      display: none;
    }

    .mat-mdc-slide-toggle-disabled-interactive & {
      display: block;
    }

    .mdc-switch:hover & {
      opacity: 0.04;
      transition: 75ms opacity cubic-bezier(0, 0, 0.2, 1);
    }

    // Needs a little more specificity so the :hover styles don't override it.
    .mat-mdc-slide-toggle.mat-mdc-slide-toggle-focused .mdc-switch & {
      opacity: 0.12;
    }

    @include token-utils.use-tokens($_mdc-slots...) {
      #{$_interactive-disabled-selector}:enabled:focus &,
      #{$_interactive-disabled-selector}:enabled:active &,
      #{$_interactive-disabled-selector}:enabled:hover:not(:focus) &,
      .mdc-switch--unselected:enabled:hover:not(:focus) & {
        @include token-utils.create-token-slot(background, unselected-hover-state-layer-color);
      }

      .mdc-switch--unselected:enabled:focus & {
        @include token-utils.create-token-slot(background, unselected-focus-state-layer-color);
      }

      .mdc-switch--unselected:enabled:active & {
        @include token-utils.create-token-slot(background, unselected-pressed-state-layer-color);
        @include token-utils.create-token-slot(opacity, unselected-pressed-state-layer-opacity);
        transition: opacity 75ms linear;
      }

      .mdc-switch--selected:enabled:hover:not(:focus) & {
        @include token-utils.create-token-slot(background, selected-hover-state-layer-color);
      }

      .mdc-switch--selected:enabled:focus & {
        @include token-utils.create-token-slot(background, selected-focus-state-layer-color);
      }

      .mdc-switch--selected:enabled:active & {
        @include token-utils.create-token-slot(background, selected-pressed-state-layer-color);
        @include token-utils.create-token-slot(opacity, selected-pressed-state-layer-opacity);
        transition: opacity 75ms linear;
      }
    }
  }
}

.mdc-switch__icons {
  position: relative;
  height: 100%;
  width: 100%;
  z-index: 1;

  @include token-utils.use-tokens($_mdc-slots...) {
    .mdc-switch--disabled.mdc-switch--unselected & {
      @include token-utils.create-token-slot(opacity, disabled-unselected-icon-opacity);
    }

    .mdc-switch--disabled.mdc-switch--selected & {
      @include token-utils.create-token-slot(opacity, disabled-selected-icon-opacity);
    }
  }
}

.mdc-switch__icon {
  bottom: 0;
  left: 0;
  margin: auto;
  position: absolute;
  right: 0;
  top: 0;
  opacity: 0;
  transition: opacity 30ms 0ms cubic-bezier(0.4, 0, 1, 1);

  @include token-utils.use-tokens($_mdc-slots...) {
    .mdc-switch--unselected & {
      @include token-utils.create-token-slot(width, unselected-icon-size);
      @include token-utils.create-token-slot(height, unselected-icon-size);
      @include token-utils.create-token-slot(fill, unselected-icon-color);
    }

    .mdc-switch--unselected.mdc-switch--disabled & {
      @include token-utils.create-token-slot(fill, disabled-unselected-icon-color);
    }

    .mdc-switch--selected & {
      @include token-utils.create-token-slot(width, selected-icon-size);
      @include token-utils.create-token-slot(height, selected-icon-size);
      @include token-utils.create-token-slot(fill, selected-icon-color);
    }

    .mdc-switch--selected.mdc-switch--disabled & {
      @include token-utils.create-token-slot(fill, disabled-selected-icon-color);
    }
  }
}

.mdc-switch--selected .mdc-switch__icon--on,
.mdc-switch--unselected .mdc-switch__icon--off {
  opacity: 1;
  transition: opacity 45ms 30ms cubic-bezier(0, 0, 0.2, 1);
}

.mat-mdc-slide-toggle {
  @include vendor-prefixes.user-select(none);
  display: inline-block;
  -webkit-tap-highlight-color: transparent;

  // Remove the native outline since we use the ripple for focus indication.
  outline: 0;

  // The ripple needs extra specificity so the base ripple styling doesn't override its `position`.
  .mat-mdc-slide-toggle-ripple,
  .mdc-switch__ripple::after {
    @include layout-common.fill();
    border-radius: 50%;
    // Disable pointer events for the ripple container so that it doesn't eat the mouse events meant
    // for the input. Pointer events can be safely disabled because the ripple trigger element is
    // the host element.
    pointer-events: none;
    // Fixes the ripples not clipping to the border radius on Safari. Uses `:not(:empty)`
    // in order to avoid creating extra layers when there aren't any ripples.
    &:not(:empty) {
      transform: translateZ(0);
    }
  }

  // Needs a little more specificity so the :hover styles don't override it.
  // For slide-toggles render the focus indicator when we know
  // the hidden input is focused (slightly different for each control).
  &.mat-mdc-slide-toggle-focused .mat-focus-indicator::before {
    content: '';
  }

  .mat-internal-form-field {
    @include token-utils.use-tokens($_mat-slots...) {
      @include token-utils.create-token-slot(color, label-text-color);
      @include token-utils.create-token-slot(font-family, label-text-font);
      @include token-utils.create-token-slot(line-height, label-text-line-height);
      @include token-utils.create-token-slot(font-size, label-text-size);
      @include token-utils.create-token-slot(letter-spacing, label-text-tracking);
      @include token-utils.create-token-slot(font-weight, label-text-weight);
    }
  }

  .mat-ripple-element {
    opacity: 0.12;
  }

  // Slide-toggle components have to set `border-radius: 50%` in order to support density scaling
  // which will clip a square focus indicator so we have to turn it into a circle.
  .mat-focus-indicator::before {
    border-radius: 50%;
  }

  &._mat-animation-noopable {
    .mdc-switch__handle-track,
    .mdc-switch__icon,
    .mdc-switch__handle::before,
    .mdc-switch__handle::after,
    .mdc-switch__track::before,
    .mdc-switch__track::after {
      transition: none;
    }
  }

  // If our slide-toggle is enabled the cursor on label should appear as a pointer.
  .mdc-switch:enabled + .mdc-label {
    cursor: pointer;
  }

  // TODO(wagnermaciel): Use our custom token system to emit this css rule.
  .mdc-switch--disabled + label {
    color: var(--mdc-switch-disabled-label-text-color);
  }
}
