import React, {
  useCallback,
  useEffect,
  useLayoutEffect,
  useRef,
  useState,
} from 'react'
import { createPortal } from 'react-dom'

/* ─── Date helpers ────────────────────────────────────────────── */

const MONTH_NAMES = [
  'January','February','March','April','May','June',
  'July','August','September','October','November','December',
]
const DAY_ABBR = ['Mo','Tu','We','Th','Fr','Sa','Su']

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

/** Returns 0=Mon … 6=Sun for first day of month */
function firstWeekday(year, month) {
  const d = new Date(year, month, 1).getDay() // 0=Sun
  return (d + 6) % 7 // shift so 0=Mon
}

function toISO(date) {
  const y = date.getFullYear()
  const m = String(date.getMonth() + 1).padStart(2, '0')
  const d = String(date.getDate()).padStart(2, '0')
  return `${y}-${m}-${d}`
}

function fromISO(str) {
  if (!str) return null
  const [y, m, d] = str.split('-').map(Number)
  return new Date(y, m - 1, d)
}

function formatDisplay(isoStr) {
  if (!isoStr) return ''
  const d = fromISO(isoStr)
  if (!d) return ''
  return `${MONTH_NAMES[d.getMonth()].slice(0, 3)} ${d.getDate()}, ${d.getFullYear()}`
}

function isSameDay(a, b) {
  return a?.getFullYear() === b?.getFullYear() &&
         a?.getMonth()    === b?.getMonth()    &&
         a?.getDate()     === b?.getDate()
}

/* ─── Calendar Grid ───────────────────────────────────────────── */

function CalendarGrid({ year, month, selected, onSelect, minDate, maxDate }) {
  const numDays  = daysInMonth(year, month)
  const startWd  = firstWeekday(year, month)
  const prevDays = daysInMonth(year, month - 1 < 0 ? 11 : month - 1)
  const cells    = []

  // Filler from previous month
  for (let i = startWd - 1; i >= 0; i--) {
    cells.push({ day: prevDays - i, current: false, date: new Date(year, month - 1, prevDays - i) })
  }
  // Current month
  for (let d = 1; d <= numDays; d++) {
    cells.push({ day: d, current: true, date: new Date(year, month, d) })
  }
  // Next month filler to fill 6 rows
  let next = 1
  while (cells.length % 7 !== 0) {
    cells.push({ day: next++, current: false, date: new Date(year, month + 1, next - 1) })
  }

  const selectedDate = fromISO(selected)
  const today = new Date()
  today.setHours(0, 0, 0, 0)

  return (
    <div className="p-3">
      {/* Day-of-week headers */}
      <div className="grid grid-cols-7 mb-1">
        {DAY_ABBR.map((d) => (
          <div key={d} className="text-center text-[10px] font-semibold text-slate-500 py-1">{d}</div>
        ))}
      </div>

      {/* Day cells */}
      <div className="grid grid-cols-7 gap-y-0.5">
        {cells.map((cell, i) => {
          const iso       = toISO(cell.date)
          const isSelected = isSameDay(cell.date, selectedDate)
          const isToday   = isSameDay(cell.date, today)
          const disabled  =
            (minDate && iso < minDate) ||
            (maxDate && iso > maxDate)

          return (
            <button
              key={i}
              type="button"
              disabled={disabled}
              onClick={() => onSelect(iso)}
              className={[
                'relative flex items-center justify-center w-8 h-8 mx-auto rounded-lg text-sm transition-all',
                !cell.current ? 'text-slate-600' : '',
                cell.current && !isSelected && !disabled ? 'hover:bg-white/10 text-white' : '',
                isSelected ? 'bg-accent text-white font-semibold shadow shadow-accent/30' : '',
                isToday && !isSelected ? 'ring-1 ring-accent/50 text-accent' : '',
                disabled ? 'opacity-30 cursor-not-allowed' : 'cursor-pointer',
              ].join(' ')}
            >
              {cell.day}
            </button>
          )
        })}
      </div>
    </div>
  )
}

