<script setup lang="ts">
    import { computed, onMounted, ref, watch, nextTick } from 'vue';
    import BaseMaskedInput from '@/UI-kit/components/UI/inputs/BaseMaskedInput.vue';
    import {
        EInputInputmode,
        EInputType,
        EInputComponentType,
        IInputProps,
        UIColorName,
    } from '@/UI-kit/types';
    import { debounce, toCapitalize } from '@/UI-kit/utils';
    import { UIColor, UIIcons } from '@/UI-kit/constants';
    import UISvgIcon from '@/UI-kit/components/UI/svg-icon/UISvgIcon.vue';
    import LicensePlateInput from '@/UI-kit/components/UI/inputs/LicensePlateInput.vue';

    const props = withDefaults(defineProps<IInputProps>(), {
        component: EInputComponentType.input,
        id: String(Math.random),
        label: '',
        mask: '',
        placeholder: '',
        type: EInputType.text,
        inputmode: EInputInputmode.text,
        modelValue: '',
        errorMessage: '',
        isError: false,
        disabled: false,
        readonly: false,
        masked: false,
        isCapitalize: false,
        isSetInputFocus: false,
        delay: 0,
        isBoxShadow: false,
        isDate: false,
        isShowClear: false,
        helperImg: '',
        isAllowSameValues: false,
        autoresize: false,
        baseHeightTextarea: 48,
        prefixIcon: undefined,
        prefixIconColor: UIColor[UIColorName.Gray400],
    });

    const emit = defineEmits(['update:model-value', 'input', 'blur', 'focus']);

    const inputElement = ref();

    const borderColor = ref(UIColor[UIColorName.Gray300]);
    const bgColor = ref(UIColor[UIColorName.White10]);
    const textColor = ref(UIColor[UIColorName.Gray900]);
    const colorDanger = ref(UIColor[UIColorName.Red600]);

    const inputEl = computed(() =>
        inputElement.value?.focus ? inputElement.value : inputElement.value.$el,
    );

    const resizeTextarea = () => {
        if (
            !props.autoresize ||
            props.component !== EInputComponentType.textarea ||
            !inputEl.value
        ) {
            return;
        }

        const el = inputEl.value as HTMLTextAreaElement;
        const baseHeight = props.baseHeightTextarea;

        el.style.height = 'auto';

        const scrollHeight = el.scrollHeight;
        const nextHeight = Math.max(scrollHeight, baseHeight);

        el.style.height = `${nextHeight}px`;
    };

    const modelValue = computed(() => {
        if (!props.isDate) {
            if (props.isCapitalize && typeof props.modelValue === 'string') {
                return toCapitalize(props.modelValue);
            }
            return props.modelValue;
        }

        return String(props.modelValue).split('-').reverse().join('.');
    });

    const inputComponent = computed(() => {
        if (props.component === EInputComponentType.licence_plate) {
            return LicensePlateInput;
        }

        if (props.component === EInputComponentType.mask) {
            return BaseMaskedInput;
        }

        if (props.component === EInputComponentType.textarea) {
            return EInputComponentType.textarea;
        }

        return EInputComponentType.input;
    });

    const classList = computed(() => ({
        '--capitalize': props.isCapitalize,
        '--error': props.isError,
        '--textarea': props.component === EInputComponentType.textarea && !props.autoresize,
        '--autoresize': props.autoresize && props.component === EInputComponentType.textarea,
        '--is-show-clear': props.isShowClear,
        '--licence-plate': props.component === EInputComponentType.licence_plate,
        '--has-prefix': Boolean(props.prefixIcon),
    }));

    const isTextareaAutoresize = computed(
        () => props.autoresize && props.component === EInputComponentType.textarea,
    );

    const textareaRows = computed(() => (isTextareaAutoresize.value ? 1 : undefined));

    const updateValue = (value: string) => {
        let prepareValue = value.trim();

        if (props.isDate) {
            prepareValue = prepareValue.split('.').reverse().join('-');
        }
        emit('update:model-value', prepareValue);
        emit('input', prepareValue);
    };

    const handlerDebounce = debounce(function (event: any) {
        if (event.type === 'input') {
            return updateValue((event.target as HTMLInputElement).value);
        } else {
            return updateValue(event);
        }
    }, props.delay);

    const focus = (e: Event) => emit('focus', e);
    const blur = (e: Event) => emit('blur', (e.target as HTMLInputElement).value.trim());

    const listeners = computed(() => ({
        input: (event: any) => {
            handlerDebounce(event);
            resizeTextarea();
        },
        'update:model-value': (event: any) => handlerDebounce(event),
        blur,
        focus,
    }));

    const clearInput = () => updateValue('');

    onMounted(() => {
        if (props.autoresize && props.component === EInputComponentType.textarea) {
            nextTick(resizeTextarea);
        }

        if (props.isSetInputFocus) {
            setTimeout(() => inputElement.value.focus(), 200);
        }
    });

    watch(
        () => props.modelValue,
        () => {
            if (props.autoresize && props.component === EInputComponentType.textarea) {
                nextTick(resizeTextarea);
            }
        },
    );

    defineExpose({
        focus: () => {
            inputEl.value.focus();
        },
        blur: () => {
            inputEl.value.blur();
        },
        setSelectionRange: () => {
            if (props.type !== EInputType.email) {
                inputEl.value?.setSelectionRange(0, 0);
            }
        },
    });
