@use '@angular/cdk';
@use './m3-radio';
@use '../core/tokens/token-utils';

$_icon-size: 20px;

$fallbacks: m3-radio.get-tokens();

@function _enter-transition($name) {
  @return $name 90ms cubic-bezier(0, 0, 0.2, 1);
}

@function _exit-transition($name) {
  @return $name 90ms cubic-bezier(0.4, 0, 0.6, 1);
}

// Structural styles for a radio button. Shared with the selection list.
@mixin radio-structure($is-interactive) {
  .mdc-radio {
    display: inline-block;
    position: relative;
    flex: 0 0 auto;
    box-sizing: content-box;
    width: $_icon-size;
    height: $_icon-size;
    cursor: pointer;

    // This is something we inherited from MDC, but it shouldn't be necessary.
    // Removing it will likely lead to screenshot diffs.
    will-change: opacity, transform, border-color, color;

    $size-token: token-utils.slot(radio-state-layer-size, $fallbacks);
    padding: calc((#{$size-token} - #{$_icon-size}) / 2);

    @if ($is-interactive) {
      // MDC's hover indication comes from their ripple which we don't use.
      &:hover > .mdc-radio__native-control:not([disabled]):not(:focus) {
        & ~ .mdc-radio__background::before {
          opacity: 0.04;
          transform: scale(1);
        }
      }

      &:hover > .mdc-radio__native-control:not([disabled]) ~ .mdc-radio__background {
        > .mdc-radio__outer-circle {
          border-color: token-utils.slot(radio-unselected-hover-icon-color, $fallbacks);
        }
      }

      &:hover > .mdc-radio__native-control:enabled:checked + .mdc-radio__background {
        $token: 'radio-selected-hover-icon-color';

        > .mdc-radio__outer-circle {
          border-color: token-utils.slot($token, $fallbacks);
        }

        > .mdc-radio__inner-circle {
          background-color: token-utils.slot($token, $fallbacks, currentColor);
        }
      }

      &:active > .mdc-radio__native-control:enabled:not(:checked) + .mdc-radio__background {
        > .mdc-radio__outer-circle {
          border-color: token-utils.slot(radio-unselected-pressed-icon-color, $fallbacks);
        }
      }

      &:active > .mdc-radio__native-control:enabled:checked + .mdc-radio__background {
        $token: 'radio-selected-pressed-icon-color';

        > .mdc-radio__outer-circle {
          border-color: token-utils.slot($token, $fallbacks);
        }

        > .mdc-radio__inner-circle {
          background-color: token-utils.slot($token, $fallbacks, currentColor);
        }
      }
    }
  }

  .mdc-radio__background {
    display: inline-block;
    position: relative;
    box-sizing: border-box;
    width: $_icon-size;
    height: $_icon-size;

    &::before {
      position: absolute;
      transform: scale(0, 0);
      border-radius: 50%;
      opacity: 0;
      pointer-events: none;
      content: '';
      transition: _exit-transition(opacity), _exit-transition(transform);

      $size: token-utils.slot(radio-state-layer-size, $fallbacks);
      $offset: calc(-1 * (#{$size} - #{$_icon-size}) / 2);
      width: $size;
      height: $size;
      top: $offset;
      left: $offset;
    }
  }

  .mdc-radio__outer-circle {
    position: absolute;
    top: 0;
    left: 0;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    border-width: 2px;
    border-style: solid;
    border-radius: 50%;
    transition: _exit-transition(border-color);
  }

  .mdc-radio__inner-circle {
    position: absolute;
    top: 0;
    left: 0;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    transform: scale(0);
    border-radius: 50%;
    transition: _exit-transition(transform), _exit-transition(background-color);

    @include cdk.high-contrast {
      // Override the color, because solid colors don't show up by default in
      // high contrast mode. We need !important here, because the various state
      // selectors are really specific and duplicating them will be brittle.
      background-color: CanvasText !important;
    }
  }

  .mdc-radio__native-control {
    position: absolute;
    margin: 0;
    padding: 0;
    opacity: 0;
    top: 0;
    right: 0;
    left: 0;
    cursor: inherit;
    z-index: 1;
    width: token-utils.slot(radio-state-layer-size, $fallbacks);
    height: token-utils.slot(radio-state-layer-size, $fallbacks);

    &:checked, &:disabled {
      + .mdc-radio__background {
        transition: _enter-transition(opacity), _enter-transition(transform);

        > .mdc-radio__outer-circle {
          transition: _enter-transition(border-color);
        }

        > .mdc-radio__inner-circle {
          transition: _enter-transition(transform), _enter-transition(background-color);
        }
      }
    }

    @if ($is-interactive) {
      &:focus + .mdc-radio__background::before {
        transform: scale(1);
        opacity: 0.12;
        transition: _enter-transition(opacity), _enter-transition(transform);
      }
    }

    &:disabled {
      &:not(:checked) + .mdc-radio__background > .mdc-radio__outer-circle {
        border-color: token-utils.slot(radio-disabled-unselected-icon-color, $fallbacks);
        opacity: token-utils.slot(radio-disabled-unselected-icon-opacity, $fallbacks);
      }

      + .mdc-radio__background {
        $color-token: 'radio-disabled-selected-icon-color';
        $opacity-token: token-utils.slot(radio-disabled-selected-icon-opacity, $fallbacks);
        cursor: default;

        > .mdc-radio__outer-circle {
          border-color: token-utils.slot($color-token, $fallbacks);
          opacity: $opacity-token;
        }

        > .mdc-radio__inner-circle {
          background-color: token-utils.slot($color-token, $fallbacks, currentColor);
          opacity: $opacity-token;
        }
      }
    }

    &:enabled {
      &:not(:checked) + .mdc-radio__background > .mdc-radio__outer-circle {
        border-color: token-utils.slot(radio-unselected-icon-color, $fallbacks);
      }

      &:checked + .mdc-radio__background {
        $token: 'radio-selected-icon-color';

        > .mdc-radio__outer-circle {
          border-color: token-utils.slot($token, $fallbacks);
        }

        > .mdc-radio__inner-circle {
          background-color: token-utils.slot($token, $fallbacks, currentColor);
        }
      }

      @if ($is-interactive) {
        &:focus:checked + .mdc-radio__background {
          $token: 'radio-selected-focus-icon-color';

          > .mdc-radio__outer-circle {
            border-color: token-utils.slot($token, $fallbacks);
          }

          > .mdc-radio__inner-circle {
            background-color: token-utils.slot($token, $fallbacks, currentColor);
          }
        }
      }
    }

    &:checked + .mdc-radio__background > .mdc-radio__inner-circle {
      transform: scale(0.5);
      transition: _enter-transition(transform), _enter-transition(background-color);
    }
  }

  @if ($is-interactive) {
    &.mat-mdc-radio-disabled-interactive .mdc-radio--disabled {
      pointer-events: auto;

      // stylelint-disable selector-combinator-space-before
      .mdc-radio__native-control:not(:checked) + .mdc-radio__background
          > .mdc-radio__outer-circle {
        border-color: token-utils.slot(radio-disabled-unselected-icon-color, $fallbacks);
        opacity: token-utils.slot(radio-disabled-unselected-icon-opacity, $fallbacks);
      }
      // stylelint-enable selector-combinator-space-before

      &:hover .mdc-radio__native-control:checked + .mdc-radio__background,
      .mdc-radio__native-control:checked:focus + .mdc-radio__background,
      .mdc-radio__native-control + .mdc-radio__background {
        $color-token: 'radio-disabled-selected-icon-color';
        $opacity-token: token-utils.slot(radio-disabled-selected-icon-opacity, $fallbacks);

        > .mdc-radio__outer-circle {
          border-color: token-utils.slot($color-token, $fallbacks);
          opacity: $opacity-token;
        }

        > .mdc-radio__inner-circle {
          background-color: token-utils.slot($color-token, $fallbacks, currentColor);
          opacity: $opacity-token;
        }
      }
    }
  }
}

// Conditionally disables the animations of the radio button.
@mixin radio-noop-animations() {
  &._mat-animation-noopable {
    .mdc-radio__background::before,
    .mdc-radio__outer-circle,
    .mdc-radio__inner-circle {
      // Needs to be `!important`, because MDC's selectors are really specific.
      transition: none !important;
    }
  }
}
