<template>
  <UPopover v-model:open="isOpen" @update:open="onUpdateOpen">
    <UButton
      :id="id"
      class="w-full"
      :ui="{ base: `hover:bg-[unset] active:bg-[unset] ${modelValue ? '' : ' text-dimmed'}` }"
      :name="name"
      :color="color"
      :icon="appConfig.ui.icons.calendar"
      variant="outline"
      :disabled="disabled"
      :size="size"
      v-bind="ariaAttrs"
    >
      <span class="truncate">{{ textValue }}</span>

      <template #trailing>
        <UButton
          :icon="appConfig.ui.icons.close"
          as="div"
          variant="link"
          size="sm"
          color="neutral"
          class="p-0 ms-auto"
          @click.prevent.stop="$emit('update:modelValue', void 0)"
        />
      </template>
    </UButton>

    <template #content>
      <UCalendar
        v-bind="calendarProps"
        :model-value="calendarValue"
        :range="range"
        :disabled="disabled"
        :prevent-deselect="false"
        :ui="{ root: 'p-2' }"
        :max-value="calendarMaxValue"
        :min-value="calendarMinValue"
        @update:model-value="handleCalendarUpdate($event)"
      />

      <template v-if="withTime">
        <USeparator
          orientation="horizontal"
        />

        <div class="p-2 flex justify-between items-center gap-2">
          <div class="text-sm">
            Время
          </div>

          <UInputTime
            v-if="!range"
            :model-value="calendarValue"
            :disabled="disabled"
            size="sm"
            @update:model-value="handleTimeUpdate($event)"
          />
          <div v-else class="flex gap-2">
            <UInputTime
              :model-value="calendarValue?.start"
              :disabled="disabled || !calendarValue?.start"
              size="sm"
              @update:model-value="handleTimeUpdate($event, 'start')"
            />

            <span class="text-sm text-dimmed self-center">—</span>

            <UInputTime
              :model-value="calendarValue?.end"
              :disabled="disabled || !calendarValue?.end"
              size="sm"
              @update:model-value="handleTimeUpdate($event, 'end')"
            />
          </div>
        </div>
      </template>
    </template>
  </UPopover>
</template>

