/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
//
// Copyright 2021 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:color';
@use 'sass:map';
@use '@material/density/density';
@use '@material/dom/dom';
@use '@material/elevation/elevation-theme';
@use '@material/ripple/ripple-theme';
@use '@material/theme/color-palette';
@use '@material/theme/custom-properties';
@use '@material/theme/keys';
@use '@material/theme/shadow-dom';
@use '@material/theme/state';
@use '@material/theme/theme-color';
@use '@material/theme/theme';
@use '@material/tokens/resolvers';
@use '@material/shape/shape';
@use './switch-mixins' as switch; // FORGE(modify): importing from our local copy which mimics _switch.scss
@use '../theme/theme-values'; // FORGE(modify): using our tertiary theme

$_density-config: (
  size: (
    minimum: 28px,
    default: 48px,
    maximum: 48px,
  ),
);
$_hairline: color-palette.$grey-300;

// FORGE(modify): use tertiary color
$_inverse-primary: color.scale(
  theme-values.$tertiary,
  $lightness: 75%
);

$_on-surface: color-palette.$grey-800;
$_on-surface-dark: rgba(255, 255, 255, 0.38); // FORGE(modify): added for dark theme mixins below
$_on-surface-variant: color-palette.$grey-500; // FORGE(modify): use slighter lighter shade
$_on-surface-state-content: color-palette.$grey-900;
// FORGE(modify): use tertiary color
$_primary-state-content: color.scale(
  theme-values.$tertiary,
  $blackness: 50%
);

// FORGE(modify): added for dark theme mixin below
$_inverse-secondary: color.scale(theme-values.$secondary, $lightness: 75%);
$_secondary-state-content: color.scale(theme-values.$secondary, $blackness: 25%);

$_selectors: (
  disabled: ':disabled',
  focus: ':focus',
  hover: ':hover',
  pressed: ':active',
  selected: '.mdc-switch--selected',
  unselected: '.mdc-switch--unselected',
);

$light-theme: (
  disabled-handle-elevation: 0,
  disabled-handle-opacity: 0.24, // FORGE(modify): increase default opacity
  disabled-selected-handle-color: theme-values.$tertiary, // FORGE(modify): use primary color for handle when disabled
  disabled-selected-icon-color: on-primary,
  disabled-selected-icon-opacity: 0.54,
  disabled-selected-track-color: theme-values.$tertiary, // FORGE(modify): use primary color for track when disabled
  disabled-track-opacity: 0.12,
  disabled-unselected-handle-color: $_on-surface,
  disabled-unselected-icon-color: on-primary,
  disabled-unselected-icon-opacity: 0.54,
  disabled-unselected-track-color: $_on-surface,
  handle-elevation: 1,
  handle-height: 20px,
  handle-shadow-color: elevation-theme.$baseline-color,
  handle-shape: 10px,
  handle-surface-color: surface,
  handle-width: 20px,
  selected-focus-handle-color: $_primary-state-content,
  selected-focus-state-layer-color: theme-values.$tertiary, // FORGE(modify): use tertiary color
  selected-focus-state-layer-opacity: 0.12,
  selected-focus-track-color: $_inverse-primary,
  selected-handle-color: theme-values.$tertiary, // FORGE(modify): use tertiary color
  selected-hover-handle-color: $_primary-state-content,
  selected-hover-state-layer-color: theme-values.$tertiary, // FORGE(modify): use tertiary color
  selected-hover-state-layer-opacity: 0.04,
  selected-hover-track-color: $_inverse-primary,
  selected-icon-color: on-primary,
  selected-icon-size: 18px,
  selected-pressed-handle-color: $_primary-state-content,
  selected-pressed-state-layer-color: theme-values.$tertiary, // FORGE(modify): use tertiary color
  selected-pressed-state-layer-opacity: 0.1,
  selected-pressed-track-color: $_inverse-primary,
  selected-track-color: $_inverse-primary,
  state-layer-size: 48px,
  track-height: 14px,
  track-shape: 7px,
  track-width: 36px,
  unselected-focus-handle-color: $_on-surface-state-content,
  unselected-focus-state-layer-color: $_on-surface,
  unselected-focus-state-layer-opacity: 0.12,
  unselected-focus-track-color: $_hairline,
  unselected-handle-color: $_on-surface-variant,
  unselected-hover-handle-color: $_on-surface-state-content,
  unselected-hover-state-layer-color: $_on-surface,
  unselected-hover-state-layer-opacity: 0.04,
  unselected-hover-track-color: $_hairline,
  unselected-icon-color: on-primary,
  unselected-icon-size: 18px,
  unselected-pressed-handle-color: $_on-surface-state-content,
  unselected-pressed-state-layer-color: $_on-surface,
  unselected-pressed-state-layer-opacity: 0.1,
  unselected-pressed-track-color: $_hairline,
  unselected-track-color: $_hairline
);

