import { useEffect, useRef, useState } from 'react'
import { DayPicker } from 'react-day-picker'
import type { DateRange } from 'react-day-picker'
import { ru } from 'date-fns/locale'
import { format } from 'date-fns'
import { CalendarDays, ChevronDown, X } from 'lucide-react'
import { AnimatePresence, m } from 'framer-motion'

import 'react-day-picker/style.css'
import './DevicesDateRangePicker.scss'
import { popoverVariants, uiFadeTransition } from '../../../../shared/lib/motion'

export type DevicesDateRangePickerValue = {
  from: Date | null
  to: Date | null
  fromTime: string
  toTime: string
}

type DevicesDateRangePickerProps = {
  value: DevicesDateRangePickerValue
  onChange: (value: DevicesDateRangePickerValue) => void
}

function formatDate(date: Date | null) {
  if (!date) return ''

  return format(date, 'dd.MM.yyyy', {
    locale: ru,
  })
}

function getLabel(value: DevicesDateRangePickerValue) {
  if (!value.from && !value.to) {
    return 'Выберите период'
  }

  if (value.from && !value.to) {
    return `${formatDate(value.from)}, ${value.fromTime} — ...`
  }

  return `${formatDate(value.from)}, ${value.fromTime} — ${formatDate(value.to)}, ${value.toTime}`
}

export function DevicesDateRangePicker({
  value,
  onChange,
}: DevicesDateRangePickerProps) {
  const [isOpen, setIsOpen] = useState(false)
  const rootRef = useRef<HTMLDivElement | null>(null)

  useEffect(() => {
    function handleClickOutside(event: MouseEvent) {
      if (!rootRef.current) return

      if (!rootRef.current.contains(event.target as Node)) {
        setIsOpen(false)
      }
    }

    document.addEventListener('mousedown', handleClickOutside)

    return () => {
      document.removeEventListener('mousedown', handleClickOutside)
    }
  }, [])

  const selectedRange: DateRange | undefined =
    value.from || value.to
      ? {
          from: value.from ?? undefined,
          to: value.to ?? undefined,
        }
      : undefined

  function handleSelect(range: DateRange | undefined) {
    onChange({
      ...value,
      from: range?.from ?? null,
      to: range?.to ?? null,
    })
  }

  function handleReset() {
    onChange({
      from: null,
      to: null,
      fromTime: '07:00',
      toTime: '16:00',
    })
  }

  function handleToday() {
    const today = new Date()

    onChange({
      from: today,
      to: today,
      fromTime: '00:00',
      toTime: '23:59',
    })
  }

  function handleWeek() {
    const today = new Date()
    const start = new Date()

    start.setDate(today.getDate() - 7)

    onChange({
      from: start,
      to: today,
      fromTime: '00:00',
      toTime: '23:59',
    })
  }

  return (
    <div className="devices-date-range" ref={rootRef}>
      <button
        className={`devices-date-range__trigger ${isOpen ? 'is-open' : ''}`}
        type="button"
        onClick={() => setIsOpen((prev) => !prev)}
      >
        <CalendarDays size={15} />

        <span>{getLabel(value)}</span>

        {value.from || value.to ? (
          <X
            className="devices-date-range__clear"
            size={15}
            onClick={(event) => {
              event.stopPropagation()
              handleReset()
            }}
          />
        ) : (
          <ChevronDown className="devices-date-range__chevron" size={15} />
        )}
      </button>

      <AnimatePresence initial={false}>
        {isOpen && (
        <m.div
          className="devices-date-range__popover"
          variants={popoverVariants}
          initial="initial"
          animate="animate"
          exit="exit"
          transition={uiFadeTransition}
        >
          <DayPicker
            mode="range"
            selected={selectedRange}
            onSelect={handleSelect}
            locale={ru}
            weekStartsOn={1}
            numberOfMonths={1}
            className="devices-date-range__calendar"
            captionLayout="dropdown"
          />

          <div className="devices-date-range__time">
            <label>
              <span>Время начала</span>
              <input
                type="time"
                value={value.fromTime}
                onChange={(event) =>
                  onChange({
                    ...value,
                    fromTime: event.target.value,
                  })
                }
              />
            </label>

            <label>
              <span>Время окончания</span>
              <input
                type="time"
                value={value.toTime}
                onChange={(event) =>
                  onChange({
                    ...value,
                    toTime: event.target.value,
                  })
                }
              />
            </label>
          </div>

          <div className="devices-date-range__presets">
            <button type="button" onClick={handleToday}>
              Сегодня
            </button>

            <button type="button" onClick={handleWeek}>
              7 дней
            </button>
          </div>

          <div className="devices-date-range__footer">
            <p>
              {value.from && value.to
                ? `Выбрано: ${formatDate(value.from)} — ${formatDate(value.to)}`
                : 'Период не выбран'}
            </p>

            <div className="devices-date-range__actions">
              <button
                className="devices-date-range__reset"
                type="button"
                onClick={handleReset}
              >
                Сбросить
              </button>

              <button
                className="devices-date-range__apply"
                type="button"
                onClick={() => setIsOpen(false)}
              >
                Применить
              </button>
            </div>
          </div>
        </m.div>
        )}
      </AnimatePresence>
    </div>
  )
}
