<template>
    <div
        class="hy-select"
        :style="{ maxWidth: extend ? '' : 'max-content' }"
        :class="{ hideText: loading, icons: $slots.icon, invalidTextVisible: invalid && invalidText, transitionsEnabled }"
    >
        <select
            :class="[sizeParsed, variantParsed, { hideText: loading, invalid, isGhost, isGhostBg, isSolid }]"
            :disabled="disabled || loading"
            :value="modelValue"
            @change="$emit('update:modelValue', $event.target.value)"
            ref="select"
        >
            <slot />
            <slot name="options" />
        </select>

        <div class="icons">
            <span class="iconSlot" :class="[sizeParsed, { muted: disabled || loading }]" v-if="$slots.icon">
                <slot name="icon" />
            </span>

            <span class="chevron" :class="[sizeParsed, { muted: disabled || loading }]">
                <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 1000 1000" width="30" height="30">
                    <path
                        d="M102.406+249.281C80.8052+248.6+59.077+257.194+43.6875+274.688C16.3284+305.787+19.3688+353.203+50.4688+380.562L450.062+732.062C478.366+756.962+520.734+756.995+549.062+732.125L949.469+380.594C980.596+353.266+983.703+305.878+956.375+274.75C929.047+243.622+881.659+240.547+850.531+267.875L499.656+575.906L149.531+267.938C135.925+255.968+119.207+249.811+102.406+249.281Z"
                    />
                </svg>
            </span>
        </div>

        <p class="invalidText" ref="invalidText" v-show="invalid && invalidText" :class="{ muted: disabled || loading }">
            {{ invalidText }}
        </p>

        <transition name="hy-fade-transition">
            <HyLoader v-if="loading && progress == null" :width="25" :height="25" :line="3" />
        </transition>
        <transition name="hy-fade-transition">
            <HyProgressBar
                v-if="loading && isNaN(progress) == false && typeof progress == 'number'"
                :progress="progress"
                :width="progressWidth"
            />
        </transition>
    </div>
</template>

<script>
import HyLoader from "./Loader.vue";
import HyProgressBar from "./ProgressBar.vue";

import { getBorderRadius } from "../utils/getBorderRadius.js";

export default {
    name: "HySelect",
    props: {
        modelValue: null,
        loading: {
            type: Boolean,
            default: false,
        },
        progress: {
            type: Number,
            default: null,
        },
        progressWidth: {
            type: String,
            default: "min(calc(100% - 2 * var(--hy-element-padding)), 200px)",
        },
        disabled: {
            type: Boolean,
            default: false,
        },
        invalid: {
            type: Boolean,
            default: false,
        },
        invalidText: {
            type: String,
            default: null,
        },
        extend: {
            type: Boolean,
            default: true,
        },
        size: {
            type: String,
            default: null,
        },
        variant: {
            type: String,
            default: null,
        },
    },
    data() {
        return {
            borderRadius: "10",
            transitionsEnabled: false,
        };
    },
    computed: {
        sizeParsed() {
            let size = this.size ?? this.hy_defaults.size;
            let allowed = ["lg", "md", "sm"];

            if (allowed.includes(size)) return `size-${size}`;
            else return "size-lg";
        },

        variantParsed() {
            let allowed = [...this.hy_brand_theme.availableVariants, "secondary", "ghost", "ghost-bg"];
            allowed = allowed.filter((v) => v != "primary"); // Remove primary variant

            let variant = this.variant ?? this.hy_defaults.variant;

            if (allowed.includes(variant)) return variant;
            else return "secondary";
        },
        isGhostBg() {
            return this.variantParsed.startsWith("ghost-bg");
        },
        isGhost() {
            return this.variantParsed.startsWith("ghost") && this.variantParsed.startsWith("ghost-bg") == false;
        },
        isSolid() {
            return this.variantParsed.startsWith("ghost") == false && this.variantParsed.startsWith("ghost-bg") == false;
        },
        fontColor() {
            // Note: "ghost" and "ghost-bg" variants share the same variables => trim the "-bg" part
            return `var(--hy-variant-${this.variantParsed.replace("-bg", "")}-font-color)`;
        },
        backgroundColor() {
            return `var(--hy-variant-${this.variantParsed.replace("-bg", "")}-bg-color)`;
        },
        hoverColor() {
            return `var(--hy-variant-${this.variantParsed.replace("-bg", "")}-hover-color)`;
        },
        borderColor() {
            return `var(--hy-variant-${this.variantParsed.replace("-bg", "")}-border-color)`;
        },

        invalidTextHeight() {
            if (!this.invalidText) return "0px";
            return `${this.$refs.invalidText.offsetHeight}px`;
        },
        invalidTextLeftClipPath() {
            return `path("M 0 0 a ${this.borderRadius} ${this.borderRadius} 0 0 0 ${this.borderRadius} ${this.borderRadius} L 0 ${this.borderRadius}")`;
        },
        invalidTextRightClipPath() {
            return `path("M 0 ${this.borderRadius} a ${this.borderRadius} ${this.borderRadius} 0 0 0 ${this.borderRadius} -${this.borderRadius} L ${this.borderRadius} ${this.borderRadius}")`;
        },
    },
    mounted() {
        this.borderRadius = getBorderRadius();

        requestAnimationFrame(() => (this.transitionsEnabled = true));
    },
    components: {
        HyLoader,
        HyProgressBar,
    },
};
</script>