$forced-colors-theme: (
  disabled-handle-opacity: 1,
  disabled-selected-icon-color: GrayText,
  disabled-selected-icon-opacity: 1,
  disabled-track-opacity: 1,
  disabled-unselected-icon-color: GrayText,
  disabled-unselected-icon-opacity: 1,
);

@function density($density-scale) {
  $size: density.prop-value(
    $density-config: $_density-config,
    $density-scale: $density-scale,
    $property-name: size,
  );

  @return (state-layer-size: $size);
}

@mixin theme($theme, $resolvers: resolvers.$material) {
  @include theme.validate-theme($light-theme, $theme);

  // TODO(b/185172301): replace with improved feature targeting
  // IE11 Fallback
  @if shadow-dom.$css-selector-fallback-declarations {
    @include custom-properties.configure($emit-custom-properties: false) {
      @include dom.ie11-support {
        @include theme-styles($theme, $resolvers: $resolvers);
      }
    }
  }

  @include keys.declare-custom-properties($theme, switch);
}

@mixin theme-styles($theme, $resolvers: resolvers.$material) {
  @include theme.validate-theme($light-theme, $theme);

  $theme: keys.create-theme-properties($theme, switch);

  @include _selected-handle-color(
    (
      default: map.get($theme, selected-handle-color),
      disabled: map.get($theme, disabled-selected-handle-color),
      focus: map.get($theme, selected-focus-handle-color),
      hover: map.get($theme, selected-hover-handle-color),
      pressed: map.get($theme, selected-pressed-handle-color),
    )
  );

  @include _unselected-handle-color(
    (
      default: map.get($theme, unselected-handle-color),
      disabled: map.get($theme, disabled-unselected-handle-color),
      focus: map.get($theme, unselected-focus-handle-color),
      hover: map.get($theme, unselected-hover-handle-color),
      pressed: map.get($theme, unselected-pressed-handle-color),
    )
  );

  @include _handle-surface-color(map.get($theme, handle-surface-color));

  @include _handle-elevation(
    map.get($resolvers, elevation),
    map.get($theme, handle-shadow-color),
    (
      default: map.get($theme, handle-elevation),
      disabled: map.get($theme, disabled-handle-elevation),
    )
  );

  @include _handle-height(map.get($theme, handle-height));
  @include _handle-opacity(
    (
      disabled: map.get($theme, disabled-handle-opacity),
    )
  );

  @include _handle-shape(map.get($theme, handle-shape));
  @include _handle-width(map.get($theme, handle-width));

  @include _selected-icon-color(
    (
      default: map.get($theme, selected-icon-color),
      disabled: map.get($theme, disabled-selected-icon-color),
    )
  );

  @include _unselected-icon-color(
    (
      default: map.get($theme, unselected-icon-color),
      disabled: map.get($theme, disabled-unselected-icon-color),
    )
  );

  @include _selected-icon-opacity(
    (
      disabled: map.get($theme, disabled-selected-icon-opacity),
    )
  );

  @include _unselected-icon-opacity(
    (
      disabled: map.get($theme, disabled-unselected-icon-opacity),
    )
  );

  @include _selected-icon-size(map.get($theme, selected-icon-size));
  @include _unselected-icon-size(map.get($theme, unselected-icon-size));

  @include _selected-ripple-color(
    (
      focus: map.get($theme, selected-focus-state-layer-color),
      hover: map.get($theme, selected-hover-state-layer-color),
      pressed: map.get($theme, selected-pressed-state-layer-color),
    )
  );

  @include _unselected-ripple-color(
    (
      focus: map.get($theme, unselected-focus-state-layer-color),
      hover: map.get($theme, unselected-hover-state-layer-color),
      pressed: map.get($theme, unselected-pressed-state-layer-color),
    )
  );

  @include _selected-ripple-opacity(
    (
      focus: map.get($theme, selected-focus-state-layer-opacity),
      hover: map.get($theme, selected-hover-state-layer-opacity),
      pressed: map.get($theme, selected-pressed-state-layer-opacity),
    )
  );

  @include _unselected-ripple-opacity(
    (
      focus: map.get($theme, unselected-focus-state-layer-opacity),
      hover: map.get($theme, unselected-hover-state-layer-opacity),
      pressed: map.get($theme, unselected-pressed-state-layer-opacity),
    )
  );

  @include _state-layer-size(map.get($theme, state-layer-size));
  @include _track-height(map.get($theme, track-height));
  @include _track-opacity(
    (
      disabled: map.get($theme, disabled-track-opacity),
    )
  );

  @include _track-selected-color(
    (
      default: map.get($theme, selected-track-color),
      disabled: map.get($theme, disabled-selected-track-color),
      focus: map.get($theme, selected-focus-track-color),
      hover: map.get($theme, selected-hover-track-color),
      pressed: map.get($theme, selected-pressed-track-color),
    )
  );

  @include _track-unselected-color(
    (
      default: map.get($theme, unselected-track-color),
      disabled: map.get($theme, disabled-unselected-track-color),
      focus: map.get($theme, unselected-focus-track-color),
      hover: map.get($theme, unselected-hover-track-color),
      pressed: map.get($theme, unselected-pressed-track-color),
    )
  );

  @include _track-shape(map.get($theme, track-shape));
  @include _track-width(map.get($theme, track-width));
}

