<template>
  <CalendarField
    :id="id"
    :display-value="displayValue"
    :sync-to="validRange?.start ?? null"
    :name="name"
    :label="label"
    :placeholder="placeholder"
    :required="required"
    :disabled="disabled"
    :readonly="readonly"
    :min="min"
    :max="max"
    :hint="hint"
    :error="error"
    :success="success"
    :clearable="clearable"
    :input-class="inputClass"
    :label-class="labelClass"
    :group-class="groupClass"
    v-bind="$attrs"
    @clear="onClear"
    @close="onClose"
  >
    <template #default="{ currentMonth, currentYear, close }">
      <MonthGrid
        :month="currentMonth"
        :year="currentYear"
        :range-start="rangeStart"
        :range-end="rangeEnd"
        :preview-date="previewDate"
        :min="min"
        :max="max"
        @select="(iso) => onSelectDay(iso, close)"
        @hover="onHover"
      />
    </template>
  </CalendarField>
</template>

<script setup lang="ts">
import {computed, ref} from 'vue'
import CalendarField from './internal/CalendarField.vue'
import MonthGrid from './internal/MonthGrid.vue'
import {formatIsoToDisplay, isValidIso} from './composables/dateFormat'
import {normalizeRange, type DateRangeValue} from './composables/dateRange'

defineOptions({name: 'MalioDateRange', inheritAttrs: false})

const props = withDefaults(
  defineProps<{
    id?: string
    name?: string
    label?: string
    modelValue?: DateRangeValue | null
    placeholder?: string
    required?: boolean
    disabled?: boolean
    readonly?: boolean
    hint?: string
    error?: string
    success?: string
    min?: string
    max?: string
    clearable?: boolean
    inputClass?: string
    labelClass?: string
    groupClass?: string
  }>(),
  {
    id: '',
    name: '',
    label: '',
    modelValue: undefined,
    placeholder: 'JJ/MM/AAAA',
    required: false,
    disabled: false,
    readonly: false,
    hint: '',
    error: '',
    success: '',
    min: undefined,
    max: undefined,
    clearable: true,
    inputClass: '',
    labelClass: '',
    groupClass: '',
  },
)

const emit = defineEmits<{(e: 'update:modelValue', value: DateRangeValue | null): void}>()

const pendingStart = ref<string | null>(null)
const hoverDate = ref<string | null>(null)
const isSelecting = computed(() => pendingStart.value !== null)

const validRange = computed<DateRangeValue | null>(() => {
  const v = props.modelValue
  if (v && isValidIso(v.start) && isValidIso(v.end)) return v
  return null
})

const rangeStart = computed(() =>
  isSelecting.value ? pendingStart.value : (validRange.value?.start ?? null),
)
const rangeEnd = computed(() =>
  isSelecting.value ? null : (validRange.value?.end ?? null),
)
const previewDate = computed(() => (isSelecting.value ? hoverDate.value : null))

const displayValue = computed(() => {
  if (isSelecting.value || !validRange.value) return ''
  return `${formatIsoToDisplay(validRange.value.start)} - ${formatIsoToDisplay(validRange.value.end)}`
})

const onSelectDay = (iso: string, close: () => void) => {
  if (pendingStart.value === null) {
    pendingStart.value = iso
    hoverDate.value = null
    return
  }
  emit('update:modelValue', normalizeRange(pendingStart.value, iso))
  pendingStart.value = null
  hoverDate.value = null
  close()
}

const onHover = (iso: string | null) => {
  if (isSelecting.value) hoverDate.value = iso
}

const onClose = () => {
  pendingStart.value = null
  hoverDate.value = null
}

const onClear = () => {
  emit('update:modelValue', null)
  pendingStart.value = null
  hoverDate.value = null
}
</script>
