<template>
    <div class="hy-text-area" :class="{ transitionsEnabled }">
        <textarea
            :placeholder="placeholder"
            :disabled="disabled"
            :value="modelValue"
            @input="$emit('update:modelValue', $event.target.value)"
            :style="{ resize }"
            :class="[variantParsed, sizeParsed, { invalid, isGhost, isGhostBg, isSolid }]"
            v-bind="attributes"
        />

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

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

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

export default {
    name: "HyTextArea",
    props: {
        modelValue: String,
        placeholder: {
            type: String,
            default: "",
        },
        variant: {
            type: String,
            default: null,
        },
        size: {
            type: String,
            default: null,
        },
        required: {
            type: Boolean,
            default: false,
        },
        disabled: {
            type: Boolean,
            default: false,
        },
        invalid: {
            type: Boolean,
            default: false,
        },
        invalidText: {
            type: String,
            default: null,
        },
        resize: {
            type: String,
            default: "vertical",
        },
    },
    data() {
        return {
            borderRadius: "10",
            transitionsEnabled: false,
        };
    },
    computed: {
        attributes() {
            let attrs = { ...this.$attrs };

            // Delete attrs that shouldn't appear on the input element
            delete attrs.id;
            delete attrs.class;
            delete attrs.placeholder;
            delete attrs.required;
            delete attrs.disabled;
            delete attrs.resize;

            return attrs;
        },

        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)`;
        },
        borderColorPressed() {
            if (this.isSolid == false) return "transparent";
            else return `var(--hy-variant-${this.variantParsed.replace("-bg", "")}-border-color-pressed)`;
        },

        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,
    },
};
</script>

<style lang="scss">
.hy-text-area {
    margin: var(--hy-element-margin);
    position: relative;

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

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

        display: block;
        border-radius: var(--hy-element-border-radius);
        font-size: var(--hy-font-size);
        font-family: var(--hy-font-family);
        color: var(--hy-font-color-contrast);
        cursor: text;
        outline: none;
        width: 100%;
        max-width: 100%;
        min-height: 57px; // Approximately the height of an Input in a desktop viewport

        &:not([disabled]) {
            &:hover {
                background-color: var(--hy-variant-secondary-hover-color);
            }

            &:focus:not(.invalid) {
                border: var(--hy-element-border-accent);
            }
        }

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

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

        // Sizes
        &.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

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

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

                &:focus,
                &:active {
                    border-color: v-bind(borderColorPressed);
                }
            }
        }

        &.isGhost,
        &.isGhostBg {
            &:not([disabled]) {
                &:focus,
                &:active {
                    border-color: v-bind(borderColor);
                }
            }

            &.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);
            }
        }
    }

    .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);
        }

        &.muted {
            filter: opacity(50%);
        }
    }
}

@media only screen and (max-width: 600px) {
    .hy-text-area {
        textarea {
            min-height: 50px; // Approximately the height of an Input in a mobile viewport
        }
    }
}
</style>