@mixin _handle-color($colors) {
  @include state.default($_selectors) {
    @include _set-handle-color(state.get-default-state($colors));
  }

  @include state.hover($_selectors) {
    @include _set-handle-color(state.get-hover-state($colors));
  }

  @include state.focus($_selectors) {
    @include _set-handle-color(state.get-focus-state($colors));
  }

  @include state.pressed($_selectors) {
    @include _set-handle-color(state.get-pressed-state($colors));
  }

  @include state.disabled($_selectors) {
    @include _set-handle-color(state.get-disabled-state($colors));
  }
}

@mixin _set-handle-color($color) {
  .mdc-switch__handle {
    &::after {
      @include theme.property(background, $color);
    }
  }
}

@mixin _selected-handle-color($colors) {
  @include state.selected($_selectors) {
    @include _handle-color($colors);
  }
}

@mixin _unselected-handle-color($colors) {
  @include state.unselected($_selectors) {
    @include _handle-color($colors);
  }
}

@mixin _handle-surface-color($color) {
  .mdc-switch__handle {
    // Sets the surface color for the handle. This is used so that when an
    // opacity is applied to the "main" handle color, it will not bleed through
    // and appear transparent on top of the track.
    &::before {
      @include theme.property(background, $color);
    }
  }
}

@mixin _handle-elevation($resolver, $shadow-color, $elevations) {
  @include state.default($_selectors) {
    @include _set-handle-elevation(
      $resolver,
      $elevation: state.get-default-state($elevations),
      $shadow-color: $shadow-color
    );
  }

  @include state.disabled($_selectors) {
    @include _set-handle-elevation(
      $resolver,
      $elevation: state.get-disabled-state($elevations),
      $shadow-color: $shadow-color
    );
  }
}

@mixin _set-handle-elevation($resolver, $args...) {
  .mdc-switch__shadow {
    @include elevation-theme.with-resolver($resolver, $args...);
  }
}

@mixin _handle-height($height) {
  .mdc-switch__handle {
    @include theme.property(height, $height);
  }
}

@mixin _handle-opacity($opacities) {
  @include state.disabled($_selectors) {
    @include _set-handle-opacity(state.get-disabled-state($opacities));
  }
}

@mixin _set-handle-opacity($opacity) {
  .mdc-switch__handle {
    // Only apply to the ::after pseudo element, which is the handle's "main"
    // color. The ::before pseudo element is the surface color, which prevents
    // the handle from bleeding through on the track.
    &::after {
      @include theme.property(opacity, $opacity);
    }
  }
}

