import moment from 'moment'
import * as React from 'react'
import { type DateRange } from 'react-day-picker'

import { Calendar } from './Calendar'
import Button from '../Button/Button'
import Icon from '../Icons/Icon'
import Popover from '../Popover/Popover'
import { SideDrawer } from '../SideDrawer/SideDrawer'
import TextInput from '../Form/TextInput'
import { useFocus } from '../../hooks/useFocus/useFocus'
import { useMediaQuery } from '../../hooks/responsiveHooks'
import styles from './_datePicker.module.scss'
import { c } from '../../translations/LibraryTranslationService'
import { type DatePickerProps } from './DatePicker.models'
import {
  getDateForButtonType,
  getDateRangeForButtonType,
  isDateRangeValidWithRestrictions,
  isEmptyOrWhitespace,
  isSingleDateValidWithRestrictions,
  isValidDateString,
  parseDateRangeString,
  type RangeButtonType,
  renderActionButtons,
  type SingleButtonType,
  trimWhitespace,
} from './DatePickerHelper'

// Helper to render action buttons based on typ

export default function DatePicker(props: DatePickerProps) {
  const {
    showDateValue = true,
    dateRestrictions = {
      beforeDate: undefined,
      afterDate: undefined,
    },
    onDateChange,
    type = 'single',
    actionButtons = {
      last7Days: true,
      next7Days: true,
      thisWeekToDate: true,
      thisWeek: true,
      lastWeek: true,
      nextWeek: true,
      lastMonth: true,
      thisMonth: true,
      thisMonthToDate: true,
      nextMonth: true,
      thisQuarter: true,
      thisQuarterToDate: true,
      lastQuarter: true,
      nextQuarter: true,
      thisYear: true,
      thisYearToDate: true,
      lastYear: true,
      nextYear: true,
      today: true,
      yesterday: true,
      tomorrow: true,
    },
    placeholder,
    labelText,
    selectedDate,
    selectedDateRange,
    isExposed = false,
    disabled = false,
    disableAutoClose = false,
    clear = false,
    reset = false,
    labelTooltip,
    error = {
      text: '',
      showError: false,
    },
    layerPosition,
    position = 'bottom',
    qaTestId = 'date-picker',
  } = props

  const dateType = type === 'single' ? 'date-single' : 'date-range'
  const isEditingRef = React.useRef(false)
  const [selectedGroup, setSelectedGroup] = React.useState<string | null>(null)
  const isMobileView = useMediaQuery({ type: 'max', breakpoint: 'sm' })
  const [isDrawerOpen, setIsDrawerOpen] = React.useState(false)
  const ref = useFocus(isDrawerOpen)

  const handleSingleDateSelect = (selectedDate: Date | undefined) => {
    onDateChange(selectedDate)
    setIsDateValid(true)
    isEditingRef.current = false
  }

  const initialDateRef = React.useRef<Date | undefined>(selectedDate)
  const initialDateRangeRef = React.useRef<DateRange | undefined>(
    selectedDateRange,
  )

  const handleReset = () => {
    if (type === 'single') {
      handleSingleDateSelect(initialDateRef.current)
    } else {
      handleRangeDateSelect(initialDateRangeRef.current, true)
    }
  }

  const handleNewRangeDateSelect = (selectedRange: DateRange) => {
    const isSameDate = (
      fromDate: Date | undefined,
      toDate: Date | undefined,
    ) => {
      if (!fromDate || !toDate) return false
      return fromDate.getTime() === toDate.getTime()
    }

    if (!isSameDate(selectedDateRange?.from, selectedDateRange?.to)) {
      if (isSameDate(selectedRange.from, selectedDateRange?.from)) {
        selectedRange.from = selectedRange.to
      } else {
        selectedRange.to = selectedRange.from
      }
    }
  }

  const handleRangeDateSelect = (
    selectedRange: DateRange | undefined,
    fromInput = false,
  ) => {
    if (selectedRange?.from && selectedRange?.to) {
      if (!fromInput) {
        handleNewRangeDateSelect(selectedRange)
      }
      isEditingRef.current = false

      if (isDateRangeValidWithRestrictions(selectedRange, dateRestrictions)) {
        onDateChange(selectedRange)

        // Adjust the month view if the selected dates are not visible in the current two-month view
        if (viewMonth && selectedRange.from && selectedRange.to) {
          const currentMonth = moment(viewMonth)
          const nextMonth = moment(viewMonth).add(1, 'month')
          const fromMonth = moment(selectedRange.from)
          const toMonth = moment(selectedRange.to)

          const isFromVisible =
            fromMonth.isSame(currentMonth, 'month') ||
            fromMonth.isSame(nextMonth, 'month')
          const isToVisible =
            toMonth.isSame(currentMonth, 'month') ||
            toMonth.isSame(nextMonth, 'month')

          // Adjust the view if either date is not currently visible
          if (!isFromVisible || !isToVisible) {
            setViewMonth(selectedRange.from)
          }
        } else if (fromInput) {
          // Always adjust view when input comes from text input
          setViewMonth(selectedRange.from)
        }
      } else {
        // If date range is not valid with restrictions, don't set it
        setIsDateValid(false)
        return
      }
    } else {
      onDateChange(selectedRange)
      setSelectedBtnType(null)
    }
    setIsDateValid(true)
  }

  const [isDateValid, setIsDateValid] = React.useState(true)
  const [selectedBtnType, setSelectedBtnType] = React.useState<
    RangeButtonType | SingleButtonType | null
  >(null)
  const [viewMonth, setViewMonth] = React.useState<Date | undefined>(
    type === 'single' ? selectedDate : selectedDateRange?.from,
  )

  const [inputDate, setInputDate] = React.useState<string>('')
  const isDateSelected = Boolean(
    selectedDate ||
    (selectedDateRange && selectedDateRange.from && selectedDateRange.to) ||
    inputDate,
  )

  function getLabelWidthStyle() {
    if (!showDateValue) {
      return styles.withoutLabel
    }
    return type === 'single' ? styles.singleWithLabel : styles.rangeWithLabel
  }

  const selectSingleDate = (buttonType: SingleButtonType) => {
    const potentialDate = getDateForButtonType(buttonType)
    if (!isSingleDateValidWithRestrictions(potentialDate, dateRestrictions)) {
      return
    }
    handleSingleDateSelect(potentialDate)
  }

  const selectToday = () => selectSingleDate('today')
  const selectYesterday = () => selectSingleDate('yesterday')
  const selectTomorrow = () => selectSingleDate('tomorrow')

  const selectDateRange = (buttonType: RangeButtonType) => {
    const dateRange = getDateRangeForButtonType(buttonType)

    if (isDateRangeValidWithRestrictions(dateRange, dateRestrictions)) {
      onDateChange(dateRange)
      setViewMonth(dateRange.from)
      setSelectedBtnType(buttonType)
    }
    // If date range is not valid with restrictions, don't select it
  }

  const selectLast7Days = () => selectDateRange('last7Days')
  const selectNext7Days = () => selectDateRange('next7Days')
  const selectThisWeekToDate = () => selectDateRange('thisWeekToDate')
  const selectThisWeek = () => selectDateRange('thisWeek')
  const selectLastWeek = () => selectDateRange('lastWeek')
  const selectNextWeek = () => selectDateRange('nextWeek')
  const selectLastMonth = () => selectDateRange('lastMonth')
  const selectThisMonth = () => selectDateRange('thisMonth')
  const selectThisMonthToDate = () => selectDateRange('thisMonthToDate')
  const selectNextMonth = () => selectDateRange('nextMonth')
  const selectThisQuarter = () => selectDateRange('thisQuarter')
  const selectThisQuarterToDate = () => selectDateRange('thisQuarterToDate')
  const selectLastQuarter = () => selectDateRange('lastQuarter')
  const selectNextQuarter = () => selectDateRange('nextQuarter')
  const selectThisYear = () => selectDateRange('thisYear')
  const selectThisYearToDate = () => selectDateRange('thisYearToDate')
  const selectLastYear = () => selectDateRange('lastYear')
  const selectNextYear = () => selectDateRange('nextYear')

  const handleClear = () => {
    setInputDate('')
    if (type === 'single') {
      handleSingleDateSelect(undefined)
    } else {
      handleRangeDateSelect({ from: undefined, to: undefined })
    }
  }

  const getErrorText = () => {
    const defaultErrorMessage =
      type === 'single'
        ? c('datePickerErrorMessageSingleDate')
        : c('datePickerErrorMessageDateRange')

    const errorMessages = []
    if (!isDateValid) {
      errorMessages.push(defaultErrorMessage)
    }
    if (error.showError && error.text) {
      errorMessages.push(error.text)
    }
    if (errorMessages.length > 0) {
      return <div className={styles.errorText}>{errorMessages.join(' ')}</div>
    }
    return null
  }

  const getFormattedDateValue = () => {
    if (!showDateValue) {
      return ''
    }

    if (type === 'single') {
      if (selectedDate) {
        return moment(selectedDate).format('MM/DD/YYYY')
      }
      return isEditingRef.current ? inputDate : ''
    }

    if (selectedDateRange?.from) {
      return `${moment(selectedDateRange.from).format('MM/DD/YYYY')} - ${moment(selectedDateRange.to).format('MM/DD/YYYY')}`
    }

    return isEditingRef.current ? inputDate : ''
  }

  const datePickerContent = (setVisible: (visible: boolean) => void) => {
    return (
      <div>
        {isMobileView && isDrawerOpen && showDateValue && !isExposed ? (
          <div className={styles.mobileDrawerInput}>
            {PopoverOrSidedrawerContent({
              setVisible: setIsDrawerOpen,
              visible: isDrawerOpen,
            })}
          </div>
        ) : (
          <></>
        )}
        {type === 'single' ? (
          <Calendar
            mode='single'
            selected={selectedDate}
            onSelect={(date) => {
              handleSingleDateSelect(date)
              if (!disableAutoClose) {
                setVisible(false)
                setIsDrawerOpen(false)
              }
            }}
            {...(!isMobileView
              ? {
                  footer: renderActionButtons({
                    type,
                    actionButtons,
                    selectedBtnType,
                    c,
                    selectedGroup,
                    setSelectedGroup,
                    reset,
                    handleReset,
                    dateRestrictions,
                    handlers: {
                      selectToday,
                      selectYesterday,
                      selectTomorrow,
                    },
                  }),
                }
              : {})}
            autoFocus
            className={`${styles.calendar} ${styles.singleDatePicker}`}
            dateRestrictions={dateRestrictions}
            required
          />
        ) : (
          <Calendar
            mode='range'
            selected={selectedDateRange}
            onSelect={(selectedRange) => {
              handleRangeDateSelect(selectedRange)
            }}
            autoFocus
            month={viewMonth}
            onMonthChange={(viewMonth) => {
              setViewMonth(viewMonth)
            }}
            {...(!isMobileView
              ? {
                  footer: renderActionButtons({
                    type,
                    actionButtons,
                    selectedBtnType,
                    c,
                    selectedGroup,
                    setSelectedGroup,
                    reset,
                    handleReset,
                    dateRestrictions,
                    handlers: {
                      selectLast7Days,
                      selectNext7Days,
                      selectThisWeekToDate,
                      selectThisWeek,
                      selectLastWeek,
                      selectNextWeek,
                      selectThisMonth,
                      selectLastMonth,
                      selectThisMonthToDate,
                      selectNextMonth,
                      selectThisQuarter,
                      selectThisQuarterToDate,
                      selectLastQuarter,
                      selectNextQuarter,
                      selectThisYear,
                      selectThisYearToDate,
                      selectLastYear,
                      selectNextYear,
                    },
                  }),
                }
              : {})}
            defaultMonth={
              selectedDateRange ? selectedDateRange.from : undefined
            }
            className={`${styles.calendar} ${styles.rangeDatePicker}`}
            numberOfMonths={2}
            dateRestrictions={dateRestrictions}
            required
          />
        )}
      </div>
    )
  }

  const PopoverOrSidedrawerContent = ({
    setVisible,
    visible,
  }: {
    setVisible: (visible: boolean) => void
    visible: boolean
  }) => {
    return (
      <div className={styles.labelButton}>
        {showDateValue ? (
          <div className={styles.inputBox}>
            <TextInput
              type={dateType}
              classType={`${getLabelWidthStyle()} ${
                !showDateValue ? styles.inputWithoutLabel : ''
              } ${clear ? styles.extraPadding : styles.paddingWithLabel} ${
                !isDateValid || error.showError ? 'error ' : ''
              } ${visible ? styles.focused : ''}`}
              hasError={!isDateValid || error.showError}
              disabled={disabled}
              labelText={labelText ? labelText : ''}
              labelTooltip={labelTooltip}
              value={getFormattedDateValue()}
              placeholder={
                showDateValue
                  ? placeholder ||
                    (type === 'single'
                      ? c('validDateFormatForSingleDatePicker')
                      : c('validDateFormatForRangeDatePicker'))
                  : ''
              }
              ref={ref}
              onFocus={() => {
                setVisible(true)
                setIsDrawerOpen(true)
                setViewMonth(
                  type === 'range' ? selectedDateRange?.from : selectedDate,
                )
              }}
              callout={(_, value) => {
                const stringValue = String(value)
                setInputDate(stringValue)
                if (isEmptyOrWhitespace(stringValue)) {
                  setIsDateValid(true)
                  if (type === 'single') {
                    onDateChange(undefined)
                  } else {
                    onDateChange({ from: undefined, to: undefined })
                  }
                  return
                }

                if (type === 'single') {
                  const isValidDate = isValidDateString(stringValue)
                  if (isValidDate) {
                    setIsDateValid(true)
                    const newDate = moment(
                      trimWhitespace(stringValue),
                      'MM/DD/YYYY',
                    ).toDate()
                    handleSingleDateSelect(newDate)
                    if (!disableAutoClose) {
                      setVisible(false)
                      setIsDrawerOpen(false)
                    }
                    setViewMonth(newDate)
                  } else {
                    isEditingRef.current = true
                    setIsDateValid(false)
                    onDateChange(undefined)
                  }
                } else if (type === 'range') {
                  const dateRange = parseDateRangeString(stringValue)
                  if (dateRange) {
                    if (
                      isDateRangeValidWithRestrictions(
                        dateRange,
                        dateRestrictions,
                      )
                    ) {
                      setIsDateValid(true)
                      handleRangeDateSelect(dateRange, true)
                      setViewMonth(dateRange.from)
                    } else {
                      isEditingRef.current = true
                      setIsDateValid(false)
                      onDateChange({ from: undefined, to: undefined })
                    }
                  } else {
                    isEditingRef.current = true
                    setIsDateValid(false)
                    onDateChange({ from: undefined, to: undefined })
                  }
                }
              }}
            />
          </div>
        ) : (
          <></>
        )}
        <div
          className={`${styles.iconsContainer} ${
            labelText ? styles.iconsContainerWithLabel : ''
          }`}
        >
          {clear && isDateSelected ? (
            <>
              <Button
                className={disabled ? styles.disabledIcon : ''}
                as='unstyled'
                disabled={disabled}
                onClick={() => {
                  handleClear()
                }}
              >
                <Icon
                  icon='x'
                  iconSize='12px'
                  color={disabled ? 'gray' : 'dark-purple'}
                  qaTestId={`${qaTestId}-x-icon`}
                />
              </Button>
              <div className={styles.divider}></div>
            </>
          ) : (
            <></>
          )}
          <Button
            className={disabled ? styles.disabledIcon : ''}
            as='unstyled'
            disabled={disabled}
            onClick={() => {
              setVisible(!visible)
              setViewMonth(
                type === 'range' ? selectedDateRange?.from : selectedDate,
              )
              if (isMobileView) {
                setIsDrawerOpen(!isDrawerOpen)
              }
            }}
          >
            <Icon
              icon='calendar'
              iconSize='16px'
              color={disabled ? 'gray' : 'dark-purple'}
            />
          </Button>
        </div>
      </div>
    )
  }

  return (
    <div qa-test-id={qaTestId}>
      {!isExposed ? (
        isMobileView ? (
          <>
            {PopoverOrSidedrawerContent({
              setVisible: setIsDrawerOpen,
              visible: isDrawerOpen,
            })}
            <SideDrawer
              headerContent={
                labelText
                  ? String(labelText)
                  : type === 'single'
                    ? c('selectADate')
                    : c('selectADateRange')
              }
              isOpen={isDrawerOpen}
              layerPosition={layerPosition}
              closeCallout={() => setIsDrawerOpen(false)}
              noContentPadding
              footerContent={renderActionButtons({
                type,
                actionButtons,
                selectedBtnType,
                c,
                selectedGroup,
                setSelectedGroup,
                reset,
                handleReset,
                dateRestrictions,
                handlers: {
                  selectToday,
                  selectYesterday,
                  selectTomorrow,
                  selectLast7Days,
                  selectNext7Days,
                  selectThisWeekToDate,
                  selectThisWeek,
                  selectLastWeek,
                  selectNextWeek,
                  selectThisMonth,
                  selectLastMonth,
                  selectThisMonthToDate,
                  selectNextMonth,
                  selectThisQuarter,
                  selectThisQuarterToDate,
                  selectLastQuarter,
                  selectNextQuarter,
                  selectThisYear,
                  selectThisYearToDate,
                  selectLastYear,
                  selectNextYear,
                },
              })}
            >
              {datePickerContent(() => {})}
            </SideDrawer>
          </>
        ) : (
          <Popover
            popoverContent={({ setVisible }) => datePickerContent(setVisible)}
            position={position}
            maxWidth='600px'
            noPadding
            disableCloseOnScroll
            className={styles.DatePickerPopover}
          >
            {({ visible, setVisible }) =>
              PopoverOrSidedrawerContent({ setVisible, visible })
            }
          </Popover>
        )
      ) : (
        datePickerContent(() => {})
      )}
      {getErrorText()}
    </div>
  )
}
