//
// Copyright 2016 Google Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// stylelint-disable selector-class-pattern --
// Selector '.mdc-*' should only be used in this project.

@use 'sass:map';
@use 'sass:math';
@use '../animation/functions' as functions2;
@use '../animation/variables' as animation-variables;
@use '../density/functions' as density-functions;
@use '../dom/dom';
@use '../feature-targeting/feature-targeting';
@use '../focus-ring/focus-ring';
@use '../ripple/ripple';
@use '../ripple/ripple-theme';
@use '../touch-target/mixins' as touch-target-mixins;
@use '../theme/theme-color';
@use './checkbox-custom-properties';
@use '../theme/theme';
@use '../theme/color-custom-properties';
@use '../theme/custom-properties';
@use '../touch-target/variables' as touch-target-variables;
@use './checkbox-theme';

///
/// Checkbox and ripple styles.
///
@mixin core-styles($query: feature-targeting.all()) {
  @include without-ripple($query);
  @include ripple-styles($query);
}

/// Checkbox styles (Excluding ripple styles).
///
/// NOTE: This API is intended for use by frameworks that may want to separate the ripple-related styles from the other
/// checkbox styles. It is recommended that most users use `mdc-checkbox-core-styles` instead.
// TODO(b/162887560): Rename to `checkbox-without-ripple-styles()`
@mixin without-ripple($query: feature-targeting.all()) {
  // TODO(b/165005345): Include theme-styles() after static-styles().
  @include theme-styles($query: $query);
  @include static-styles($query: $query);
}

/// Checkbox static styles.
/// Checkbox styles that are not customizable should go here.
@mixin static-styles($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include touch-target-mixins.wrapper($query); // COPYBARA_COMMENT_THIS_LINE

  @include feature-targeting.targets($feat-animation) {
    @include mark-keyframes_;
  }

  .mdc-checkbox {
    @include feature-targeting.targets($feat-structure) {
      @include base_;
    }

    @include ripple-theme.focus {
      .mdc-checkbox__focus-ring {
        @include focus-ring.focus-ring(
          $query: $query,
          $container-outer-padding-vertical: 0,
          $container-outer-padding-horizontal: 0
        );
      }
    }

    // Turn off focus ring for IE when HCM is turn off. For some reason this
    // adds space to the bottom on the focused checkbox inside a dialog.
    @media all and (-ms-high-contrast: none) {
      .mdc-checkbox__focus-ring {
        display: none;
      }
    }
  }

  @include dom.forced-colors-mode {
    .mdc-checkbox__mixedmark {
      @include feature-targeting.targets($feat-structure) {
        margin: 0 1px; // Extra horizontal space around mixedmark symbol.
      }
    }
  }

  // Needed to disable hover effects on CSS-only (non-JS) checkboxes
  .mdc-checkbox--disabled {
    @include feature-targeting.targets($feat-structure) {
      @include disabled_;
    }
  }

  .mdc-checkbox__background {
    @include background_($query);
  }

  .mdc-checkbox__checkmark {
    @include checkmark_($query);
  }

  .mdc-checkbox__checkmark-path {
    @include checkmark-path_($query);
  }

  .mdc-checkbox__mixedmark {
    @include mixedmark_($query);
  }

  .mdc-checkbox--anim {
    @include feature-targeting.targets($feat-animation) {
      @include anim_;
    }
  }

  .mdc-checkbox__native-control:checked ~ .mdc-checkbox__background,
  .mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background,
  .mdc-checkbox__native-control[data-indeterminate='true']
    ~ .mdc-checkbox__background {
    @include feature-targeting.targets($feat-animation) {
      @include background--marked_;
    }

    .mdc-checkbox__checkmark-path {
      @include feature-targeting.targets($feat-structure) {
        @include checkmark-path--marked_;
      }
    }
  }

  .mdc-checkbox__native-control {
    @include feature-targeting.targets($feat-structure) {
      @include native-control_;
    }

    &:disabled {
      @include feature-targeting.targets($feat-structure) {
        @include disabled_;
      }
    }
  }

  .mdc-checkbox--touch {
    @include checkbox-theme.touch-target(
      custom-properties.create(
        checkbox-state-layer-size,
        touch-target-variables.$height
      ),
      custom-properties.create(
        checkbox-state-layer-size,
        checkbox-theme.$ripple-size
      ),
      $query: $query
    );
  }

  .mdc-checkbox__native-control:checked ~ .mdc-checkbox__background {
    .mdc-checkbox__checkmark {
      @include checkmark--checked_($query);
    }

    .mdc-checkbox__mixedmark {
      @include feature-targeting.targets($feat-structure) {
        @include mixedmark--checked_;
      }
    }
  }
  .mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background,
  .mdc-checkbox__native-control[data-indeterminate='true']
    ~ .mdc-checkbox__background {
    .mdc-checkbox__checkmark {
      @include checkmark--indeterminate_($query);
    }

    .mdc-checkbox__mixedmark {
      @include feature-targeting.targets($feat-structure) {
        @include mixedmark--indeterminate_;
      }
    }
  }

  // JS checkbox
  .mdc-checkbox.mdc-checkbox--upgraded {
    .mdc-checkbox__background,
    .mdc-checkbox__checkmark,
    .mdc-checkbox__checkmark-path,
    .mdc-checkbox__mixedmark {
      @include feature-targeting.targets($feat-animation) {
        @include child--upgraded_;
      }
    }
  }
}

