//
// Copyright 2021 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// [Modified by Sandlada & Kai Orion]
//
// Copyright 2025 Sandlada & Kai Orion
// SPDX-License-Identifier: MIT
//

@use 'sass:map';
@use '../../../themes';
@use '../../../tokens';

$_motion: tokens.md-sys-motion-values();
$_easing-standard: map.get($_motion, 'easing-standard');

@mixin styles() {
    $tokens: tokens.md-comp-switch-values();

    @layer switch-styles, switch-styles-hcm;

    @layer switch-styles {
        & {
            display: inline-flex;
            outline: none;
            vertical-align: top;
            -webkit-tap-highlight-color: transparent;
            cursor: pointer;
            align-items: center;
            flex-shrink: 0; // Stop from collapsing in flex containers
            position: relative;
            width: map.get($tokens, 'track-width');
            height: map.get($tokens, 'track-height');

            // Track shape
            border-start-start-radius: map.get($tokens, 'track-shape-start-start');
            border-start-end-radius: map.get($tokens, 'track-shape-start-end');
            border-end-end-radius: map.get($tokens, 'track-shape-end-end');
            border-end-start-radius: map.get($tokens, 'track-shape-end-start');
        }

        &.disabled {
            cursor: default;
        }

        &[touch-target='wrapper'] {
            margin: max(0px, (48px - map.get($tokens, 'track-height')) / 2) 0px;
        }

        & [data-component='focus-ring'] {
            @include themes.md-comp-focus-ring-theme(
                (
                    'shape-start-start': map.get($tokens, 'track-shape-start-start'),
                    'shape-start-end': map.get($tokens, 'track-shape-start-end'),
                    'shape-end-end': map.get($tokens, 'track-shape-end-end'),
                    'shape-end-start': map.get($tokens, 'track-shape-end-start'),
                )
            );
        }

        // Input is also touch target
        & input {
            appearance: none;
            height: max(100%, map.get($tokens, 'touch-target-size'));
            width: max(100%, map.get($tokens, 'touch-target-size'));
            outline: none;
            margin: 0;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 1;
            cursor: inherit;
        }

        &[touch-target='none'] input {
            display: none;
        }
    }

    @include _track-styles($tokens);
    @include _handle-styles($tokens);
    @include _icon-styles($tokens);
}

@mixin _icon-styles($tokens) {
    @layer switch-icon-styles {
        & .icons {
            position: relative;
            height: 100%;
            width: 100%;
        }

        & .icon {
            position: absolute;
            inset: 0;
            margin: auto;
            display: flex;
            align-items: center;
            justify-content: center;
            fill: currentColor;

            transition: fill 67ms linear, opacity 33ms linear, transform 167ms $_easing-standard;
            opacity: 0;
        }

        &.disabled .icon {
            transition: none;
        }

        &.selected .icon--on,
        &.unselected .icon--off {
            opacity: 1;
        }

        // rotate selected icon into view when there is no unselected icon
        &.unselected .handle:not(.with-icon) .icon--on {
            transform: rotate(-45deg);
        }

        & .icon--off {
            width: map.get($tokens, 'icon-size');
            height: map.get($tokens, 'icon-size');
            color: map.get($tokens, 'icon-color');
        }

        & .unselected:hover .icon--off {
            color: map.get($tokens, 'hover-icon-color');
        }

        &.unselected:focus-within .icon--off {
            color: map.get($tokens, 'focus-icon-color');
        }

        &.unselected:active .icon--off {
            color: map.get($tokens, 'pressed-icon-color');
        }

        &.unselected.disabled .icon--off {
            color: map.get($tokens, 'disabled-icon-color');
            opacity: map.get($tokens, 'disabled-icon-opacity');
        }

        & .icon--on {
            width: map.get($tokens, 'selected-icon-size');
            height: map.get($tokens, 'selected-icon-size');
            color: map.get($tokens, 'selected-icon-color');
        }

        &.selected:hover .icon--on {
            color: map.get($tokens, 'selected-hover-icon-color');
        }

        &.selected:focus-within .icon--on {
            color: map.get($tokens, 'selected-focus-icon-color');
        }

        &.selected:active .icon--on {
            color: map.get($tokens, 'selected-pressed-icon-color');
        }

        &.selected.disabled .icon--on {
            color: map.get($tokens, 'disabled-selected-icon-color');
            opacity: map.get($tokens, 'disabled-selected-icon-opacity');
        }
    }

    @layer switch-icon-hcm {
        @media (forced-colors: active) {
            & .icon--off {
                fill: Canvas;
            }

            & .icon--on {
                fill: ButtonText;
            }

            &.disabled.unselected .icon--off,
            &.disabled.selected .icon--on {
                opacity: 1;
            }

            &.disabled .icon--on {
                fill: GrayText;
            }
        }
    }
}