@mixin _handle-shape($shape) {
  .mdc-switch__handle {
    @include shape.radius($shape);
  }
}

@mixin _handle-width($width) {
  .mdc-switch__handle {
    @include theme.property(width, $width);
  }

  .mdc-switch__handle-track {
    @include theme.property(
      width,
      'calc(100% - width)',
      $replace: (width: $width)
    );
  }
}

@mixin _icon-color($colors) {
  @include state.default($_selectors) {
    @include _set-icon-color(state.get-default-state($colors));
  }

  @include state.disabled($_selectors) {
    @include _set-icon-color(state.get-disabled-state($colors));
  }
}

@mixin _set-icon-color($color) {
  .mdc-switch__icon {
    @include theme.property(fill, $color);
  }
}

@mixin _selected-icon-color($colors) {
  @include state.selected($_selectors) {
    @include _icon-color($colors);
  }
}

@mixin _unselected-icon-color($colors) {
  @include state.unselected($_selectors) {
    @include _icon-color($colors);
  }
}

@mixin _icon-opacity($opacities) {
  @include state.disabled($_selectors) {
    @include _set-icon-opacity(state.get-disabled-state($opacities));
  }
}

@mixin _set-icon-opacity($opacity) {
  .mdc-switch__icons {
    @include theme.property(opacity, $opacity);
  }
}

@mixin _selected-icon-opacity($opacities) {
  @include state.selected($_selectors) {
    @include _icon-opacity($opacities);
  }
}

@mixin _unselected-icon-opacity($opacities) {
  @include state.unselected($_selectors) {
    @include _icon-opacity($opacities);
  }
}

@mixin _icon-size($size) {
  .mdc-switch__icon {
    @include theme.property(width, $size);
    @include theme.property(height, $size);
  }
}

@mixin _selected-icon-size($size) {
  @include state.selected($_selectors) {
    @include _icon-size($size);
  }
}

@mixin _unselected-icon-size($size) {
  @include state.unselected($_selectors) {
    @include _icon-size($size);
  }
}

@mixin _ripple-color($colors) {
  @include state.independent-elements(pressed) {
    @include state.hover($_selectors) {
      @include ripple-theme.states-base-color(
        state.get-hover-state($colors),
        $ripple-target: switch.$ripple-target
      );
    }

    @include state.focus($_selectors) {
      @include ripple-theme.states-base-color(
        state.get-focus-state($colors),
        $ripple-target: switch.$ripple-target
      );
    }

    @include state.pressed($_selectors) {
      @include ripple-theme.states-base-color(
        state.get-pressed-state($colors),
        $ripple-target: switch.$ripple-target
      );
    }
  }
}

@mixin _selected-ripple-color($colors) {
  @include state.selected($_selectors) {
    @include _ripple-color($colors);
  }
}

@mixin _unselected-ripple-color($colors) {
  @include state.unselected($_selectors) {
    @include _ripple-color($colors);
  }
}

@mixin _ripple-opacity($opacities) {
  @include state.independent-elements(pressed) {
    @include state.hover($_selectors) {
      @include ripple-theme.states-hover-opacity(
        state.get-hover-state($opacities),
        $ripple-target: switch.$ripple-target
      );
    }

    @include state.focus($_selectors) {
      @include ripple-theme.states-focus-opacity(
        state.get-focus-state($opacities),
        $ripple-target: switch.$ripple-target
      );
    }

    @include state.pressed($_selectors) {
      @include ripple-theme.states-press-opacity(
        state.get-pressed-state($opacities),
        $ripple-target: switch.$ripple-target
      );
    }
  }
}

@mixin _selected-ripple-opacity($opacities) {
  @include state.selected($_selectors) {
    @include _ripple-opacity($opacities);
  }
}

@mixin _unselected-ripple-opacity($opacities) {
  @include state.unselected($_selectors) {
    @include _ripple-opacity($opacities);
  }
}

@mixin _state-layer-size($size) {
  .mdc-switch__ripple {
    @include theme.property(height, $size);
    @include theme.property(width, $size);
  }
}

@mixin _track-height($height) {
  .mdc-switch__track {
    @include theme.property(height, $height);
  }
}

