<template>
  <div class="relative" ref="target">
    <AisInput
        name="dateField"
        icon="calendar"
        placeholder="yyyy-mm-dd"
        v-model="selectedIsoDate"
        :value="selectedIsoDate"
        @click="toggleDatepicker"
        :size="pickerSize"
        :disabled="disabled"
        :class="{'cursor-not-allowed':disabled}"
    />
    <div v-if="!disabled">
      <transition
          enter-active-class="transition duration-100 ease-out"
          enter-from-class="transform scale-95 opacity-0"
          enter-to-class="transform scale-100 opacity-100"
          leave-active-class="transition duration-75 ease-in"
          leave-from-class="transform scale-100 opacity-100"
          leave-to-class="transform scale-95 opacity-0"
      >
        <div class="ais-datepicker border border-secondary border-opacity-25 shadow-lg pt-2 px-2 py-2 bg-white absolute z-50 mt-2 min-w-[350px]" :class="pickerSize"
             v-if="showDatePicker">
        <div class="flex justify-between">

          <svg @click="goToPreviousYear" xmlns="http://www.w3.org/2000/svg"
               class=" w-7 h-7 px-1 py-1  cursor-pointer rounded-full" :class="`${onHoverVariant(variant)}`" fill="none"
               viewBox="0 0 24 24" stroke="currentColor">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7"/>
          </svg>

          <div class="flex space-x-2">

            <svg @click="goToPreviousMonth" xmlns="http://www.w3.org/2000/svg"
                 class="w-7 h-7 px-1 py-1 cursor-pointer rounded-full" :class="`${onHoverVariant(variant)}`" fill="none"
                 viewBox="0 0 24 24" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
            </svg>

            <label class="text-lg font-medium font-serif">{{ getMonthAsString() }} {{ year }}</label>

            <svg @click="goToNextMonth" xmlns="http://www.w3.org/2000/svg"
                 class="w-7 h-7 px-1 py-1 cursor-pointer rounded-full" :class="`${onHoverVariant(variant)}`" fill="none"
                 viewBox="0 0 24 24" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
            </svg>

          </div>

          <svg @click="goToNextYear" xmlns="http://www.w3.org/2000/svg"
               class="w-7 h-7 px-1 py-1 cursor-pointer rounded-full" :class="`${onHoverVariant(variant)}`" fill="none"
               viewBox="0 0 24 24" stroke="currentColor">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7"/>
          </svg>
        </div>

        <div class="border-b-2 pt-2 ">

        </div>

        <div class="grid grid-cols-7 gap-y-4 gap-x-4 mt-2">
          <div v-for="week in daysShortMap">
            <label class="font-light">{{ week }}</label>
          </div>
          <div class="font-medium" :style="{'grid-column-start': computeWeekStartClass}">
            <button :disabled="handleMinMaxAndDisableDate(1)" @click="onDateClick(1)" class="font-medium"
                    :class="[computeOnDateHover, styleSelectedDate(1), handleMinMaxAndDisableDate(1)? 'opacity-20 hover:cursor-not-allowed': '']">
              1
            </button>
          </div>
          <div v-for="date in range(2,getTotalNumberOfDays(year,month))">
            <button :disabled="handleMinMaxAndDisableDate(date)" @click="onDateClick(date)" class="font-medium"
                    :class="[computeOnDateHover, styleSelectedDate(date), handleMinMaxAndDisableDate(date)? 'opacity-20 hover:cursor-not-allowed': '']">
              {{ date }}
            </button>
          </div>
        </div>
      </div>
      </transition>
    </div>
  </div>
</template>

<script setup>
import {ref, computed, onMounted, watch} from 'vue';
import {DatepickerProps} from "@/components/datepicker/datepicker-props.js";
import AisInput from "@/components/input/AisInput.vue";
import {onHoverVariant} from "@/util/variants-util";
import { controlProps } from "@/util/controls.js";
import { onClickOutside, onKeyUp, useDateFormat } from '@vueuse/core'
import { useSize } from "@/composables/useInjections";

const emit = defineEmits(['select', 'update:modelValue'])

const props = defineProps({
  ...DatepickerProps,
  size: controlProps.size
})

const pickerSize = useSize(props, 'md')

const selectedDate = ref(null);

const showDatePicker = ref(false);
const target = ref(null)

const year = ref(new Date().getFullYear());
const month = ref(new Date().getMonth());

