<script setup lang="ts">
/**
 * Props-driven date picker composition. Popover trigger Button shows the
 * formatted current date; the popover hosts the shadcn `Calendar`.
 * Values round-trip as ISO date strings (`yyyy-MM-dd` by default).
 *
 *   <DatePicker v-model="startsAt" label="Starts at" />
 *
 * Self-contained — no Pinia / store coupling. Composes `FieldFrame` for
 * label / helpText / errors chrome.
 */
import { computed, ref } from "vue"
import { Calendar as CalendarIcon } from "@lucide/vue"
import {
  CalendarDate,
  parseDate,
  type DateValue,
} from "@internationalized/date"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import { FieldFrame } from "@/components/ui/field-frame"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"
import { cn } from "@/lib/utils"

export interface DatePickerProps {
  modelValue?: string | null
  id?: string
  name?: string
  label?: string
  hideLabel?: boolean
  placeholder?: string
  required?: boolean
  readonly?: boolean
  disabled?: boolean
  helpText?: string
  errors?: string[]
  /** ISO date string, e.g. "2024-06-10" */
  minDate?: string
  /** ISO date string, e.g. "2024-06-25" */
  maxDate?: string
  /** Display format. Default `yyyy-MM-dd`. */
  format?: string
}

const props = withDefaults(defineProps<DatePickerProps>(), {
  errors: () => [],
})

const model = defineModel<string | null>("modelValue")

const open = ref(false)

const calendarValue = computed<DateValue | undefined>(() => {
  const iso = model.value
  if (!iso) {
    return undefined
  }
  return safeParseDate(iso)
})

const min = computed<DateValue | undefined>(() =>
  props.minDate ? safeParseDate(props.minDate) : undefined,
)

const max = computed<DateValue | undefined>(() =>
  props.maxDate ? safeParseDate(props.maxDate) : undefined,
)

const displayValue = computed<string>(() => {
  const iso = model.value
  if (!iso) {
    return ""
  }
  return formatDate(iso, props.format)
})

function safeParseDate(value: string): DateValue | undefined {
  try {
    // Accept full ISO datetime ("2024-06-15T00:00:00Z") or date-only.
    const dateOnly = value.includes("T") ? value.slice(0, 10) : value
    return parseDate(dateOnly)
  } catch {
    return undefined
  }
}

function formatDate(iso: string, format?: string): string {
  const parsed = safeParseDate(iso)
  if (!parsed) {
    return iso
  }
  if (!format || format === "yyyy-MM-dd") {
    return parsed.toString()
  }
  const date = new Date(parsed.year, parsed.month - 1, parsed.day)
  try {
    return new Intl.DateTimeFormat(undefined, {
      year: "numeric",
      month: "short",
      day: "2-digit",
    }).format(date)
  } catch {
    return parsed.toString()
  }
}

function onSelect(value: DateValue | undefined): void {
  if (!value) {
    model.value = null
    return
  }
  const calendar =
    value instanceof CalendarDate
      ? value
      : new CalendarDate(value.year, value.month, value.day)
  model.value = calendar.toString()
  open.value = false
}
</script>

<template>
  <FieldFrame
    :label="label"
    :required="required"
    :hide-label="hideLabel"
    :for="id"
    :help-text="helpText"
    :errors="errors"
  >
    <Popover v-model:open="open">
      <PopoverTrigger as-child>
        <Button
          type="button"
          variant="outline"
          :disabled="disabled"
          :class="
            cn(
              'w-full justify-start text-left font-normal',
              !model && 'text-muted-foreground',
            )
          "
          :data-element-name="name ?? undefined"
          :data-readonly="readonly || undefined"
        >
          <CalendarIcon class="mr-2 size-4" />
          <span>{{ displayValue || placeholder || "Pick a date" }}</span>
        </Button>
      </PopoverTrigger>
      <PopoverContent class="w-auto p-0">
        <Calendar
          :model-value="calendarValue"
          :min-value="min"
          :max-value="max"
          :placeholder="calendarValue ?? min ?? max"
          @update:model-value="onSelect"
        />
      </PopoverContent>
    </Popover>
  </FieldFrame>
</template>