@mixin _track-opacity($opacities) {
  @include state.disabled($_selectors) {
    @include _set-track-opacity(state.get-disabled-state($opacities));
  }
}

@mixin _set-track-opacity($opacity) {
  .mdc-switch__track {
    @include theme.property(opacity, $opacity);
  }
}

@mixin _track-selected-color($colors) {
  @include state.default($_selectors) {
    @include _set-track-selected-color(state.get-default-state($colors));
  }

  @include state.hover($_selectors) {
    @include _set-track-selected-color(state.get-hover-state($colors));
  }

  @include state.focus($_selectors) {
    @include _set-track-selected-color(state.get-focus-state($colors));
  }

  @include state.pressed($_selectors) {
    @include _set-track-selected-color(state.get-pressed-state($colors));
  }

  @include state.disabled($_selectors) {
    @include _set-track-selected-color(state.get-disabled-state($colors));
  }
}

@mixin _set-track-selected-color($color) {
  .mdc-switch__track::after {
    @include theme.property(background, $color);
  }
}

@mixin _track-unselected-color($colors) {
  @include state.default($_selectors) {
    @include _set-track-unselected-color(state.get-default-state($colors));
  }

  @include state.hover($_selectors) {
    @include _set-track-unselected-color(state.get-hover-state($colors));
  }

  @include state.focus($_selectors) {
    @include _set-track-unselected-color(state.get-focus-state($colors));
  }

  @include state.pressed($_selectors) {
    @include _set-track-unselected-color(state.get-pressed-state($colors));
  }

  @include state.disabled($_selectors) {
    @include _set-track-unselected-color(state.get-disabled-state($colors));
  }
}

@mixin _set-track-unselected-color($color) {
  .mdc-switch__track::before {
    @include theme.property(background, $color);
  }
}

@mixin _track-shape($shape) {
  .mdc-switch__track {
    @include shape.radius($shape);
  }
}

@mixin _track-width($width) {
  @include theme.property(width, $width);
}

// FORGE(new): added mixin for generating dark theme properties
@mixin dark-theme-properties() {
  --mdc-switch-selected-handle-color: #{theme-values.$secondary};
  --mdc-switch-selected-hover-handle-color: #{$_secondary-state-content};
  --mdc-switch-selected-focus-handle-color: #{$_secondary-state-content};
  --mdc-switch-selected-pressed-handle-color: #{$_secondary-state-content};
  --mdc-switch-selected-focus-state-layer-color: #{theme-values.$secondary};
  --mdc-switch-selected-hover-state-layer-color: #{theme-values.$secondary};
  --mdc-switch-selected-pressed-state-layer-color: #{theme-values.$secondary};
  --mdc-switch-selected-focus-track-color: #{$_inverse-secondary};
  --mdc-switch-selected-hover-track-color: #{$_inverse-secondary};
  --mdc-switch-selected-pressed-track-color: #{$_inverse-secondary};
  --mdc-switch-selected-track-color: #{$_inverse-secondary};
  --mdc-switch-unselected-hover-handle-color: rgba(255, 255, 255, 0.54);
  --mdc-switch-unselected-focus-handle-color: rgba(255, 255, 255, 0.87);
  --mdc-switch-unselected-pressed-handle-color: rgba(255, 255, 255, 0.54);
  --mdc-switch-unselected-focus-state-layer-color: rgba(255, 255, 255, 0.87);
  --mdc-switch-unselected-hover-state-layer-color: rgba(255, 255, 255, 0.87);
  --mdc-switch-unselected-pressed-state-layer-color: rgba(255, 255, 255, 0.87);
  --mdc-switch-disabled-handle-opacity: 0.54;
  --mdc-switch-disabled-selected-handle-color: #{$_inverse-secondary};
  --mdc-switch-disabled-selected-icon-opacity: 0.54;
  --mdc-switch-disabled-selected-track-color: #{$_inverse-secondary};
  --mdc-switch-disabled-track-opacity: 0.38;
  --mdc-switch-disabled-unselected-handle-color: #{$_on-surface-dark};
  --mdc-switch-disabled-unselected-icon-color: on-primary;
  --mdc-switch-disabled-unselected-icon-opacity: 0.54;
  --mdc-switch-disabled-unselected-track-color: #{$_on-surface-dark};
}
