"use client"
import { useCallback, useEffect, useRef, useState } from "react"
import { FocusScope, useOverlay } from "react-aria"
import { Button as ButtonRAC } from "react-aria-components"
import { useFormContext, useWatch } from "react-hook-form"
import { useIntl } from "react-intl"
import { useMediaQuery } from "usehooks-ts"

import { longDateFormat } from "@scandic-hotels/common/constants/dateFormats"
import { dt } from "@scandic-hotels/common/dt"
import { useScrollLock } from "@scandic-hotels/common/hooks/useScrollLock"
import { Typography } from "@scandic-hotels/design-system/Typography"

import useLang from "../../../hooks/useLang"
import DatePickerRangeDesktop from "./Range/Desktop"
import DatePickerRangeMobile from "./Range/Mobile"

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

import type { DateRange } from "react-day-picker"

type DatePickerFormProps = {
  ariaLabelledBy?: string
  name?: string
}
export default function DatePickerForm({
  ariaLabelledBy,
  name = "date",
}: DatePickerFormProps) {
  const lang = useLang()

  const checkIsDesktop = useMediaQuery("(min-width: 1367px)")
  const [isDesktop, setIsDesktop] = useState(true)
  const { lockScroll, unlockScroll } = useScrollLock({
    autoLock: false,
  })
  const [isOpen, setIsOpen] = useState(false)
  const selectedDate = useWatch({ name })
  const { setValue } = useFormContext()
  const ref = useRef<HTMLDivElement | null>(null)
  const close = useCallback(() => {
    if (!selectedDate.toDate) {
      setValue(
        name,
        {
          fromDate: selectedDate.fromDate,
          toDate: dt(selectedDate.fromDate).add(1, "day").format("YYYY-MM-DD"),
        },
        { shouldDirty: true }
      )
    }
    setIsOpen(false)
    unlockScroll()
  }, [name, setValue, selectedDate, unlockScroll])

  const { overlayProps, underlayProps } = useOverlay(
    {
      isOpen,
      onClose: () => {
        close()
      },
      isDismissable: true,
    },
    ref
  )

  function handleSelectDate(
    _nextRange: DateRange | undefined,
    selectedDay: Date
  ) {
    const now = dt()
    const dateClicked = dt(selectedDay)
    const dateClickedFormatted = dateClicked.format("YYYY-MM-DD")
    /* check if selected date is not before todays date,
     which happens when "Enter" key is pressed in any other input field of the form */
    if (!dateClicked.isBefore(now, "day")) {
      // Handle form value updates based on the requirements
      if (selectedDate.fromDate && selectedDate.toDate) {
        // Both dates were previously selected, starting fresh with new date
        setValue(
          name,
          {
            fromDate: dateClickedFormatted,
            toDate: undefined,
          },
          { shouldDirty: true }
        )
      } else if (selectedDate.fromDate && !selectedDate.toDate) {
        // If the selected day is the same as the first date, we don't need to update the form value
        if (dateClicked.isSame(selectedDate.fromDate)) {
          return
        }
        // We're selecting the second date
        if (dateClicked.isBefore(selectedDate.fromDate)) {
          // If second selected date is before first date, swap them
          setValue(
            name,
            {
              fromDate: dateClickedFormatted,
              toDate: selectedDate.fromDate,
            },
            { shouldDirty: true }
          )
        } else {
          // If second selected date is after first date, keep order
          setValue(
            name,
            {
              fromDate: selectedDate.fromDate,
              toDate: dateClickedFormatted,
            },
            { shouldDirty: true }
          )
        }
      }
    }
  }

  useEffect(() => {
    setIsDesktop(checkIsDesktop)
  }, [checkIsDesktop])

  const selectedFromDate = dt(selectedDate.fromDate)
    .locale(lang)
    .format(longDateFormat[lang])
  const selectedToDate = !!selectedDate.toDate
    ? dt(selectedDate.toDate).locale(lang).format(longDateFormat[lang])
    : ""

  return isDesktop ? (
    <div className={styles.datePicker}>
      <Trigger
        ariaLabelledBy={ariaLabelledBy}
        onPress={() => {
          setIsOpen((prev) => !prev)
        }}
        selectedFromDate={selectedFromDate}
        selectedToDate={selectedToDate}
      />
      {isOpen && (
        <div {...underlayProps}>
          <FocusScope contain restoreFocus autoFocus>
            <div
              {...overlayProps}
              ref={ref}
              className={styles.pickerContainer}
              data-datepicker-open={isOpen}
            >
              <DatePickerRangeDesktop
                close={close}
                handleOnSelect={handleSelectDate}
                // DayPicker lib needs Daterange in form as below to show appropriate UI
                selectedRange={{
                  from: dt(selectedDate.fromDate).toDate(),
                  to: selectedDate.toDate
                    ? dt(selectedDate.toDate).toDate()
                    : undefined,
                }}
              />
            </div>
          </FocusScope>
        </div>
      )}
    </div>
  ) : (
    <div className={styles.datePicker}>
      <Trigger
        ariaLabelledBy={ariaLabelledBy}
        onPress={() => {
          setIsOpen((prev) => !prev)
          if (!isOpen) {
            lockScroll()
          } else {
            unlockScroll()
          }
        }}
        selectedFromDate={selectedFromDate}
        selectedToDate={selectedToDate}
      />
      {isOpen && (
        <div {...underlayProps}>
          <FocusScope contain restoreFocus autoFocus>
            <div
              {...overlayProps}
              ref={ref}
              className={styles.pickerContainer}
              data-datepicker-open={isOpen}
            >
              <DatePickerRangeMobile
                close={close}
                handleOnSelect={handleSelectDate}
                // DayPicker lib needs Daterange in form as below to show appropriate UI
                selectedRange={{
                  from: dt(selectedDate.fromDate).toDate(),
                  to: selectedDate.toDate
                    ? dt(selectedDate.toDate).toDate()
                    : undefined,
                }}
              />
            </div>
          </FocusScope>
        </div>
      )}
    </div>
  )
}

function Trigger({
  onPress,
  selectedFromDate,
  selectedToDate,
  ariaLabelledBy,
}: {
  onPress?: () => void
  selectedFromDate: string
  selectedToDate: string
  ariaLabelledBy?: string
}) {
  const intl = useIntl()
  const { register } = useFormContext()

  const triggerText = intl.formatMessage(
    {
      id: "booking.selectedDateRange",
      defaultMessage: "{selectedFromDate} – {selectedToDate}",
    },
    {
      selectedFromDate,
      selectedToDate,
    }
  )
  return (
    <>
      <Typography variant="Body/Paragraph/mdRegular">
        <ButtonRAC
          className={styles.triggerButton}
          onPress={onPress}
          type="button"
          aria-labelledby={ariaLabelledBy}
        >
          {triggerText}
        </ButtonRAC>
      </Typography>
      <input {...register("date.fromDate")} type="hidden" />
      <input {...register("date.toDate")} type="hidden" />
    </>
  )
}
