<script setup>
import { computed, ref, useAttrs, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRequired } from 'src/composables/useRequired';

const $attrs = useAttrs();
const { isRequired, requiredFieldRule } = useRequired($attrs);
const { t } = useI18n();
const emit = defineEmits([
    'update:modelValue',
    'update:options',
    'keyup.enter',
    'remove',
    'blur',
]);

const $props = defineProps({
    modelValue: {
        type: [String, Number],
        default: null,
    },
    isOutlined: {
        type: Boolean,
        default: false,
    },
    info: {
        type: String,
        default: '',
    },
    clearable: {
        type: Boolean,
        default: true,
    },
    emptyToNull: {
        type: Boolean,
        default: true,
    },
    insertable: {
        type: Boolean,
        default: false,
    },
    maxlength: {
        type: Number,
        default: null,
    },
    uppercase: {
        type: Boolean,
        default: false,
    },
});

const vnInputRef = ref(null);
const value = computed({
    get() {
        return $props.modelValue;
    },
    set(value) {
        if ($props.emptyToNull && value === '') value = null;
        emit('update:modelValue', value);
    },
});
const hover = ref(false);
const styleAttrs = computed(() => {
    return $props.isOutlined
        ? {
              dense: true,
              outlined: true,
              rounded: true,
          }
        : {};
});

const focus = () => {
    vnInputRef.value.focus();
};

defineExpose({
    focus,
    vnInputRef,
});

const mixinRules = [
    requiredFieldRule,
    ...($attrs.rules ?? []),
    (val) => {
        const maxlength = $props.maxlength;
        if (maxlength && +val?.length > maxlength)
            return t(`maxLength`, { value: maxlength });
        const { min, max } = vnInputRef.value.$attrs;
        if (!min) return null;
        if (min >= 0) if (Math.floor(val) < min) return t('inputMin', { value: min });
        if (!max) return null;
        if (max > 0) {
            if (Math.floor(val) > max) return t('inputMax', { value: max });
        }
    },
];

const handleKeydown = (e) => {
    if (e.key === 'Backspace') return;

    if ($props.insertable && e.key.match(/[0-9]/)) {
        handleInsertMode(e);
    }
};

const handleInsertMode = (e) => {
    e.preventDefault();
    const input = e.target;
    const cursorPos = input.selectionStart;
    const maxlength = $props.maxlength;
    let currentValue = value.value;
    if (!currentValue) currentValue = e.key;
    const newValue = e.key;
    if (newValue && !isNaN(newValue) && cursorPos < maxlength) {
        value.value =
            currentValue.substring(0, cursorPos) +
            newValue +
            currentValue.substring(cursorPos + 1);
    }
    nextTick(() => {
        input.setSelectionRange(cursorPos + 1, cursorPos + 1);
    });
};

const handleUppercase = () => {
    value.value = value.value?.toUpperCase() || '';
};
</script>

<template>
    <div @mouseover="hover = true" @mouseleave="hover = false">
        <QInput
            ref="vnInputRef"
            v-model="value"
            v-bind="{ ...$attrs, ...styleAttrs }"
            :type="$attrs.type"
            :class="{ required: isRequired }"
            @keyup.enter="emit('keyup.enter')"
            @blur="emit('blur')"
            @keydown="handleKeydown"
            :clearable="false"
            :rules="mixinRules"
            :lazy-rules="true"
            hide-bottom-space
            :data-cy="($attrs['data-cy'] ?? $attrs.label) + '_input'"
        >
            <template #prepend v-if="$slots.prepend">
                <slot name="prepend" />
            </template>
            <template #append>
                <QIcon
                    name="close"
                    size="xs"
                    :style="{
                        visibility:
                            hover &&
                            value &&
                            !$attrs.disabled &&
                            !$attrs.readonly &&
                            $props.clearable
                                ? 'visible'
                                : 'hidden',
                    }"
                    @click="
                        () => {
                            value = null;
                            vnInputRef.focus();
                            emit('remove');
                        }
                    "
                ></QIcon>

                <QIcon
                    name="match_case"
                    size="xs"
                    v-if="!$attrs.disabled && !$attrs.readonly && $props.uppercase"
                    @click="handleUppercase"
                    class="uppercase-icon"
                >
                    <QTooltip>
                        {{ t('Convert to uppercase') }}
                    </QTooltip>
                </QIcon>

                <slot name="append" v-if="$slots.append && !$attrs.disabled" />
                <QIcon v-if="info" name="info">
                    <QTooltip max-width="350px">
                        {{ info }}
                    </QTooltip>
                </QIcon>
            </template>
        </QInput>
    </div>
</template>

<style>
.uppercase-icon {
    transition:
        color 0.3s,
        transform 0.2s;
    cursor: pointer;
}

.uppercase-icon:hover {
    color: #ed9937;
    transform: scale(1.2);
}
</style>
<i18n>
    en:
        inputMin: Must be more than {value}
        maxLength: The value exceeds {value} characters
        inputMax: Must be less than {value}

    es:
        inputMin: Debe ser mayor a {value}
        maxLength: El valor excede los {value} carácteres
        inputMax: Debe ser menor a {value}
        Convert to uppercase: Convertir a mayúsculas
</i18n>
