////
/// @group controls.toggles
////

@use '../utils' as *;
@use '../site' as *;
@use './base.scss' as *;
@use './button.scss' as *;
@use './helpers.scss' as *;

/*

    Many toggles use the same basic approach. The expected markup looks like this:

    <div class="outeclass">
        <input type="checkbox || radio" id="abc" />
        <label for="abc">Is checked?</label>
    </div>

    The  outer class contains a label and an input. Use the input to manage checked state but hide
    it. The label becomes the interactive element and we use the before/after pseudo elements to
    create the check element.

*/

@mixin toggle-base($config) {
    @include css-map(
        flat-merge(
            control-base(),
            (
                cursor: pointer,
            )
        )
    );

    $toggle-width: flat-get($config, 'toggle-width');
    $toggle-height: flat-get($config, 'toggle-height');
    $toggle-spacing: flat-get($config, 'toggle-spacing');
    $toggle-side: flat-get($config, 'toggle-side');

    // hide inputs
    input {
        position: absolute;
        appearance: none;
        opacity: 0;
        width: 0;
        height: 0;
        transform: scale(0);
    }

    label {
        user-select: none;
        position: relative;
        align-items: inherit;
        display: inherit;
        font-size: inherit;
        cursor: inherit;
        position: relative;
        min-height: $toggle-height;
        font-size: inherit;
        font-weight: inherit;
        font-family: inherit;
        color: inherit;

        @if ($toggle-side == left) {
            padding-left: $toggle-width + $toggle-spacing;
        } @else {
            padding-right: $toggle-width + $toggle-spacing;
        }

        &:before,
        &:after {
            @if ($toggle-side == left) {
                left: 0;
            } @else {
                right: 0;
            }

            content: '';
            display: block;
            background-color: transparent;
            background-size: contain;
            background-repeat: no-repeat;
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            width: $toggle-width;
            height: $toggle-height;
            @include transition(opacity);
        }
    }

    // add focus selector
    $focus-selector: get('focus-selector');
    input[type='radio']#{$focus-selector} + label,
    input[type='checkbox']#{$focus-selector} + label {
        @include control-focus-style(flat-get($config, '-px-focus-style'));
        border-radius: flat-get($config, '-px-radius');
    }
}

@mixin toggle-base-icons($config) {
    $toggle-background: flat-get($config, 'toggle-background');
    $toggle-background-hover: flat-get($config, 'toggle-background-hover');
    $toggle-check: flat-get($config, 'toggle-check');
    $toggle-indeterminate: flat-get($config, 'toggle-indeterminate');

    label {
        &:before {
            opacity: 1;
            @if ($toggle-background) {
                background-image: $toggle-background;
            }
        }

        &:after {
            opacity: 0;
            @if ($toggle-check) {
                background-image: $toggle-check;
            }
        }
    }

    input:checked + label {
        &:after {
            opacity: 1;
        }
    }

    @if ($toggle-indeterminate) {
        input[type='checkbox']:indeterminate + label {
            &:after {
                opacity: 1;
                background-image: $toggle-indeterminate;
            }
        }
    }

    @if ($toggle-background-hover) {
        &:hover {
            label:before {
                background-image: $toggle-background-hover;
            }
        }
    }
}

@mixin checkbox($overrides: ()) {
    $config: flat-merge(control-base(), get('controls:checkbox'), $overrides);
    @include toggle-base($config);
    @include toggle-base-icons($config);
}

@mixin radio($overrides: ()) {
    $config: flat-merge(control-base(), get('controls:radio'), $overrides);
    @include toggle-base($config);
    @include toggle-base-icons($config);
}