<script>
import { useAppConfig, useFormField } from "#imports";
import { CalendarDateTime, getLocalTimeZone } from "@internationalized/date";
import { reactiveOmit } from "@vueuse/core";
import { useForwardProps } from "reka-ui";
import { computed, ref } from "vue";
import { formatDate, formatServerDateTime } from "../utils";
function createCalendarDate(value, withTime = true) {
  const date = new Date(value);
  if (withTime) {
    return new CalendarDateTime(date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
  }
  return new CalendarDateTime(date.getFullYear(), date.getMonth() + 1, date.getDate());
}
</script>

<script setup>
const props = defineProps({
  modelValue: { type: null, required: true },
  id: { type: String, required: false },
  name: { type: String, required: false },
  withTime: { type: Boolean, required: false, default: true },
  minValue: { type: String, required: false },
  maxValue: { type: String, required: false },
  as: { type: null, required: false },
  nextYearIcon: { type: null, required: false },
  nextYear: { type: Object, required: false },
  nextMonthIcon: { type: null, required: false },
  nextMonth: { type: Object, required: false },
  prevYearIcon: { type: null, required: false },
  prevYear: { type: Object, required: false },
  prevMonthIcon: { type: null, required: false },
  prevMonth: { type: Object, required: false },
  color: { type: null, required: false, default: "neutral" },
  variant: { type: null, required: false },
  size: { type: null, required: false },
  range: { type: Boolean, required: false },
  monthControls: { type: Boolean, required: false },
  yearControls: { type: Boolean, required: false },
  defaultValue: { type: null, required: false },
  class: { type: null, required: false },
  ui: { type: null, required: false },
  defaultPlaceholder: { type: null, required: false },
  placeholder: { type: null, required: false },
  allowNonContiguousRanges: { type: Boolean, required: false },
  pagedNavigation: { type: Boolean, required: false },
  preventDeselect: { type: Boolean, required: false },
  maximumDays: { type: Number, required: false },
  weekStartsOn: { type: Number, required: false },
  weekdayFormat: { type: String, required: false },
  fixedWeeks: { type: Boolean, required: false },
  numberOfMonths: { type: Number, required: false },
  disabled: { type: Boolean, required: false },
  readonly: { type: Boolean, required: false },
  initialFocus: { type: Boolean, required: false },
  isDateDisabled: { type: Function, required: false },
  isDateUnavailable: { type: Function, required: false },
  isDateHighlightable: { type: Function, required: false },
  nextPage: { type: Function, required: false },
  prevPage: { type: Function, required: false },
  disableDaysOutsideCurrentView: { type: Boolean, required: false },
  fixedDate: { type: String, required: false }
});
const emit = defineEmits(["update:modelValue", "change", "blur", "focus"]);
const appConfig = useAppConfig();
const calendarProps = useForwardProps(reactiveOmit(props, "modelValue", "id", "name", "withTime", "minValue", "maxValue"));
const {
  id,
  name,
  color,
  disabled,
  ariaAttrs,
  size,
  emitFormBlur,
  emitFormChange,
  emitFormFocus,
  emitFormInput
} = useFormField(props);
const isOpen = ref(false);
function isRange() {
  return !!props.range;
}
const textValue = computed(() => {
  if (!props.modelValue) {
    return "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u0430\u0442\u0443";
  }
  if (!isRange(props.modelValue)) {
    return formatDate(props.modelValue);
  }
  return `${formatDate(props.modelValue.start)} - ${formatDate(props.modelValue.end)}`;
});
const calendarValue = computed(() => {
  if (!props.modelValue) {
    return void 0;
  }
  if (!isRange(props.modelValue)) {
    return createCalendarDate(props.modelValue);
  }
  return {
    start: createCalendarDate(props.modelValue.start),
    end: createCalendarDate(props.modelValue.end)
  };
});
const calendarMinValue = computed(
  () => props.minValue ? createCalendarDate(props.minValue, false) : void 0
);
const calendarMaxValue = computed(
  () => props.maxValue ? createCalendarDate(props.maxValue, false) : void 0
);
function onUpdateOpen(value) {
  if (!value) {
    const event = new FocusEvent("blur");
    emit("blur", event);
    emitFormBlur();
  } else {
    const event = new FocusEvent("focus");
    emit("focus", event);
    emitFormFocus();
  }
}
function onUpdate(value) {
  emit("update:modelValue", value);
  emit("change", new Event("change", { target: { value } }));
  emitFormChange();
  emitFormInput();
}
function handleCalendarUpdate(calendarValue2, setInitialTime = true) {
  if (!calendarValue2) {
    onUpdate(void 0);
    return;
  }
  if (isRange(calendarValue2) && (!calendarValue2.start || !calendarValue2.end)) {
    return;
  }
  if (isRange(calendarValue2)) {
    const endDate = calendarValue2.end.toDate(getLocalTimeZone());
    setInitialTime && endDate.setHours(23, 59, 59, 999);
    const value = {
      start: formatServerDateTime(calendarValue2.start.toDate(getLocalTimeZone())),
      end: formatServerDateTime(endDate)
    };
    onUpdate(value);
  } else {
    onUpdate(formatServerDateTime(calendarValue2.toDate(getLocalTimeZone())));
  }
}
function handleTimeUpdate(timeValue, type) {
  if (!timeValue) {
    return;
  }
  if (!type) {
    return handleCalendarUpdate(timeValue);
  }
  const otherType = type === "start" ? "end" : "start";
  const value = {
    [type]: timeValue,
    [otherType]: calendarValue.value?.[otherType]
  };
  handleCalendarUpdate(value, false);
}
</script>