/// Checkbox theme styles.
/// Checkbox styles that are customizable should go here.
@mixin theme-styles($query: feature-targeting.all()) {
  .mdc-checkbox {
    @include checkbox-theme.theme-deprecated(
      checkbox-theme.$light-theme-deprecated,
      $query: $query
    );
  }
}

/// Checkbox's ripple styles.
///
/// NOTE: This API is intended for use by frameworks that may want to separate the ripple-related styles from the other
/// checkbox styles. It is recommended that most users use `mdc-checkbox-core-styles` instead.
@mixin ripple-styles($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include ripple.common($query); // COPYBARA_COMMENT_THIS_LINE

  .mdc-checkbox {
    @include ripple.surface(
      $query: $query,
      $ripple-target: checkbox-theme.$ripple-target
    );
    @include ripple.radius-unbounded(
      $query: $query,
      $ripple-target: checkbox-theme.$ripple-target
    );
    @include ripple-theme.behind-content(
      checkbox-theme.$ripple-target,
      $query: $query
    );
  }

  #{checkbox-theme.$ripple-target} {
    @include ripple.target-common($query: $query);
  }
}

@mixin base_ {
  display: inline-block;
  position: relative;
  flex: 0 0 checkbox-theme.$icon-size;
  box-sizing: content-box;
  width: checkbox-theme.$icon-size;
  height: checkbox-theme.$icon-size;
  line-height: 0;
  white-space: nowrap;
  cursor: pointer;
  vertical-align: bottom;
}

@mixin disabled_ {
  cursor: default;
  pointer-events: none;
}

@mixin child--upgraded_ {
  transition: none;
}

// Animation