<style lang="scss">
.hy-select {
    margin: var(--hy-element-margin);
    position: relative;
    min-width: max-content;

    &.transitionsEnabled {
        select,
        .iconSlot,
        .chevron,
        .invalidText {
            transition: var(--hy-element-transition);
            transition-property: background-color, color, border, filter;
        }
    }

    select {
        -moz-appearance: none;
        -webkit-appearance: none;
        appearance: none;

        width: 100%;
        border-radius: var(--hy-element-border-radius);
        padding: var(--hy-element-padding);
        padding-right: 45px;
        font-size: var(--hy-font-size);
        font-family: var(--hy-font-family);
        cursor: pointer;

        &:disabled {
            cursor: not-allowed;
            filter: opacity(50%);
        }

        &.invalid {
            border: var(--hy-element-border-error) !important;
        }

        &.hideText {
            color: transparent;
        }

        // Size
        &.size-lg {
            padding: var(--hy-element-padding);
        }

        &.size-md {
            padding: var(--hy-element-padding-md);
        }

        &.size-sm {
            padding: var(--hy-element-padding-sm);
        }

        // Brand theme variants
        border: 2px solid transparent; // TODO: make border width a CSS variable
        color: v-bind(fontColor);

        &.isSolid {
            box-shadow: var(--hy-element-shadow);
            border-color: v-bind(borderColor); // Solids show they're border always (if they have one)
            background-color: v-bind(backgroundColor); // Solids always have a background

            &:not([disabled]) {
                &:hover {
                    background-color: v-bind(hoverColor);
                }
            }
        }

        &.isGhost,
        &.isGhostBg {
            &.hideText {
                background-color: v-bind(backgroundColor); // Show background color if hideText is set (e.g. loading is active)
            }
        }

        &.isGhost {
            background-color: transparent;

            &:not([disabled]):hover {
                background-color: v-bind(backgroundColor);
            }
        }

        &.isGhostBg {
            background-color: v-bind(backgroundColor);

            &:not([disabled]):hover {
                background-color: v-bind(hoverColor);
            }
        }
    }

    &.icons > select {
        padding-left: calc(var(--hy-element-padding) + 40px);
    }

    .iconSlot {
        pointer-events: none;
        position: absolute;
        margin: 0;
        left: 2px; // 2px border-width
        padding: 0 var(--hy-element-padding);
        border-radius: var(--hy-element-border-radius);
        color: v-bind(fontColor);

        &.size-lg {
            top: calc(var(--hy-element-padding) + 2px); // 2px border-width
        }

        &.size-md {
            top: calc(var(--hy-element-padding-md) + 2px); // 2px border-width
        }

        &.size-sm {
            top: calc(var(--hy-element-padding-sm) + 2px); // 2px border-width
        }
    }

    .chevron {
        position: absolute;
        width: 16px;
        height: 16px;
        right: 15px;
        align-items: center;
        display: flex;
        margin: 0;
        pointer-events: none;
        transform: rotate(-90deg);

        &.size-lg {
            top: calc(var(--hy-element-padding) + 2px + 4px); // 2px border-width + 4px arbatrary value for centering
        }

        &.size-md {
            top: calc(var(--hy-element-padding-md) + 4px); // 2px border-width + 4px arbatrary value for centering
        }

        &.size-sm {
            top: calc(var(--hy-element-padding-sm) + 4px); // 2px border-width + 4px arbatrary value for centering
        }

        svg {
            fill: v-bind(fontColor);
        }
    }

    .invalidText {
        font-size: var(--hy-font-size-small);
        padding: var(--hy-element-padding-sm);
        margin: 0;
        background-color: var(--hy-invalid-bg-color);
        border-radius: var(--hy-element-border-radius);
        border-top-left-radius: 0;
        border-top-right-radius: 0;
        position: relative;

        &::before,
        &::after {
            content: "";
            height: var(--hy-element-border-radius);
            width: var(--hy-element-border-radius);
            top: calc(var(--hy-element-border-radius) * -1);
            position: absolute;
            background-color: var(--hy-invalid-bg-color);
        }

        &::before {
            left: 0;
            clip-path: v-bind(invalidTextLeftClipPath);
        }

        &::after {
            right: 0;
            clip-path: v-bind(invalidTextRightClipPath);
        }
    }

    .hy-loader {
        position: absolute;
        top: calc(50% - 12.5px);
        left: calc(50% - 12.5px);
    }

    .hy-progress-bar {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

    &.invalidTextVisible {
        .hy-loader {
            top: calc(50% - 12.5px - (v-bind(invalidTextHeight) / 2));
        }

        .hy-progress-bar {
            top: calc(50% - (v-bind(invalidTextHeight) / 2));
        }
    }

    .invalidText,
    .iconSlot,
    .chevron {
        &.muted {
            filter: opacity(50%);
        }
    }
}
</style>