</script>

<template>
    <div :class="classList" class="ui-input__wrap">
        <label v-if="label" :for="id" class="ui-input__label" v-html="label" />
        <div class="ui-input__inner">
            <div class="ui-input__block">
                <UISvgIcon
                    v-if="prefixIcon"
                    class="ui-input__prefix"
                    :name="prefixIcon"
                    :color="prefixIconColor"
                />
                <button
                    v-if="isShowClear && modelValue"
                    type="button"
                    class="ui-input__close"
                    @mousedown.prevent.stop="clearInput"
                >
                    <UISvgIcon
                        class="ui-input__close-icon"
                        :name="UIIcons.Close"
                        :fill="UIColor[UIColorName.Gray400]"
                    />
                </button>
                <Component
                    :is="inputComponent"
                    :id="id"
                    ref="inputElement"
                    class="ui-input"
                    :class="classList"
                    :value="modelValue"
                    :maska="mask"
                    :type="type"
                    :is-allow-same-values="isAllowSameValues"
                    :is-error="isError"
                    :disabled="disabled"
                    :readonly="readonly"
                    :placeholder="placeholder"
                    :masked="masked"
                    :inputmode="inputmode"
                    :rows="textareaRows"
                    v-on="listeners"
                    @focus="focus($event)"
                    @blur="emit('blur', $event)"
                />
            </div>
            <img
                v-if="helperImg"
                class="ui-input__img-example"
                height="52"
                width="100"
                :src="helperImg"
                alt="icon"
            />
            <div v-if="isError" class="ui-input__error" v-html="errorMessage" />
        </div>
    </div>
</template>

<style lang="scss" scoped>
    @use '@/UI-kit/assets/scss/mixins/index.mixin';

    .ui-input {
        $content: &;

        @include index.text(14px, 500, 20px);

        position: relative;
        display: inline-block;
        width: 100%;
        height: 48px;
        padding: 8px 16px;
        background: v-bind(bgColor);
        color: v-bind(textColor);
        border: 1px solid v-bind(borderColor);
        transition: all 0.25s;
        border-radius: 8px;
        text-align: left;
        appearance: unset;
        box-sizing: border-box;
        outline: 0;

        &::placeholder {
            color: var(--gray-400);
            font-weight: 500;
            font-size: 14px;
            line-height: 20px;
            text-transform: none;
        }

        &:hover,
        &:focus {
            border-color: var(--blue-500);
        }

        &:disabled {
            border-color: var(--gray-300);
            background: var(--gray-100);
        }

        &.--error {
            border-color: v-bind(colorDanger);
            color: v-bind(colorDanger);
        }

        &.--capitalize {
            text-transform: capitalize;
        }

        &.--textarea {
            resize: none;
            height: 100px;
        }

        &.--autoresize {
            resize: none;
            width: 100%;
            max-width: 100%;
            height: auto;
            min-height: 48px;
            max-height: 150px;
            overflow-y: auto;
            transition: none;
        }

        &.--licence-plate {
            height: auto;
            padding: 0;
            background: transparent;
            color: inherit;
            border: none;
        }

        &__close {
            @include index.flex(row, 0, center, center);

            position: absolute;
            top: 50%;
            right: 10px;
            z-index: 2;
            width: 24px;
            height: 24px;
            border: none;
            transition: 1s;
            transform: translateY(-50%);
            outline: none;

            &-icon {
                width: 10px;
                height: 10px;
                color: var(--gray-600);
            }
        }

        &.--has-prefix {
            padding-left: 40px;
        }

        &.--is-show-clear {
            padding-right: 40px;
        }

        &__prefix {
            position: absolute;
            top: 50%;
            left: 12px;
            z-index: 2;
            width: 16px;
            height: 16px;
            transform: translateY(-50%);
            pointer-events: none;
        }

        &__label {
            @include index.text(14px, 600, 20px);

            color: var(--gray-900);
        }

        &__wrap {
            @include index.flex(column);

            width: 100%;
            gap: 3px;
        }

        &__inner,
        &__block {
            position: relative;
            z-index: 2;
            width: 100%;
        }

        &__img {
            &-example {
                position: relative;
                z-index: 1;
                width: 100%;
                margin-top: -12px;
                border-radius: 0 0 12px 12px;
                object-fit: contain;

                @media (min-width: 410px) {
                    margin-top: -6px;
                    object-fit: cover;
                }
            }
        }

        &__error {
            text-align: left;
            color: v-bind(colorDanger);
            font-size: 12px;
        }
    }
</style>