@mixin anim_ {
  $mdc-checkbox-indeterminate-change-duration_: 500ms;

  // stylelint-disable no-unknown-animations -- allow unknown animations

  &-unchecked-checked,
  &-unchecked-indeterminate,
  &-checked-unchecked,
  &-indeterminate-unchecked {
    .mdc-checkbox__background {
      animation-duration: checkbox-theme.$transition-duration * 2;
      animation-timing-function: linear;
    }
  }

  &-unchecked-checked {
    .mdc-checkbox__checkmark-path {
      // Instead of delaying the animation, we simply multiply its length by 2 and begin the
      // animation at 50% in order to prevent a flash of styles applied to a checked checkmark
      // as the background is fading in before the animation begins.
      animation: mdc-checkbox-unchecked-checked-checkmark-path
        checkbox-theme.$transition-duration * 2 linear 0s;
      transition: none;
    }
  }

  &-unchecked-indeterminate {
    .mdc-checkbox__mixedmark {
      animation: mdc-checkbox-unchecked-indeterminate-mixedmark
        checkbox-theme.$transition-duration linear 0s;
      transition: none;
    }
  }

  &-checked-unchecked {
    .mdc-checkbox__checkmark-path {
      animation: mdc-checkbox-checked-unchecked-checkmark-path
        checkbox-theme.$transition-duration linear 0s;
      transition: none;
    }
  }

  &-checked-indeterminate {
    .mdc-checkbox__checkmark {
      animation: mdc-checkbox-checked-indeterminate-checkmark
        checkbox-theme.$transition-duration linear 0s;
      transition: none;
    }

    .mdc-checkbox__mixedmark {
      animation: mdc-checkbox-checked-indeterminate-mixedmark
        checkbox-theme.$transition-duration linear 0s;
      transition: none;
    }
  }

  &-indeterminate-checked {
    .mdc-checkbox__checkmark {
      animation: mdc-checkbox-indeterminate-checked-checkmark
        $mdc-checkbox-indeterminate-change-duration_ linear 0s;
      transition: none;
    }

    .mdc-checkbox__mixedmark {
      animation: mdc-checkbox-indeterminate-checked-mixedmark
        $mdc-checkbox-indeterminate-change-duration_ linear 0s;
      transition: none;
    }
  }

  &-indeterminate-unchecked {
    .mdc-checkbox__mixedmark {
      animation: mdc-checkbox-indeterminate-unchecked-mixedmark
        $mdc-checkbox-indeterminate-change-duration_ * 0.6 linear 0s;
      transition: none;
    }
  }

  // stylelint-enable no-unknown-animations
}

@mixin background_($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);
  $feat-color: feature-targeting.create-target($query, color);

  @include feature-targeting.targets($feat-structure) {
    display: inline-flex;
    position: absolute;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: checkbox-theme.$icon-size;
    height: checkbox-theme.$icon-size;
    // border-color is overridden by the mdc-checkbox-unmarked-stroke-color() mixin
    border: checkbox-theme.$border-width solid currentColor;
    border-radius: 2px;
    background-color: transparent;
    pointer-events: none;
    will-change: background-color, border-color;
  }

  @include feature-targeting.targets($feat-animation) {
    transition: transition-exit(background-color), transition-exit(border-color);
  }
}

@mixin background--marked_ {
  transition: transition-enter(border-color), transition-enter(background-color);
}

// stylelint-disable block-no-empty -- For backward compatibility.
@mixin focus-indicator_($query: feature-targeting.all()) {
}
@mixin focus-indicator--focused_($query: feature-targeting.all()) {
}
// stylelint-enable block-no-empty

// Native input

@mixin native-control_ {
  position: absolute;
  margin: 0;
  padding: 0;
  opacity: 0;
  cursor: inherit;
}

// Check mark

@mixin checkmark_($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    opacity: 0;
  }

  @include feature-targeting.targets($feat-animation) {
    transition: transition-exit(
      opacity,
      0ms,
      checkbox-theme.$transition-duration * 2
    );
  }

  .mdc-checkbox--upgraded & {
    @include feature-targeting.targets($feat-structure) {
      opacity: 1;
    }
  }
}

@mixin checkmark--checked_($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-animation) {
    transition: transition-enter(
        opacity,
        0ms,
        checkbox-theme.$transition-duration * 2
      ),
      transition-enter(transform, 0ms, checkbox-theme.$transition-duration * 2);
  }

  @include feature-targeting.targets($feat-structure) {
    opacity: 1;
  }
}

@mixin checkmark--indeterminate_($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    transform: rotate(45deg);
    opacity: 0;
  }

  @include feature-targeting.targets($feat-animation) {
    transition: transition-exit(
        opacity,
        0ms,
        checkbox-theme.$transition-duration
      ),
      transition-exit(transform, 0ms, checkbox-theme.$transition-duration);
  }
}

// Check mark path

