////
/// @group utils.misc
////

@use 'collections.scss' as *;
@use 'flatmap.scss' as *;
@use 'strings.scss' as *;
@use 'units.scss' as *;

/// Completely resets the appearance of controls (input and button)
///@example control-reset // =>
///appearance: none;
/// border: none;
///outline: none;
/// -webkit-touch-callout: none;
/// user-select: none;

@mixin control-reset {
    appearance: none;
    border: none;
    outline: none;
    &:focus {
        border: none;
        outline: none;
    }
}

/// Style the placeholder text for a text input element
/// @example
/// input {
///     @include placeholder {
///         /* styles for placeholder here */
///     }
/// }

@mixin placeholder {
    &::placeholder {
        @content;
    }
    &::-webkit-input-placeholder {
        @content;
    }
    &:-moz-placeholder {
        @content;
    }
    &::-moz-placeholder {
        @content;
    }
    &:-ms-input-placeholder {
        @content;
    }
}

/// Disable text selection on an element
///@example no-select // =>
@mixin no-select {
    -webkit-touch-callout: none;
    user-select: none;
}

/// Use the (now broadly supported) line-clamp property to restrict the
/// number of lines that are shown in a text element.
///
/// @param {number} $lines The maximum number of lines to be shown
///
///@example line-clamp(3) // =>
///display: -webkit-box;
///-webkit-line-clamp: 3;
///-webkit-box-orient: vertical;
///overflow: hidden;
@mixin line-clamp($lines) {
    display: -webkit-box;
    -webkit-line-clamp: $lines;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/// Shortcut for the ::before pseudo element with common defaults for content
/// and display.
///
/// @param {*} $content [''] The value for the content property.
/// @param {*} $display [block] The value for the display property.
///
///@example before('hello, world') // =>
///content: "";
///display: block;

@mixin before($content: '', $display: block) {
    &:before {
        content: '';
        display: block;
        @content;
    }
}

/// Shortcut for the ::after pseudo element with common defaults for content
/// and display.
///
/// @param {*} $content [''] The value for the content property.
/// @param {*} $display [block] The value for the display property.
///
///@example after('goodbye, world') // =>
///content: "";
///display: block;

@mixin after($content: '', $display: block) {
    &:after {
        content: '';
        display: block;
        @content;
    }
}

/// Create a triangle element using the border properties
///
/// @param {string} $direction The direction the arrow is pointing (up, down, left, right, etc.)
/// @param {color} $color The fill color for the arrow
/// @param {length} $height The height of the arrow
/// @param {length} $width  The width of the arrow
///
/// @example triangle('up', 'red', 10px, 2px) // =>
///border-style: solid;
/// height: 0;
/// width: 0;
/// border-color: transparent transparent "red" transparent;
/// border-width: 0 1px 10px 1px;

@mixin triangle($direction, $color, $height, $width) {
    border-style: solid;
    height: 0;
    width: 0;

    @if ($direction == 'up') {
        border-color: transparent transparent $color transparent;
        border-width: 0 ($width * 0.5) $height ($width * 0.5);
    }
    @if ($direction == 'down') {
        border-color: $color transparent transparent transparent;
        border-width: $height ($width * 0.5) 0 ($width * 0.5);
    }
    @if ($direction == 'right') {
        border-color: transparent transparent transparent $color;
        border-width: ($height * 0.5) 0 ($height * 0.5) $width;
    }
    @if ($direction == 'left') {
        border-color: transparent $color transparent transparent;
        border-width: ($height * 0.5) $width ($height * 0.5) 0;
    }
    @if ($direction == 'up-left') {
        border-color: $color transparent transparent transparent;
        border-width: $height $width 0 0;
    }
    @if ($direction == 'up-right') {
        border-color: transparent $color transparent transparent;
        border-width: 0 $width $height 0;
    }
    @if ($direction == 'down-left') {
        border-color: transparent transparent transparent $color;
        border-width: $height 0 0 $width;
    }
    @if ($direction == 'down-right') {
        border-color: transparent transparent $color transparent;
        border-width: 0 0 $height $width;
    }
}

/// Sets a generated checked pattern background svg image on an element
///
/// @param {*} $width [12px] The width of an individual square in the checked pattern
/// @param {*} $color [#c8c8c8] The first of two colors in the check pattern
/// @param {*} $color-alt [transparent] The second of two colors in the check pattern
///
/// @example @include checkered-background(20px, green) // => creates a green and transparent checkered background where each square is 20px x 20px

@mixin checkered-background($width: 12px, $color: rgba(black, 0.1), $color-alt: transparent) {
    background-size: #{$width * 2} #{$width * 2};
    background-repeat: repeat;
    background-image: inline-svg(
        '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="#{$color}" d="M0 0h10v10H0z"/><path fill="#{$color-alt}" d="M10 0h10v10H10zM0 10h10v10H0z"/><path fill="#{$color}" d="M10 10h10v10H10z"/></g></svg>'
    );
}

/// Finds and replaces keys in a map
///
/// @example
/// $map: map-key-replace(( oldkey: 'value'), (oldkey: newkey));

@function map-key-replace($map, $key-replacements) {
    $remap: ();
    @each $key, $val in $map {
        $prop: map-get-default($key-replacements, $key, $key);
        @if (not is-list($prop)) {
            $prop: ($prop);
        }
        @each $propname in $prop {
            $remap: map-merge(
                $remap,
                (
                    $propname: $val,
                )
            );
        }
    }

    @return $remap;
}

/// Generates css from a map of properties and values. Properties can be remapped with aliases or
/// ignored with a start pattern.
///
/// @param {map} $map The property map used to generate the css
/// @param {map} $aliases Property aliases map (e.g (-px-accent: background-color))
/// @param {list} $map-states If provided, the specified map-type properties will be interpreted as
/// sub states (e.g. (hover: (...)) becomes &:hover {...})
/// @param {string} $ignore-start-pattern Properties that start with this will be ignored
///
/// @example TODO - Robby, do we need an actual map for the test? Sarah is getting an error in scratch

@mixin css-map(
    $map,
    $aliases: (),
    $map-states: false,
    $use-smart-aliases: true,
    $ignore-start-pattern: '-'
) {
    @if ($use-smart-aliases) {
        $smart-aliases: (
            disabled: 'disabled, &:disabled:hover, &:disabled:active',
            readonly: 'read-only, &:read-only:hover, &:read-only:active',
            read-only: 'read-only, &:read-only:hover, &:read-only:active',
        );
        $aliases: flat-merge($smart-aliases, $aliases);
    }

    // walk through $map and replace any aliases with their counterparts
    $remap: map-key-replace($map, $aliases);

    // replace $map-states with their aliases
    $map-states: list-replace($map-states, $aliases);

    @each $key, $val in $remap {
        @if not((starts-with($key, $ignore-start-pattern))) {
            @if (is-map($val)) {
                @if (is-list($map-states) and list-contains($map-states, $key)) {
                    &:#{$key} {
                        @include css-map($val, $aliases, $ignore-start-pattern);
                    }
                }
            } @else if (is-list($val) and length($val) == 0) {
                // do nothing (empty maps look like empty lists in scss)
            } @else {
                #{$key}: $val;
            }
        }
    }
}

/// Generates a loud striped background gradient that can be used when debugging (especially helpful for scrolling)
///
/// @param {*} $color1 [yellowgreen] The first color in the gradient
/// @param {*} $color2 [gold] The second color in the gradient
/// @example debug-zebra() // =>
///background-image: repeating-linear-gradient(-45deg, yellowgreen 0 20px, gold 20px 40px);

@mixin debug-zebra($color1: yellowgreen, $color2: gold) {
    background-image: repeating-linear-gradient(-45deg, $color1 0 20px, $color2 20px 40px);
}