@mixin _handle-styles($tokens) {
    @layer switch-handle-styles {
        & .handle-container {
            display: flex;
            place-content: center;
            place-items: center;
            position: relative;
            // this easing is custom to perform the "overshoot" animation
            transition: margin 300ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
        }

        $margin: calc(map.get($tokens, 'track-width') - map.get($tokens, 'track-height'));

        &.selected .handle-container {
            margin-inline-start: $margin !important;
        }

        &.unselected .handle-container {
            margin-inline-end: $margin !important;
        }

        &.disabled .handle-container {
            transition: none;
        }

        & .handle {
            // Handle shape
            border-start-start-radius: map.get($tokens, 'handle-shape-start-start');
            border-start-end-radius: map.get($tokens, 'handle-shape-start-end');
            border-end-end-radius: map.get($tokens, 'handle-shape-end-end');
            border-end-start-radius: map.get($tokens, 'handle-shape-end-start');
            height: map.get($tokens, 'handle-height');
            width: map.get($tokens, 'handle-width');

            transform-origin: center;
            transition-property: height, width;
            transition-duration: 250ms, 250ms;
            transition-timing-function: $_easing-standard, $_easing-standard;
            z-index: 0;
        }

        & .handle::before {
            content: '';
            display: flex;
            inset: 0;
            position: absolute;
            border-radius: inherit;
            box-sizing: border-box;
            transition: background-color 67ms linear;
        }

        &.disabled .handle,
        &.disabled .handle::before {
            transition: none;
        }

        &.selected .handle {
            height: map.get($tokens, 'selected-handle-height');
            width: map.get($tokens, 'selected-handle-width');
        }

        & .handle.with-icon {
            height: map.get($tokens, 'with-icon-handle-height');
            width: map.get($tokens, 'with-icon-handle-width');
        }

        &.selected:not(.disabled):active .handle,
        &.unselected:not(.disabled):active .handle {
            height: map.get($tokens, 'pressed-handle-height');
            width: map.get($tokens, 'pressed-handle-width');
            transition-timing-function: linear;
            transition-duration: 100ms;
        }

        &.selected .handle::before {
            background-color: map.get($tokens, 'selected-handle-color');
        }

        &.selected:hover .handle::before {
            background-color: map.get($tokens, 'selected-hover-handle-color');
        }

        &.selected:focus-within .handle::before {
            background-color: map.get($tokens, 'selected-focus-handle-color');
        }

        &.selected:active .handle::before {
            background-color: map.get($tokens, 'selected-pressed-handle-color');
        }

        &.selected.disabled .handle::before {
            background-color: map.get($tokens, 'disabled-selected-handle-color');
            opacity: map.get($tokens, 'disabled-selected-handle-opacity');
        }

        &.unselected .handle::before {
            background-color: map.get($tokens, 'handle-color');
        }

        &.unselected:hover .handle::before {
            background-color: map.get($tokens, 'hover-handle-color');
        }

        &.unselected:focus-within .handle::before {
            background-color: map.get($tokens, 'focus-handle-color');
        }

        &.unselected:active .handle::before {
            background-color: map.get($tokens, 'pressed-handle-color');
        }

        &.unselected.disabled .handle::before {
            background-color: map.get($tokens, 'disabled-handle-color');
            opacity: map.get($tokens, 'disabled-handle-opacity');
        }

        & [data-component='ripple'] {
            border-radius: map.get($tokens, 'state-layer-shape') !important;
            height: map.get($tokens, 'state-layer-size');
            inset: unset !important;
            width: map.get($tokens, 'state-layer-size');
        }

        &.selected [data-component='ripple'] {
            @include themes.md-comp-ripple-theme(
                (
                    'hover-color': map.get($tokens, 'selected-hover-state-layer-color'),
                    'pressed-color': map.get($tokens, 'selected-pressed-state-layer-color'),
                    'hover-opacity': map.get($tokens, 'selected-hover-state-layer-opacity'),
                    'pressed-opacity': map.get($tokens, 'selected-pressed-state-layer-opacity'),
                )
            );
        }

        &.unselected [data-component='ripple'] {
            @include themes.md-comp-ripple-theme(
                (
                    'hover-color': map.get($tokens, 'hover-state-layer-color'),
                    'pressed-color': map.get($tokens, 'pressed-state-layer-color'),
                    'hover-opacity': map.get($tokens, 'hover-state-layer-opacity'),
                    'pressed-opacity': map.get($tokens, 'pressed-state-layer-opacity'),
                )
            );
        }
    }

    @layer switch-handle-hcm {
        @media (forced-colors: active) {
            &.unselected .handle::before {
                background: ButtonText;
            }

            &.disabled .handle::before {
                opacity: 1;
            }

            &.disabled.unselected .handle::before {
                background: GrayText;
            }
        }
    }
}