@mixin checkmark-path_($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-animation) {
    transition: transition-exit(
      stroke-dashoffset,
      0ms,
      checkbox-theme.$transition-duration * 2
    );
  }

  @include feature-targeting.targets($feat-structure) {
    stroke: currentColor;
    stroke-width: checkbox-theme.$mark-stroke-size * 1.3;
    stroke-dashoffset: $mark-path-length_;
    stroke-dasharray: $mark-path-length_;
  }
}

@mixin checkmark-path--marked_ {
  stroke-dashoffset: 0;
}

// Mixed mark

@mixin mixedmark_($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    width: 100%;
    height: 0;
    transform: scaleX(0) rotate(0deg);
    border-width: math.div(math.floor(checkbox-theme.$mark-stroke-size), 2);
    border-style: solid;
    opacity: 0;
  }

  @include feature-targeting.targets($feat-animation) {
    transition: transition-exit(opacity), transition-exit(transform);
  }
}

@mixin mixedmark--checked_ {
  transform: scaleX(1) rotate(-45deg);
}

@mixin mixedmark--indeterminate_ {
  transform: scaleX(1) rotate(0deg);
  opacity: 1;
}

@function transition-enter(
  $property,
  $delay: 0ms,
  $duration: checkbox-theme.$transition-duration
) {
  @return functions2.enter($property, $duration, $delay);
}

@function transition-exit(
  $property,
  $delay: 0ms,
  $duration: checkbox-theme.$transition-duration
) {
  @return functions2.exit-temporary($property, $duration, $delay);
}

// Manual calculation done on SVG
$mark-path-length_: 29.7833385 !default;
$indeterminate-checked-easing-function_: cubic-bezier(0.14, 0, 0, 1) !default;

@mixin mark-keyframes_ {
  @keyframes mdc-checkbox-unchecked-checked-checkmark-path {
    0%,
    50% {
      stroke-dashoffset: $mark-path-length_;
    }

    50% {
      animation-timing-function: animation-variables.$deceleration-curve-timing-function;
    }

    100% {
      stroke-dashoffset: 0;
    }
  }

  @keyframes mdc-checkbox-unchecked-indeterminate-mixedmark {
    0%,
    68.2% {
      transform: scaleX(0);
    }

    68.2% {
      animation-timing-function: cubic-bezier(0, 0, 0, 1);
    }

    100% {
      transform: scaleX(1);
    }
  }

  @keyframes mdc-checkbox-checked-unchecked-checkmark-path {
    from {
      animation-timing-function: animation-variables.$acceleration-curve-timing-function;
      opacity: 1;
      stroke-dashoffset: 0;
    }

    to {
      opacity: 0;
      stroke-dashoffset: $mark-path-length_ * -1;
    }
  }

  @keyframes mdc-checkbox-checked-indeterminate-checkmark {
    from {
      animation-timing-function: animation-variables.$deceleration-curve-timing-function;
      transform: rotate(0deg);
      opacity: 1;
    }

    to {
      transform: rotate(45deg);
      opacity: 0;
    }
  }

  @keyframes mdc-checkbox-indeterminate-checked-checkmark {
    from {
      animation-timing-function: $indeterminate-checked-easing-function_;
      transform: rotate(45deg);
      opacity: 0;
    }

    to {
      transform: rotate(360deg);
      opacity: 1;
    }
  }

  @keyframes mdc-checkbox-checked-indeterminate-mixedmark {
    from {
      animation-timing-function: mdc-animation-deceleration-curve-timing-function;
      transform: rotate(-45deg);
      opacity: 0;
    }

    to {
      transform: rotate(0deg);
      opacity: 1;
    }
  }

  @keyframes mdc-checkbox-indeterminate-checked-mixedmark {
    from {
      animation-timing-function: $indeterminate-checked-easing-function_;
      transform: rotate(0deg);
      opacity: 1;
    }

    to {
      transform: rotate(315deg);
      opacity: 0;
    }
  }

  @keyframes mdc-checkbox-indeterminate-unchecked-mixedmark {
    0% {
      animation-timing-function: linear;
      transform: scaleX(1);
      opacity: 1;
    }

    32.8%,
    100% {
      transform: scaleX(0);
      opacity: 0;
    }
  }
}