/* ─── DatePicker ──────────────────────────────────────────────── */

/**
 * Nova DatePicker
 *
 * @prop {string}   value       - ISO date string 'YYYY-MM-DD' or ''
 * @prop {function} onChange    - called with ISO string
 * @prop {string}   label
 * @prop {string}   placeholder
 * @prop {string}   error
 * @prop {string}   hint
 * @prop {boolean}  required
 * @prop {boolean}  clearable
 * @prop {string}   minDate     - ISO string lower bound
 * @prop {string}   maxDate     - ISO string upper bound
 */
export default function DatePicker({
  value = '',
  onChange,
  label,
  placeholder = 'Pick a date',
  error,
  hint,
  required = false,
  clearable = false,
  minDate,
  maxDate,
  id,
  disabled = false,
  className = '',
}) {
  const [open, setOpen]     = useState(false)
  const [dropPos, setPos]   = useState({ top: 0, left: 0, width: 240, openUp: false })

  const today   = new Date()
  const initVal = value ? fromISO(value) : today
  const [viewYear,  setYear]  = useState(initVal?.getFullYear() ?? today.getFullYear())
  const [viewMonth, setMonth] = useState(initVal?.getMonth()    ?? today.getMonth())

  const triggerRef = useRef(null)
  const inputId    = id ?? (label ? `dp-${label.toLowerCase().replace(/\s+/g, '-')}` : 'date-picker')

  const measure = useCallback(() => {
    if (!triggerRef.current) return
    const rect   = triggerRef.current.getBoundingClientRect()
    const height = 320
    const openUp = window.innerHeight - rect.bottom < height + 8 && rect.top > height + 8
    setPos({
      top:   openUp ? rect.top - height - 4 : rect.bottom + 4,
      left:  rect.left,
      width: Math.max(rect.width, 280),
      openUp,
    })
  }, [])

  const openPicker = () => {
    if (disabled) return
    if (value) {
      const d = fromISO(value)
      if (d) { setYear(d.getFullYear()); setMonth(d.getMonth()) }
    }
    measure()
    setOpen(true)
  }

  // close on outside click
  useEffect(() => {
    if (!open) return
    const handler = (e) => {
      if (
        !triggerRef.current?.contains(e.target) &&
        !document.getElementById(`dp-panel-${inputId}`)?.contains(e.target)
      ) setOpen(false)
    }
    document.addEventListener('mousedown', handler)
    return () => document.removeEventListener('mousedown', handler)
  }, [open, inputId])

  useEffect(() => {
    if (!open) return
    const onScroll = (e) => {
      if (document.getElementById(`dp-panel-${inputId}`)?.contains(e.target)) return
      setOpen(false)
    }
    const onResize = () => setOpen(false)
    window.addEventListener('scroll', onScroll, true)
    window.addEventListener('resize', onResize)
    return () => {
      window.removeEventListener('scroll', onScroll, true)
      window.removeEventListener('resize', onResize)
    }
  }, [open, inputId])

  const prevMonth = () => {
    if (viewMonth === 0) { setMonth(11); setYear((y) => y - 1) }
    else setMonth((m) => m - 1)
  }
  const nextMonth = () => {
    if (viewMonth === 11) { setMonth(0); setYear((y) => y + 1) }
    else setMonth((m) => m + 1)
  }

  const handleSelect = (iso) => {
    onChange?.(iso)
    setOpen(false)
  }

  const clearValue = (e) => { e.stopPropagation(); onChange?.('') }

  const triggerClass = [
    'relative flex items-center h-[42px] rounded-xl border px-3.5 gap-2 cursor-pointer w-full',
    'bg-white/[0.06] text-sm transition-all duration-150',
    'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-0',
    error
      ? 'border-red-500/60 focus-visible:ring-red-500/40'
      : open
        ? 'border-accent/50 ring-2 ring-accent/40'
        : 'border-white/12 hover:border-white/22',
    disabled ? 'opacity-50 cursor-not-allowed pointer-events-none' : '',
    className,
  ].join(' ')

  return (
    <div className="flex flex-col gap-1.5">
      {label && (
        <label htmlFor={inputId} className="text-sm font-medium text-white/85 select-none">
          {label}{required && <span className="text-red-400 ml-1">*</span>}
        </label>
      )}

      <div ref={triggerRef} className={triggerClass} tabIndex={disabled ? -1 : 0} onClick={openPicker}
        onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openPicker() } }}
        role="button" aria-label={label ?? placeholder} id={inputId}
      >
        {/* Calendar icon */}
        <svg width="14" height="14" viewBox="0 0 14 14" fill="none" className="text-slate-500 shrink-0" aria-hidden="true">
          <rect x="1" y="2.5" width="12" height="10.5" rx="1.5" stroke="currentColor" strokeWidth="1.3" />
          <path d="M1 6h12" stroke="currentColor" strokeWidth="1.3" />
          <path d="M4 1v3M10 1v3" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" />
          <circle cx="4.5" cy="9" r="0.75" fill="currentColor" />
          <circle cx="7" cy="9" r="0.75" fill="currentColor" />
          <circle cx="9.5" cy="9" r="0.75" fill="currentColor" />
        </svg>

        <span className={`flex-1 truncate ${value ? 'text-white' : 'text-slate-500'}`}>
          {value ? formatDisplay(value) : placeholder}
        </span>

        {clearable && value && (
          <button type="button" tabIndex={-1} onClick={clearValue}
            className="w-5 h-5 flex items-center justify-center rounded text-slate-500 hover:text-white transition-colors"
            aria-label="Clear date"
          >
            <svg width="10" height="10" viewBox="0 0 10 10" fill="none" aria-hidden="true">
              <path d="M1 1l8 8M9 1L1 9" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
            </svg>
          </button>
        )}
      </div>

      {error && <p role="alert" className="text-xs text-red-400">{error}</p>}
      {!error && hint && <p className="text-xs text-slate-500">{hint}</p>}

      {open && createPortal(
        <div
          id={`dp-panel-${inputId}`}
          className="fixed z-[500] rounded-2xl border border-white/12 bg-nova-900 shadow-2xl shadow-black/50 overflow-hidden"
          style={{ top: dropPos.top, left: dropPos.left, width: dropPos.width }}
        >
          {/* Month nav header */}
          <div className="flex items-center justify-between px-3 pt-3">
            <button type="button" onClick={prevMonth}
              className="w-8 h-8 flex items-center justify-center rounded-lg text-slate-400 hover:text-white hover:bg-white/8 transition-all"
              aria-label="Previous month"
            >
              <svg width="10" height="10" viewBox="0 0 10 10" fill="none" aria-hidden="true">
                <path d="M7 1L3 5l4 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
              </svg>
            </button>

            <span className="text-sm font-semibold text-white">
              {MONTH_NAMES[viewMonth]} {viewYear}
            </span>

            <button type="button" onClick={nextMonth}
              className="w-8 h-8 flex items-center justify-center rounded-lg text-slate-400 hover:text-white hover:bg-white/8 transition-all"
              aria-label="Next month"
            >
              <svg width="10" height="10" viewBox="0 0 10 10" fill="none" aria-hidden="true">
                <path d="M3 1l4 4-4 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
              </svg>
            </button>
          </div>

          <CalendarGrid
            year={viewYear}
            month={viewMonth}
            selected={value}
            onSelect={handleSelect}
            minDate={minDate}
            maxDate={maxDate}
          />

          {/* Today shortcut */}
          <div className="border-t border-white/8 px-3 py-2 flex justify-end">
            <button
              type="button"
              onClick={() => handleSelect(toISO(new Date()))}
              className="text-xs text-accent hover:text-accent/80 font-medium transition-colors"
            >
              Today
            </button>
          </div>
        </div>,
        document.body,
      )}
    </div>
  )
}