@mixin _track-styles($tokens) {
    @layer switch-track-styles {
        & .track {
            position: absolute;
            width: 100%;
            height: 100%;
            box-sizing: border-box;
            border-radius: inherit;
            // Center content
            display: flex;
            justify-content: center;
            align-items: center;
        }

        &.selected.disabled .track {
            background-clip: border-box;
        }

        // Separate node for background/outline colors to support opacity changes.
        & .background,
        & .outline {
            display: flex;
            position: absolute;
            height: 100%;
            width: 100%;
            border-radius: inherit;
            box-sizing: border-box;
            transition-property: opacity, background-color;
            transition-timing-function: linear;
            transition-duration: 67ms;
        }

        &.disabled .background,
        &.disabled .outline {
            background-color: transparent;
            border-color: transparent;
        }

        &.disabled .background,
        &.disabled .outline {
            transition: none;
            opacity: map.get($tokens, 'disabled-track-opacity');
        }

        &.disabled .background,
        &.disabled .outline {
            background-clip: content-box;
        }

        &.selected .background {
            background-color: map.get($tokens, 'selected-track-color');
        }

        &.selected:hover .background {
            background-color: map.get($tokens, 'selected-hover-track-color');
        }

        &.selected:focus-within .background {
            background-color: map.get($tokens, 'selected-focus-track-color');
        }

        &.selected:active .background {
            background-color: map.get($tokens, 'selected-pressed-track-color');
        }

        &.selected.disabled .background {
            background-color: map.get($tokens, 'disabled-selected-track-color');
        }

        &.unselected .background {
            background-color: map.get($tokens, 'track-color');
        }

        &.unselected .outline {
            border-color: map.get($tokens, 'track-outline-color');
            border-style: solid;
            border-width: map.get($tokens, 'track-outline-width');
        }

        &.unselected:hover .background {
            background-color: map.get($tokens, 'hover-track-color');
        }

        &.unselected:hover .outline {
            border-color: map.get($tokens, 'hover-track-outline-color');
        }

        &.unselected:focus-visible .background {
            background-color: map.get($tokens, 'focus-track-color');
        }

        &.unselected:focus-visible .outline {
            border-color: map.get($tokens, 'focus-track-outline-color');
        }

        &.unselected:active .background {
            background-color: map.get($tokens, 'pressed-track-color');
        }

        &.unselected:active .outline {
            border-color: map.get($tokens, 'pressed-track-outline-color');
        }

        &.unselected.disabled .background {
            background-color: map.get($tokens, 'disabled-track-color');
        }

        &.unselected.disabled .outline {
            border-color: map.get($tokens, 'disabled-track-outline-color');
        }
    }

    @layer switch-track-hcm {
        @media (forced-colors: active) {
            &.selected .background {
                background: ButtonText;
            }

            &.selected .outline {
                border-color: ButtonText;
            }

            &.disabled .outline {
                border-color: GrayText;
            }

            &.disabled .background,
            &.disabled .outline {
                opacity: 1;
            }

            &.disabled.selected .background {
                background: GrayText;
            }
        }
    }
}
