<script setup>
import { nextTick, watch, computed, ref, useAttrs } from 'vue';
import { date, getCssVar } from 'quasar';
import VnDate from './VnDate.vue';
import { useRequired } from 'src/composables/useRequired';

const $attrs = useAttrs();
const { isRequired, requiredFieldRule } = useRequired($attrs);
const model = defineModel({ type: [String, Date] });

const $props = defineProps({
    isOutlined: {
        type: Boolean,
        default: false,
    },
    showEvent: {
        type: Boolean,
        default: true,
    },
});

const vnInputDateRef = ref(null);
const errColor = getCssVar('negative');
const textColor = ref('');

const dateFormat = 'DD/MM/YYYY';
const isPopupOpen = ref();
const hover = ref();

const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])];

const popupDate = computed(() =>
    model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value,
);

const styleAttrs = computed(() => {
    return $props.isOutlined
        ? {
              dense: true,
              outlined: true,
              rounded: true,
          }
        : {};
});

const inputValue = ref('');

const validateAndCleanInput = (value) => {
    inputValue.value = value.replace(/[^0-9./-]/g, '');
};

const manageDate = (date) => {
    inputValue.value = date.split('/').reverse().join('/');
    formatDate();
    isPopupOpen.value = false;
};

watch(
    () => model.value,
    (nVal) => {
        if (nVal) inputValue.value = date.formatDate(new Date(model.value), dateFormat);
        else inputValue.value = '';
    },
    { immediate: true },
);

const formatDate = () => {
    let value = inputValue.value;
    if (!value || value === model.value) {
        textColor.value = '';
        return;
    }
    const regex =
        /^([0]?[1-9]|[12][0-9]|3[01])([./-])([0]?[1-9]|1[0-2])([./-](\d{1,4}))?$/;
    if (!regex.test(value)) {
        textColor.value = errColor;
        return;
    }

    value = value.replace(/[.-]/g, '/');
    const parts = value.split('/');
    if (parts.length < 2) {
        textColor.value = errColor;
        return;
    }

    let [day, month, year] = parts;
    if (day.length === 1) day = '0' + day;
    if (month.length === 1) month = '0' + month;

    const currentYear = Date.vnNew().getFullYear();
    if (!year) year = currentYear;
    const millennium = currentYear.toString().slice(0, 1);

    switch (year.length) {
        case 1:
            year = `${millennium}00${year}`;
            break;
        case 2:
            year = `${millennium}0${year}`;
            break;
        case 3:
            year = `${millennium}${year}`;
            break;
        case 4:
            break;
    }

    let isoCandidate = `${year}/${month}/${day}`;
    isoCandidate = date.formatDate(
        new Date(isoCandidate).toISOString(),
        'YYYY-MM-DDTHH:mm:ss.SSSZ',
    );
    const [isoYear, isoMonth, isoDay] = isoCandidate.split('-').map((e) => parseInt(e));
    const parsedDate = new Date(isoYear, isoMonth - 1, isoDay);

    const isValidDate =
        parsedDate instanceof Date &&
        !isNaN(parsedDate) &&
        parsedDate.getFullYear() === parseInt(year) &&
        parsedDate.getMonth() === parseInt(month) - 1 &&
        parsedDate.getDate() === parseInt(day);

    if (!isValidDate) {
        textColor.value = errColor;
        return;
    }

    if (model.value) {
        const original =
            model.value instanceof Date ? model.value : new Date(model.value);
        parsedDate.setHours(
            original.getHours(),
            original.getMinutes(),
            original.getSeconds(),
            original.getMilliseconds(),
        );
    }

    model.value = parsedDate.toISOString();

    textColor.value = '';
};

const handleEnter = (event) => {
    formatDate();

    nextTick(() => {
        const newEvent = new KeyboardEvent('keydown', {
            key: 'Enter',
            code: 'Enter',
            bubbles: true,
            cancelable: true,
        });
        vnInputDateRef.value?.$el?.dispatchEvent(newEvent);
    });
};
</script>

<template>
    <div @mouseover="hover = true" @mouseleave="hover = false">
        <QInput
            ref="vnInputDateRef"
            v-model="inputValue"
            class="vn-input-date"
            placeholder="dd/mm/aaaa"
            v-bind="{ ...$attrs, ...styleAttrs }"
            :class="{ required: isRequired }"
            :rules="mixinRules"
            :clearable="false"
            :input-style="{ color: textColor }"
            @click="isPopupOpen = !isPopupOpen"
            @keydown="isPopupOpen = false"
            @focusout="formatDate"
            @keydown.enter.prevent="handleEnter"
            hide-bottom-space
            :data-cy="($attrs['data-cy'] ?? $attrs.label) + '_inputDate'"
            @update:model-value="validateAndCleanInput"
        >
            <template #append>
                <QIcon
                    name="close"
                    size="xs"
                    v-if="
                        ($attrs.clearable == undefined || $attrs.clearable) &&
                        hover &&
                        inputValue &&
                        !$attrs.disable
                    "
                    @click="
                        vnInputDateRef.focus();
                        inputValue = null;
                        model = null;
                        isPopupOpen = false;
                    "
                />
            </template>
            <QMenu
                v-if="$q.screen.gt.xs"
                transition-show="scale"
                transition-hide="scale"
                v-model="isPopupOpen"
                anchor="bottom left"
                self="top start"
                :no-focus="true"
                :no-parent-event="true"
            >
                <VnDate v-model="popupDate" @update:model-value="manageDate" />
            </QMenu>
            <QDialog v-else v-model="isPopupOpen">
                <VnDate v-model="popupDate" @update:model-value="manageDate" />
            </QDialog>
        </QInput>
    </div>
</template>
<i18n>
    es:
        Open date: Abrir fecha
</i18n>
