<template>
  <div class="cpDatepicker">
    <cp-input
      v-show="!isInline"
      :id="datePickerReferenceId"
      class="cpDatepicker__input"
      :disabled="isDisabled"
      :error-message="errorMessage"
      :is-invalid="isError"
      :label="label"
      :model-value="inputComputedValue"
      :placeholder="placeholder"
      type="text"
    />
    <core-datepicker
      class="cpDatepicker__datepicker"
      :class="{ 'cpDatepicker__datepicker--isInline': isInline }"
      :close-after-select="closeAfterSelect"
      :date-one="dateOne"
      :date-two="dateTwo"
      :inline="isInline"
      :locale="locale"
      :max-date="maxDate"
      :min-date="computedMinDate"
      :mode="mode"
      :months-to-show="numberOfMonths"
      :trigger-element-id="datePickerReferenceId"
      @closed="() => (isDisabled = false)"
      @date-one-selected="onDateOneSelected"
      @date-two-selected="onDateTwoSelected"
      @opened="() => (isDisabled = true)"
    />
  </div>
</template>

<script setup lang="ts">
import { DateTime } from 'luxon'
import { computed, ref, useId, watch } from 'vue'

import CpInput from '@/components/CpInput.vue'

import { formatDates } from '@/helpers'
import CoreDatepicker from '@/libs/CoreDatepicker.vue'

type DatepickerMode = 'range' | 'single'

interface Props {
  allowPastDates?: boolean
  closeAfterSelect?: boolean
  errorMessage?: string
  initDateOne?: string
  initDateTwo?: string
  inputValue?: string
  isError?: boolean
  isInline?: boolean
  label?: string
  locale?: string
  maxDate?: string | Date
  minDate?: string | Date
  mode?: DatepickerMode
  placeholder?: string
  singleMonth?: boolean
  triggerElementId?: string
}

interface Emits {
  (e: 'dates', dates: string[]): void
}

const props = withDefaults(defineProps<Props>(), {
  triggerElementId: '',
  mode: 'single',
  closeAfterSelect: true,
  label: '',
  placeholder: 'Select a date',
  inputValue: '',
  isError: false,
  errorMessage: '',
  initDateOne: '',
  initDateTwo: '',
  minDate: () => DateTime.local().toISODate(),
  maxDate: '',
  allowPastDates: false,
  isInline: false,
  singleMonth: false,
  locale: () => navigator.language,
})

const emit = defineEmits<Emits>()

const humanFormat = 'EEE DD'
const dateOne = ref(props.initDateOne || '')
const dateTwo = ref(props.mode === 'range' ? props.initDateTwo : '')
const isDisabled = ref(false)
const datePickerReferenceId = ref(props.triggerElementId || useId())

const inputComputedValue = computed(() => {
  if (props.inputValue) return props.inputValue

  return formatDates({
    dateOne: dateOne.value,
    dateTwo: dateTwo.value,
    format: humanFormat,
    locale: props.locale,
  })
})

const numberOfMonths = computed(() => {
  return props.singleMonth ? 1 : 2
})

const computedMinDate = computed(() => {
  return props.allowPastDates ? '' : props.minDate
})

const onDateOneSelected = (date: string) => selectDate('dateOne', date)
const onDateTwoSelected = (date: string) => selectDate('dateTwo', date)

const selectDate = (dateType: 'dateOne' | 'dateTwo', dateValue: string): void => {
  if (dateType === 'dateOne') {
    dateOne.value = dateValue
  } else {
    dateTwo.value = dateValue
  }
  emit('dates', [dateOne.value, ...(dateTwo.value ? [dateTwo.value] : [])])
}

const updateDateValue = (date: 'dateOne' | 'dateTwo', newValue: string, oldValue: string): void => {
  if (newValue !== oldValue) {
    if (date === 'dateOne') {
      dateOne.value = newValue
    } else {
      dateTwo.value = newValue
    }
  }
}

watch(
  () => props.initDateOne,
  (newValue, oldValue) => {
    updateDateValue('dateOne', newValue, oldValue)
  },
)

watch(
  () => props.initDateTwo,
  (newValue, oldValue) => {
    updateDateValue('dateTwo', newValue, oldValue)
  },
)
</script>

<style lang="scss">
.cpDatepicker {
  // Opening transition layout adaptation
  .asd__fade-enter-from {
    transform: translateX(-50%) scale(0.8);
  }

  .asd__fade-enter-to {
    transform: translateX(-50%) scale(1);
  }

  &__input input:disabled {
    background-color: var(--cp-background-primary);
  }

  &__datepicker {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
  }

  &__datepicker:not(&__datepicker--isInline) {
    margin-top: var(--cp-dimensions-2_5);
  }

  @media (min-width: 350px) {
    position: relative;
  }

  @media (max-width: 767px) and (min-width: 350px) {
    &__datepicker {
      right: 0;
      left: 0;
      transform: initial;
    }

    &__datepicker:not(&__datepicker--isInline) {
      margin-top: var(--cp-spacing-xl);
    }

    // Opening transition layout adaptation
    .asd__fade-enter-from {
      transform: scale(0.8);
    }

    .asd__fade-enter-to {
      transform: scale(1);
    }
  }
}
</style>
