<script setup>
import { computed, onMounted, ref, watch, onUnmounted, nextTick } from 'vue';

import ZoneCalendar from './ZoneCalendar.vue';

import { useStateStore } from 'stores/useStateStore';
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
import { useArrayData } from 'src/composables/useArrayData';

const props = defineProps({
    dataKey: {
        type: String,
        required: true,
    },
});

const emit = defineEmits([
    'update:firstDay',
    'update:lastDay',
    'update:events',
    'onDateSelected',
]);

const stateStore = useStateStore();
const weekdayStore = useWeekdayStore();

const nMonths = ref(4);
const _date = ref(Date.vnNew());
const _data = ref(null);
const firstDay = ref(null);
const lastDay = ref(null);
const months = ref([]);
const days = ref({});
const exclusions = ref({});
const geoExclusions = ref({});
const events = ref([]);

const arrayData = useArrayData(props.dataKey);
const { store } = arrayData;

const refreshEvents = () => {
    days.value = {};
    if (!data.value) return;

    let day = new Date(firstDay.value.getTime());

    while (day <= lastDay.value) {
        let stamp = day.getTime();
        let wday = day.getDay();
        let dayEvents = [];
        let _exclusions = exclusions.value[stamp] || [];

        if (events.value) {
            for (let event of events.value) {
                let match;
                switch (event.type) {
                    case 'day':
                        match = event.dated == stamp;
                        break;
                    default:
                        match =
                            event.wdays[wday] &&
                            (!event.started || stamp >= event.started) &&
                            (!event.ended || stamp <= event.ended);
                        break;
                }
                if (match && !_exclusions.find((e) => e.zoneFk == event.zoneFk)) {
                    dayEvents.push(event);
                }
            }
        }
        if (dayEvents.length) days.value[stamp] = dayEvents;

        day.setDate(day.getDate() + 1);
    }
    emit('update:events', events.value);
};

const date = computed({
    get: () => _date.value,
    set: (value) => {
        _date.value = value;
        let stamp = value.getTime();

        firstDay.value = new Date(stamp);
        firstDay.value.setDate(1);

        lastDay.value = new Date(stamp);
        lastDay.value.setMonth(lastDay.value.getMonth() + nMonths.value);
        lastDay.value.setDate(0);

        months.value = [];
        for (let i = 0; i < nMonths.value; i++) {
            let monthDate = new Date(stamp);
            monthDate.setMonth(value.getMonth() + i);
            months.value.push(monthDate);
        }

        emit('update:firstDay', firstDay.value);
        emit('update:lastDay', lastDay.value);
        refreshEvents();
    },
});

const data = computed({
    get: () => {
        return _data.value;
    },
    set: (value) => {
        _data.value = value;

        value = value || {};

        events.value = value.events;
        function toStamp(date) {
            return date && new Date(date).setHours(0, 0, 0, 0);
        }

        exclusions.value = {};
        let _exclusions = value.exclusions;

        if (_exclusions) {
            for (let exclusion of _exclusions) {
                let stamp = toStamp(exclusion.dated);
                if (!exclusions[stamp]) exclusions.value[stamp] = [];
                exclusions.value[stamp].push(exclusion);
            }
        }

        geoExclusions.value = {};
        let _geoExclusions = value.geoExclusions;
        if (_geoExclusions) {
            for (let geoExclusion of _geoExclusions) {
                let stamp = toStamp(geoExclusion.dated);
                if (!geoExclusions.value[stamp]) geoExclusions.value[stamp] = [];
                geoExclusions.value[stamp].push(geoExclusion);
            }
        }

        let _events = value.events;
        if (_events) {
            for (let event of _events) {
                event.dated = toStamp(event.dated);
                event.ended = toStamp(event.ended);
                event.started = toStamp(event.started);
                event.wdays = weekdayStore.fromSet(event.weekDays || '');
            }
        }

        refreshEvents();
    },
});

watch(
    () => store.data,
    (value) => {
        data.value = value;
    },
    { immediate: true }
);

const getMonthNameAndYear = (date) => {
    const monthName = weekdayStore.getLocaleMonths[date.getMonth()].locale;
    const year = date.getFullYear();
    return `${monthName} ${year}`;
};

const headerTitle = computed(() => {
    if (!months.value?.length) return;

    const firstMonth = getMonthNameAndYear(months.value[0]);
    const lastMonth = getMonthNameAndYear(months.value[months.value.length - 1]);

    return `${firstMonth} - ${lastMonth}`;
});

const step = (direction) => {
    const _date = new Date(date.value);
    _date.setMonth(_date.getMonth() + nMonths.value * direction);
    date.value = _date;
};

const onDateSelected = (data) => emit('onDateSelected', data);

onMounted(async () => {
    let initialDate = Date.vnNew();
    initialDate.setDate(1);
    initialDate.setHours(0, 0, 0, 0);
    date.value = initialDate;
    weekdayStore.initStore();
    await nextTick();
    stateStore.rightDrawer = true;
});

onUnmounted(() => arrayData.destroy());
</script>

<template>
    <QCard style="height: max-content">
        <div class="calendars-header">
            <QBtn
                icon="arrow_left"
                size="sm"
                flat
                class="full-height"
                @click="step(-1)"
            />
            <span>{{ headerTitle }}</span>
            <QBtn
                icon="arrow_right"
                size="sm"
                flat
                class="full-height"
                @click="step(1)"
            />
        </div>
        <div class="calendars-container">
            <ZoneCalendar
                v-for="(month, index) in months"
                :key="index"
                :month="month.getMonth() + 1"
                :year="month.getFullYear()"
                :month-date="month"
                :geo-exclusions="geoExclusions"
                :exclusions="exclusions"
                :days-map="days"
                @on-date-selected="onDateSelected"
            />
        </div>
    </QCard>
</template>

<style lang="scss" scoped>
.calendars-header {
    height: 45px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: $primary;
    font-weight: bold;
    font-size: 16px;
}

.calendars-container {
    max-width: 800px;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-evenly;
}
</style>
