<template>
    <div class="mt-1 relative rounded-sm shadow-sm"
         @keydown.escape="hideDatePicker"
    >
        <!-- Fix for the click away event to force close -->
        <div
            v-if="showDatePicker"
            @click="hideDatePicker"
            class="fixed inset-0"
            tabindex="-1"
        ></div>

        <!-- Date input -->
        <input type="hidden" :name="name" :value="selectedDate">
        <input class="form-input block w-full rounded-sm pr-10 sm:text-sm sm:leading-5"
               placeholder="Select Date"
               type="text"
               :placeholder="placeholder"
               :name="name"
               v-model="selectedDate"
               v-date
               @blur="updateDateContext"
               @click="toggleDatePicker"
               autocomplete="off"
        />
        <div class="absolute top-0 right-0 px-3 py-2">
            <svg class="h-5 w-5 text-gray-400" fill="none" stroke-linecap="round" stroke-linejoin="round"
                 stroke-width="2" viewBox="0 0 24 24"
                 stroke="currentColor"
            >
                <path d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
            </svg>
        </div>

        <!-- Datepicker dropdown -->
        <transition
            enter-active-class="transition ease-out duration-100"
            enter-class="transform opacity-0 scale-95"
            enter-to-class="transform opacity-100 scale-100"
            leave-active-class="transition ease-in duration-75"
            leave-class="transform opacity-100 scale-100"
            leave-to-class="transform opacity-0 scale-95"
        >
            <div v-if="showDatePicker" class="origin-top-right absolute right-0 mt-1 z-10 w-full md:w-64 lg:w-full">
                <div class="bg-white p-4 rounded-sm border border-gray-300 focus:outline-none shadow-xl">

                    <div class="flex justify-between items-center mb-2">
                        <div>
                            <span class="text-lg font-bold text-gray-800">{{ month }}</span>
                            <span class="ml-1 text-lg text-gray-600 font-normal">{{ year }}</span>
                        </div>
                        <div>
                            <button
                                type="button"
                                class="transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 p-1 rounded-full focus:outline-none"
                                @click="previousMonth"
                            >
                                <svg class="h-5 w-5 text-gray-500 inline-flex" fill="none" stroke-linecap="round"
                                     stroke-linejoin="round" stroke-width="2"
                                     viewBox="0 0 24 24" stroke="currentColor"
                                >
                                    <path d="M15 19l-7-7 7-7"></path>
                                </svg>
                            </button>
                            <button
                                type="button"
                                class="transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 p-1 rounded-full focus:outline-none"
                                @click="nextMonth"
                            >
                                <svg class="h-5 w-5 text-gray-500 inline-flex" fill="none" stroke-linecap="round"
                                     stroke-linejoin="round" stroke-width="2"
                                     viewBox="0 0 24 24" stroke="currentColor"
                                >
                                    <path d="M9 5l7 7-7 7"></path>
                                </svg>
                            </button>
                        </div>
                    </div>

                    <div class="flex flex-wrap mb-3 -mx-1">
                        <template v-for="day in daysOfWeek">
                            <div style="width: 14.26%" class="px-1">
                                <div class="text-gray-800 font-medium text-center text-xs">{{ day }}</div>
                            </div>
                        </template>
                    </div>

                    <div class="flex flex-wrap -mx-1">
                        <template v-for="blank in firstDayOfMonth">
                            <div style="width: 14.28%" class="text-center border p-1 border-transparent text-sm">
                                &nbsp;
                            </div>
                        </template>
                        <template v-for="(date, index) in daysInMonth">
                            <div style="width: 14.28%" class="px-1 mb-1">
                                <div
                                    :class="dateClasses(date)"
                                    :title="dateTitle(date)"
                                >
                                    <a @click.prevent="selectDate(date)">
                                        <span>{{ date.format('DD') }}</span>
                                    </a>
                                </div>
                            </div>
                        </template>
                    </div>

                </div>
            </div>
        </transition>

    </div>
</template>


