import { useState, useRef, useEffect, useCallback } from 'react'
import { createPortal } from 'react-dom'
import styles from './DateTimePicker.module.css'

interface DateTimePickerProps {
  value?: Date
  onChange?: (date: Date | null) => void
  label?: string
  placeholder?: string
  className?: string
}

const DAYS = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']

function getDaysInMonth(year: number, month: number): number {
  return new Date(year, month + 1, 0).getDate()
}

function getFirstDayOfWeek(year: number, month: number): number {
  const day = new Date(year, month, 1).getDay()
  return day === 0 ? 6 : day - 1 // Monday = 0
}

function formatDisplay(d: Date | undefined): string {
  if (!d) return '—'
  const date = d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })
  const time = d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', hour12: false })
  return `${date}\u2009${time}`
}

function pad(n: number): string {
  return String(n).padStart(2, '0')
}

export function DateTimePicker({ value, onChange, label, placeholder, className }: DateTimePickerProps) {
  const [open, setOpen] = useState(false)
  const [viewYear, setViewYear] = useState(value?.getFullYear() ?? new Date().getFullYear())
  const [viewMonth, setViewMonth] = useState(value?.getMonth() ?? new Date().getMonth())
  const [selectedDate, setSelectedDate] = useState<Date | null>(value ?? null)
  const [hour, setHour] = useState(value ? pad(value.getHours()) : pad(new Date().getHours()))
  const [minute, setMinute] = useState(value ? pad(value.getMinutes()) : pad(new Date().getMinutes()))

  const triggerRef = useRef<HTMLButtonElement>(null)
  const panelRef = useRef<HTMLDivElement>(null)
  const [pos, setPos] = useState({ top: 0, left: 0 })

  // Sync when value changes externally
  useEffect(() => {
    if (value) {
      setSelectedDate(value)
      setHour(pad(value.getHours()))
      setMinute(pad(value.getMinutes()))
      setViewYear(value.getFullYear())
      setViewMonth(value.getMonth())
    }
  }, [value])

  const reposition = useCallback(() => {
    if (!triggerRef.current) return
    const rect = triggerRef.current.getBoundingClientRect()
    setPos({
      top: rect.bottom + 4,
      left: rect.left,
    })
  }, [])

  useEffect(() => {
    if (open) {
      const id = requestAnimationFrame(reposition)
      return () => cancelAnimationFrame(id)
    }
  }, [open, reposition])

  // Close on Escape only — panel closes via Apply/Now buttons
  useEffect(() => {
    if (!open) return
    function handleKey(e: KeyboardEvent) {
      if (e.key === 'Escape') setOpen(false)
    }
    document.addEventListener('keydown', handleKey)
    return () => document.removeEventListener('keydown', handleKey)
  }, [open])

  function handleDone() {
    if (selectedDate) {
      const d = new Date(selectedDate)
      d.setHours(parseInt(hour, 10) || 0, parseInt(minute, 10) || 0, 0, 0)
      onChange?.(d)
    }
    setOpen(false)
  }

  function handleDayClick(day: number) {
    const d = new Date(viewYear, viewMonth, day)
    setSelectedDate(d)
  }

  function handleNow() {
    const now = new Date()
    onChange?.(now)
    setOpen(false)
  }

  function prevMonth() {
    if (viewMonth === 0) { setViewMonth(11); setViewYear((y) => y - 1) }
    else setViewMonth((m) => m - 1)
  }

  function nextMonth() {
    if (viewMonth === 11) { setViewMonth(0); setViewYear((y) => y + 1) }
    else setViewMonth((m) => m + 1)
  }

  const daysInMonth = getDaysInMonth(viewYear, viewMonth)
  const firstDay = getFirstDayOfWeek(viewYear, viewMonth)
  const today = new Date()

  const monthLabel = new Date(viewYear, viewMonth).toLocaleDateString(undefined, { month: 'long', year: 'numeric' })

  return (
    <div className={`${styles.wrapper} ${className ?? ''}`}>
      {label && <span className={styles.label}>{label}</span>}
      <button
        ref={triggerRef}
        type="button"
        className={styles.trigger}
        onClick={() => setOpen(!open)}
      >
        {value ? formatDisplay(value) : (placeholder ?? '—')}
      </button>

      {open && createPortal(
        <div
          ref={panelRef}
          className={styles.panel}
          style={{ top: pos.top, left: pos.left }}
        >
          {/* Month navigation */}
          <div className={styles.monthNav}>
            <button type="button" className={styles.navBtn} onClick={prevMonth} aria-label="Previous month">&#9664;</button>
            <span className={styles.monthLabel}>{monthLabel}</span>
            <button type="button" className={styles.navBtn} onClick={nextMonth} aria-label="Next month">&#9654;</button>
          </div>

          {/* Calendar grid */}
          <div className={styles.calendar}>
            {DAYS.map((d) => (
              <span key={d} className={styles.dayHeader}>{d}</span>
            ))}
            {Array.from({ length: firstDay }, (_, i) => (
              <span key={`pad-${i}`} className={styles.dayEmpty} />
            ))}
            {Array.from({ length: daysInMonth }, (_, i) => {
              const day = i + 1
              const isToday = viewYear === today.getFullYear() && viewMonth === today.getMonth() && day === today.getDate()
              const isSelected = selectedDate && viewYear === selectedDate.getFullYear() && viewMonth === selectedDate.getMonth() && day === selectedDate.getDate()
              return (
                <button
                  key={day}
                  type="button"
                  className={[styles.day, isToday ? styles.dayToday : '', isSelected ? styles.daySelected : ''].filter(Boolean).join(' ')}
                  onClick={() => handleDayClick(day)}
                >
                  {day}
                </button>
              )
            })}
          </div>

          {/* Time selector */}
          <div className={styles.timeRow}>
            <span className={styles.timeLabel}>Time</span>
            <input
              type="text"
              className={styles.timeInput}
              value={hour}
              onChange={(e) => setHour(e.target.value.replace(/\D/g, '').slice(0, 2))}
              maxLength={2}
              aria-label="Hour"
            />
            <span className={styles.timeSep}>:</span>
            <input
              type="text"
              className={styles.timeInput}
              value={minute}
              onChange={(e) => setMinute(e.target.value.replace(/\D/g, '').slice(0, 2))}
              maxLength={2}
              aria-label="Minute"
            />
          </div>

          {/* Actions */}
          <div className={styles.actions}>
            <button type="button" className={styles.todayBtn} onClick={handleNow}>Now</button>
            <button type="button" className={styles.doneBtn} onClick={handleDone} disabled={!selectedDate}>Apply</button>
          </div>
        </div>,
        document.body,
      )}
    </div>
  )
}

DateTimePicker.displayName = 'DateTimePicker'
