<template>
  <div>
    <div class="flex w-full justify-center mb-2">
      <VcInput
        v-model="selectedDuration"
        dynamic-error-space
        max-width="100%"
        class="w-1/3"
        type="number"
        :color="color"
      />
      <div class="w-0.5" />
      <VcDropdown
        :model-value="selectedRelative"
        :options="relativeOptions"
        :config="configOptions"
        @option-select="onOptionSelect"
      />
    </div>
    <VcInput
      :model-value="`${$tVU.t('date.picker.end.date')} ${calculatedDate}`"
      dynamic-error-space
      max-width="100%"
      class="w-full"
      readonly
      :color="color"
    />
    <div class="mt-2 flex justify-end">
      <VcButton
        type="default"
        size="middle"
        icon="vc-icon-Save"
        :disabled="selectDateButtonDisabled"
        @click="selectDate"
      >
        {{ $tVU.t('general.apply') }}
      </VcButton>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType } from 'vue'
import VcInput from '@/components/VcInput/VcInput.vue'
import VcDropdown from '@/components/VcDropdown/VcDropdown.vue'
import VcButton from '@/components/VcButton/VcButton.vue'
import { add, sub } from 'date-fns/fp'
import color from '@/mixins/input/color.mixin'

declare type relativeOptionType = {
  key: string,
  label: string,
  datePart: string,
  action: typeof add
}

const RELATIVE_OPTIONS_ACTIONS: {
  [key: string]: typeof add } = {
    ADD: add,
    SUB: sub
  }

const RELATIVE_DATE_PARTS = ['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds']

const DATE_PARTS_TRANSLATIONS: {
  [key: string]: string } = {
    years: 'date.picker.parts.years',
    months: 'date.picker.parts.months',
    weeks: 'date.picker.parts.weeks',
    days: 'date.picker.parts.days',
    hours: 'date.picker.parts.hours',
    minutes: 'date.picker.parts.minutes',
    seconds: 'date.picker.parts.seconds'
  }

export default defineComponent({
  name: 'ExtendedDatetimeRangePickerRelative',
  components: { VcInput, VcDropdown, VcButton },
  mixins: [color],
  props: {
    modelValue: {
      type: Date as PropType<Date | null>,
      default: null
    },
    minDate: {
      type: [Date, String] as PropType<Date | string | null>,
      default: null
    },
    maxDate: {
      type: [Date, String] as PropType<Date | string | null>,
      default: null
    },
    relativeDateParts: {
      type: Array as PropType<string[]>,
      default: () => [...RELATIVE_DATE_PARTS]
    }
  },
  emits: ['update:modelValue'],
  data: () => ({
    calculatedDate: new Date() as Date,
    selectedRelative: null as relativeOptionType | null,
    selectedDuration: 0,
    configOptions: {
      labelKey: 'label',
      valueKey: 'key'
    }
  }),
  computed: {
    selectDateButtonDisabled (): boolean {
      return !this.isDateValid
    },
    isDateValid (): boolean {
      if (this.maxDate === null && this.minDate === null) return true

      if (this.maxDate !== null) {
        return new Date(this.maxDate).getTime() > new Date(this.calculatedDate).getTime()
      }

      if (this.minDate !== null) {
        return new Date(this.minDate).getTime() < new Date(this.calculatedDate).getTime()
      }

      return true
    },
    relativeOptions (): relativeOptionType[] {
      return Object.keys(RELATIVE_OPTIONS_ACTIONS).map(action => {
        return this.relativeDateParts.map(datePart => {
          return {
            key: `${action}-${datePart}`,
            label: `${this.$tVU.t(DATE_PARTS_TRANSLATIONS[datePart])} ${action === 'ADD' ? this.$tVU.t('date.picker.from.now') : this.$tVU.t('date.picker.ago')}`,
            datePart: datePart,
            action: RELATIVE_OPTIONS_ACTIONS[action]
          }
        })
      }).flat() as relativeOptionType[]
    }
  },
  watch: {
    selectedDuration () {
      this.calculateDate()
    },
    selectedRelative: {
      deep: true,
      handler () {
        this.calculateDate()
      }
    },
    modelValue: {
      immediate: true,
      deep: true,
      handler (val) {
        if (val) {
          this.calculatedDate = val
        }
      }
    }
  },
  methods: {
    calculateDate (): void {
      if (this.selectedRelative !== null) {
        this.calculatedDate = this.selectedRelative.action(
          {
            [this.selectedRelative.datePart]: this.selectedDuration
          },
          new Date()
        )
      }
    },
    onOptionSelect (val: relativeOptionType): void {
      this.selectedRelative = val
    },
    selectDate (): void {
      this.$emit('update:modelValue', this.calculatedDate)
    }
  }
})
</script>