<script>
export default {
    props : {
        name : {
            required : true
        },
        value : {
            default : null
        },
        placeholder : {
            type : String,
            default : 'format dd/mm/yyyy'
        },
        disabledDates : {
            type : Array,
            default : () => []
        },
        bookedDates : {
            type : Array,
            default : () => []
        },
        restrictedDates : {
            type : Array,
            default : () => []
        },
        disablePastDates : {
            type : Boolean,
            default : false
        },
        disabledDays : {
            type : Array,
            default : () => []
        },
        startOnMonday : {
            type : Boolean,
            default : false
        },
    },

    data() {
        return {
            showDatePicker : false,
            datepickerValue : null,
            selectedDate : null,
            today : window.moment().startOf('day'),
            dateContext : window.moment(),
        }
    },

    computed : {
        daysOfWeek() {
            return this.startOnMonday
                ? ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
                : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
        },
        year() {
            return this.dateContext.format('Y');
        },
        month() {
            return this.dateContext.format('MMMM');
        },
        currentDate() {
            return this.dateContext.get('date');
        },
        firstDayOfMonth() {
            let firstDay = window.moment(this.dateContext).subtract((this.currentDate - 1), 'days');
            let weekday = firstDay.weekday();
            return this.startOnMonday ? ((weekday + 6) % 7) : weekday;
        },
        daysInMonth() {
            let daysInMonth = [];
            let numberOfDays = window.moment(this.dateContext).daysInMonth();

            for (let i = 1; i < numberOfDays + 1; i++) {
                daysInMonth.push(
                    window.moment(this.dateContext).startOf('month').date(i)
                )
            }

            return daysInMonth;
        },
    },

    methods : {
        updateDateContext() {
            if (this.selectedDate) {
                this.dateContext = window.moment(this.selectedDate, 'DD/MM/YYYY');
            }
        },
        toggleDatePicker() {
            return this.showDatePicker = !this.showDatePicker;
        },
        hideDatePicker() {
            return this.showDatePicker = false;
        },
        nextMonth() {
            this.dateContext = window.moment(this.dateContext).add(1, 'month');
        },
        previousMonth() {
            this.dateContext = window.moment(this.dateContext).subtract(1, 'month');
        },
        isToday(date) {
            return date.startOf('day').isSame(this.today);
        },
        isPast(date) {
            return this.disablePastDates && date.isBefore(this.today);
        },
        isClosedDay(date) {
            return this.disabledDays.length && this.disabledDays.includes(date.format('dddd').toLowerCase());
        },
        isBooked(date) {
            return this.bookedDates.length && this.bookedDates.includes(date.format('YYYY-MM-DD'));
        },
        isRestricted(date) {
            return this.restrictedDates.length && this.restrictedDates.includes(date.format('YYYY-MM-DD'));
        },
        isGenericDisabled(date) {
            return this.disabledDates.length && this.disabledDates.includes(date.format('YYYY-MM-DD'));
        },
        isDisabled(date) {
            return this.isPast(date) || this.isClosedDay(date) || this.isBooked(date) || this.isRestricted(date) || this.isGenericDisabled(date);
        },
        dateClasses(date) {
            let classes = ['text-center text-sm leading-none rounded-full leading-loose transition ease-in-out duration-100'];

            if (this.isDisabled(date)) {
                classes.push('cursor-not-allowed');

                if (this.isBooked(date)) {
                    classes.push('text-green-300 line-through');
                } else if (this.isRestricted(date)) {
                    classes.push('text-red-300 line-through');
                } else if (this.isClosedDay(date)) {
                    classes.push('text-gray-300 line-through');
                } else {
                    classes.push('text-gray-300 line-through');
                }
            } else {
                classes.push('cursor-pointer');

                if (this.dateIsSelected(date)) {
                    classes.push('bg-gray-700 text-white');
                } else if (this.isToday(date)) {
                    classes.push('border border-red-300 text-gray-700 hover:bg-gray-200');
                } else {
                    classes.push('text-gray-700 hover:bg-gray-200');
                }
            }

            return classes;
        },
        dateTitle(date) {
            if (this.isBooked(date)) return 'Booked';
            if (this.isRestricted(date)) return 'Restricted';
            if (this.isClosedDay(date)) return 'Closed';
            if (this.isPast(date)) return 'Past date';
            return '';
        },
        selectDate(date) {
            if (this.isDisabled(date)) {
                return;
            }
            this.selectedDate = date.format('DD/MM/YYYY');
            this.$emit('selected', this.selectedDate);
            this.hideDatePicker();
        },
        dateIsSelected(date) {
            return this.selectedDate === date.format('DD/MM/YYYY');
        },
    },

    watch : {
        value : function (newValue, oldValue) {
            if (newValue) {
                this.selectedDate = newValue;
                this.dateContext = window.moment(newValue, 'DD/MM/YYYY');
            } else {
                this.selectedDate = null;
                this.dateContext = window.moment();
            }
        }
    },

    mounted() {
        if (this.value) {
            this.selectedDate = this.value;
            this.dateContext = window.moment(this.value, 'DD/MM/YYYY');
        }
    }
}
</script>