const daysShortMap = ref(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']);
const monthMap = ref(['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'])


onClickOutside(target, () => showDatePicker.value = false)
onKeyUp('Escape', () => showDatePicker.value = false)

const currentIsoDate = computed(() => formatDate(new Date()) )
const selectedIsoDate = computed({
  get () { return selectedDate.value ? formatDate(selectedDate.value) : '' },
  set(val) { setDate(val) }
})

function getTotalNumberOfDays(year, month) {
  return 40 - new Date(year, month, 40).getDate();
}

function range(start, end) {
  return Array(end - start + 1).fill().map((_, idx) => start + idx)
}

function getMonthAsString() {
  return monthMap.value[month.value];
}

function goToPreviousMonth() {
  const selectedYear = year.value;
  month.value--;
  if (month.value < 0) {
    //set month to December and decrease year to -1
    month.value = 11
    year.value = selectedYear - 1;
  }
}

function goToNextMonth() {
  const selectedYear = year.value;
  month.value++;
  if (month.value > 11) {
    //set month to January and increase year by 1
    month.value = 0;
    year.value = selectedYear + 1;
  }
}

function goToPreviousYear() {
  year.value = year.value - 1;
}

function goToNextYear() {
  year.value = year.value + 1;
}

const variantBorderBottomColor = computed(() => {
  switch (props.variant){
    case 'primary':
      return 'border-b-primary';
    case 'info':
      return 'border-b-info';
    case 'danger':
      return 'border-b-danger';
    case 'success':
      return 'border-b-success';
    case 'warning':
      return 'border-b-warning';
    case 'plain':
      return 'border-b-plain';
    case 'secondary':
      return 'border-b-secondary';
    default:
      return 'border-b-default';
  }
})

function styleSelectedDate(date) {
  const isoDate = formatDate(new Date(year.value,month.value,date))

  if(isoDate === selectedIsoDate.value) {
    const classLst = [`${onHoverVariant(props.variant)}`]
    classLst.push(props.variant === 'warning' ? 'border warning' : `${props.variant}`)
    return classLst
  } else if(isoDate === currentIsoDate.value){
    const classLst = [`${variantBorderBottomColor.value} rounded-none hover:rounded-full hover:border-none`]
    if(props.variant !== 'plain')
      classLst.push("border-b-4")

    return classLst;
  }
}

function handleMinMaxAndDisableDate(date) {
  const minDate = props.min;
  const maxDate = props.max;
  const disableDatesArr = props.exclude;
  const onlyShowDateArr = props.only;
  const selectedDate = new Date(year.value, month.value, date);
  if(onlyShowDateArr && disableDatesArr){
    throw new TypeError("You cannot use both :only and :exclude prop. Please use either one of them")
  }

  if (minDate) {
    if (minDate > selectedDate) {
      return true;
    }
  }
  if (maxDate) {
    if (maxDate < selectedDate) {
      return true;
    }
  }

  if (disableDatesArr) {
    return convertDateOrStringArrToStringArr(disableDatesArr).includes(formatDate(selectedDate))
  }

  if(onlyShowDateArr) {
    //disable all dates and only show dates in 'only' prop array
    return !convertDateOrStringArrToStringArr(onlyShowDateArr).includes(formatDate(selectedDate))
  }
}

function convertDateOrStringArrToStringArr(arr) {
  return arr.map(a => {
    if(typeof a === 'string'){
      return a;
    }
    if(a instanceof Date) {
      return  a.toISOString().split('T')[0];
    }
  })
}

function formatDate(date) {
  return useDateFormat(date, 'YYYY-MM-DD').value
}

function emitClickedDate() {
  emit('update:modelValue', selectedIsoDate.value)
  emit('select', {
    ymd: selectedIsoDate.value,
    date: selectedDate.value
  })
  showDatePicker.value = false
}

function onDateClick(dateInNumber){
  selectedDate.value = new Date(year.value,month.value,dateInNumber);
  emitClickedDate()
}

function toggleDatepicker() {
  showDatePicker.value = true
}

function onTxtInput(e){
  if(e.target)
    setDate(e.target.value)
}

function setDate(value){
  if (value && value.length === 10)
    selectedDate.value = parseDate(value);
  else
    selectedDate.value = '';

  emitClickedDate()
}

const computeWeekStartClass = computed(() => {
  return new Date(year.value, month.value, 1).getDay() + 1
})

/*Other variants are not getting rendered, According to tailwind we cannot construct dynamic tailwind classes
*if we want to include these variants then we will need to add pattern or classes to safelist array in tailwind.config.js
*
* workaround for this is to create variant-util.ts
*
* */
const computeOnDateHover = computed(() => {
  return `transition h-8 w-8 ease-in-out duration-75 rounded-full cursor-pointer ${onHoverVariant(props.variant)}`;
  // if (props.variant === 'primary' || props.variant === 'warning' || props.variant === 'plain') {
  //   return `transition ease-in-out duration-75 h-8 w-8 rounded-full cursor-pointer ${onHoverVariant(props.variant)}`
  // } else {
  //   return `transition h-8 w-8 ease-in-out duration-75 rounded-full cursor-pointer  ${onHoverVariant(props.variant)}`;
  // }
});

const computeWidthSizeStyles = computed(() => {
  const classLst = ['w-max'];
  if(pickerSize.value === 'sm'){
    classLst.push('min-w-[20%]')
  }
   if(pickerSize.value === 'md'){
    classLst.push('min-w-[50%]')
  }else if(pickerSize.value === 'lg'){
    classLst.push('min-w-[65%]')
  }
  return classLst;
})

function init(value){
  if(value) {
    selectedDate.value = value instanceof Date ? value : parseDate(value)
    emit('update:modelValue', selectedIsoDate.value)
  }
}

const parseDate = (dateString) => {
  const dateSplit = dateString.split("-");
  const year = dateSplit[0];
  const month = dateSplit[1];
  const date = dateSplit[2];
  return new Date(parseInt(year), month - 1, parseInt(date))
}

watch(selectedDate, (value) => {
  let m, y

  if(value) {
    m = value.getMonth()
    y = value.getFullYear()
  }

  month.value = m || new Date().getMonth()
  year.value = y || new Date().getFullYear()
})
watch(() => props.modelValue, (value) => {
  init(value)
})


onMounted(()=>{
  init(props.modelValue)
})




</script>
