"use client"
import { parseDate } from "@internationalized/date"
import { useState } from "react"
import { DateInput, DatePicker, Group } from "react-aria-components"
import { useController, useFormContext, useWatch } from "react-hook-form"
import { useIntl } from "react-intl"

import { dt } from "@/lib/dt"

import Select from "@/components/TempDesignSystem/Select"
import { rangeArray } from "@/utils/rangeArray"

import { DateName } from "./date"

import styles from "./date.module.css"

import type { Key } from "react-aria-components"

import type { DateProps } from "./date"

export default function DateSelect({ name, registerOptions = {} }: DateProps) {
  const intl = useIntl()
  const d = useWatch({ name })
  const { control, setValue } = useFormContext()
  const { field } = useController({
    control,
    name,
    rules: registerOptions,
  })

  const [dateSegments, setDateSegment] = useState<{
    year: number | null
    month: number | null
    date: number | null
    daysInMonth: number
  }>({
    year: null,
    month: null,
    date: null,
    daysInMonth: 31,
  })

  const currentYear = new Date().getFullYear()
  const months = rangeArray(1, 12).map((month) => ({
    value: month,
    label: `${month}`,
  }))
  const years = rangeArray(1900, currentYear - 18)
    .reverse()
    .map((year) => ({ value: year, label: `${year}` }))

  function createOnSelect(selector: DateName) {
    /**
     * Months are 0 index based and therefore we
     * must subtract by 1 to get the selected month
     */
    return (select: Key) => {
      const value =
        selector === DateName.month ? Number(select) - 1 : Number(select)
      const newSegments = { ...dateSegments, [selector]: value }

      /**
       * Update daysInMonth when year or month changes
       * to ensure the user can't select a date that doesn't exist.
       */
      if (selector === DateName.year || selector === DateName.month) {
        const year = selector === DateName.year ? value : newSegments.year
        const month = selector === DateName.month ? value : newSegments.month
        if (year !== null && month !== null) {
          newSegments.daysInMonth = dt().year(year).month(month).daysInMonth()
        }
      }

      if (Object.values(newSegments).every((val) => val !== null)) {
        const newDate = dt()
          .utc()
          .set("year", newSegments.year!)
          .set("month", newSegments.month!)
          .set("date", Math.min(newSegments.date!, newSegments.daysInMonth))

        setValue(name, newDate.format("YYYY-MM-DD"))
      }
      setDateSegment(newSegments)
    }
  }

  const dayLabel = intl.formatMessage({ id: "Day" })
  const monthLabel = intl.formatMessage({ id: "Month" })
  const yearLabel = intl.formatMessage({ id: "Year" })

  let dateValue = null
  try {
    /**
     * parseDate throws when its not a valid
     * date, but we can't check isNan since
     * we recieve the date as "1999-01-01"
     */
    dateValue = dt(d).isValid() ? parseDate(d) : null
  } catch (error) {
    console.error(error)
  }

  return (
    <DatePicker
      aria-label={intl.formatMessage({ id: "Select date of birth" })}
      isRequired={!!registerOptions.required}
      name={name}
      ref={field.ref}
      value={dateValue}
      data-testid={name}
    >
      <Group>
        <DateInput className={styles.container}>
          {(segment) => {
            switch (segment.type) {
              case "day":
                const maxDays = dateSegments.daysInMonth
                const days = rangeArray(1, maxDays).map((day) => ({
                  value: day,
                  label: `${day}`,
                }))
                return (
                  <div className={styles.day}>
                    <Select
                      aria-label={dayLabel}
                      items={days}
                      label={dayLabel}
                      name={DateName.date}
                      onSelect={createOnSelect(DateName.date)}
                      placeholder="DD"
                      required
                      tabIndex={3}
                      defaultSelectedKey={
                        segment.isPlaceholder ? undefined : segment.value
                      }
                    />
                  </div>
                )
              case "month":
                return (
                  <div className={styles.month}>
                    <Select
                      aria-label={monthLabel}
                      items={months}
                      label={monthLabel}
                      name={DateName.month}
                      onSelect={createOnSelect(DateName.month)}
                      placeholder="MM"
                      required
                      tabIndex={2}
                      defaultSelectedKey={
                        segment.isPlaceholder ? undefined : segment.value
                      }
                    />
                  </div>
                )
              case "year":
                return (
                  <div className={styles.year}>
                    <Select
                      aria-label={yearLabel}
                      items={years}
                      label={yearLabel}
                      name={DateName.year}
                      onSelect={createOnSelect(DateName.year)}
                      placeholder="YYYY"
                      required
                      tabIndex={1}
                      defaultSelectedKey={
                        segment.isPlaceholder ? undefined : segment.value
                      }
                    />
                  </div>
                )
              default:
                /** DateInput forces return of ReactElement */
                return <></>
            }
          }}
        </DateInput>
      </Group>
    </DatePicker>
  )
}