@mixin toggle($overrides: ()) {
    $config: flat-merge(control-base(), get('controls:toggle'), $overrides);
    $toggle-width: flat-get($config, 'toggle-width');
    $toggle-height: flat-get($config, 'toggle-height');
    $indicator-gap: flat-get($config, 'indicator-gap');
    $indicator-width: $toggle-height - ($indicator-gap * 2);
    $indicator-height: $indicator-width * flat-get($config, 'indicator-aspect');
    $toggle-right: flat-get($config, 'toggle-side') == 'right';

    @include toggle-base($config);

    label {
        // stretch within the outer div (helpful for right aligned toggles)
        width: 100%;

        &:before,
        &:after {
            @include transition(
                (right left background),
                $name: flat-get($config, '-px-transition')
            );
        }

        // toggle well
        &:before {
            width: $toggle-width;
            height: $toggle-height;
            border-radius: $toggle-height * 0.5;
            box-shadow: flat-get($config, 'toggle-shadow');
            background-color: flat-get($config, 'toggle-off-background');
        }

        // toggle indicator
        &:after {
            width: $indicator-width;
            height: $indicator-height;
            border-radius: $indicator-height * 0.5;
            box-shadow: flat-get($config, 'indicator-shadow');
            background-color: flat-get($config, 'indicator-off-background');
            @if ($toggle-right) {
                right: $toggle-width - ($indicator-gap + $indicator-width);
            } @else {
                left: $indicator-gap;
            }
        }
    }

    input[type='radio']:checked + label,
    input[type='checkbox']:checked + label {
        &:before {
            background-color: flat-get($config, 'toggle-on-background');
        }
        &:after {
            background-color: flat-get($config, 'indicator-on-background');
            @if ($toggle-right) {
                right: $indicator-gap;
            } @else {
                left: $toggle-width - ($indicator-gap + $indicator-width);
            }
        }
    }

    &:hover {
        label:before {
            background-color: flat-get($config, 'toggle-off-background-hover');
        }
        input[type='radio']:checked + label,
        input[type='checkbox']:checked + label {
            &:before {
                background-color: flat-get($config, 'toggle-on-background-hover');
            }
        }
    }

    &:active {
        label:before {
            background-color: flat-get($config, 'toggle-off-background-active');
        }
        input[type='radio']:checked + label,
        input[type='checkbox']:checked + label {
            &:before {
                background-color: flat-get($config, 'toggle-on-background-active');
            }
        }
    }
    // disabled
    input:disabled + label {
        cursor: not-allowed;
        &:before,
        &:after {
            opacity: 0.66;
        }
        color: gray(-2);
    }
}

@mixin toggle-button($overrides: ()) {
    $defaults: get('controls:toggle-button');

    $config: flat-merge(control-base(), $defaults, $overrides);
    @include toggle-base($config);

    // the label becomes the button element

    label {
        @include button($config);
    }

    // checked state

    input[type='radio']:checked + label,
    input[type='checkbox']:checked + label {
        $css-checked: flat-get($config, 'checked');
        @include css-map(
            $css-checked,
            (
                '-px-accent': 'background-color',
                '-px-radius': 'border-radius',
                '-px-shadow': 'box-shadow',
            ),
            $map-states: (hover active)
        );
    }

    // checked icon

    $icon: flat-get($config, '-px-icon');

    @if ($icon) {
        $icon-width: flat-get($config, '-px-icon-width');
        $icon-height: flat-get($config, '-px-icon-height');
        $icon-space: flat-get($config, '-px-icon-space');
        $padding: get-fourpart(flat-get($config, padding));
        $icon-offset: ($icon-width + $icon-space);

        label {
            padding-left: map-get($padding, left) - $icon-offset;
            padding-right: map-get($padding, right);
            @include transition(background-color color border box-shaow padding, $dur: 75ms);
            &:before {
                content: '';
                background-image: $icon;
                background-size: contain;
                background-position: center center;
                width: $icon-width;
                height: $icon-height;
                display: inline-block;
                position: relative;
                top: initial;
                transform: none;
                margin-right: $icon-space;
                opacity: 0;
                transition: none;
                @include transition(opacity, $dur: 50ms, $delay: 100ms);
            }
        }

        input[type='radio']:checked + label,
        input[type='checkbox']:checked + label {
            padding-left: map-get($padding, left) - ($icon-offset * 0.66);
            padding-right: map-get($padding, right) - ($icon-offset * 0.33);
            &:before {
                opacity: 1;
            }
        }
    }

    // connect
    $connect: flat-get($config, '-px-connect');

    @if ($connect) {
        &:not(:first-child) {
            input[type='radio']:checked + label,
            input[type='checkbox']:checked + label,
            label {
                border-top-left-radius: 0;
                border-bottom-left-radius: 0;
                border-left: none;
            }
        }

        &:not(:last-child) {
            input[type='radio']:checked + label,
            input[type='checkbox']:checked + label,
            label {
                border-top-right-radius: 0;
                border-bottom-right-radius: 0;
            }
        }

        &:hover,
        &:active {
            border-left: none;
        }
    }
}
