"use client"

import { cn } from "@/lib/utils"
import { getDaysInMonth, getFirstDayOfMonth, isSameDay, isToday, type Locale, locales } from "@/lib/date-utils"
import { useCallback, useRef, useEffect } from "react"

interface CalendarGridProps {
  year: number
  month: number
  selectedDate: Date | null
  hoveredDate: Date | null
  rangeStart: Date | null
  rangeEnd: Date | null
  onDateSelect: (date: Date) => void
  onDateHover: (date: Date | null) => void
  locale: Locale
  minDate?: Date
  maxDate?: Date
  focusedDate: Date | null
  onFocusedDateChange: (date: Date) => void
  showWeekdays?: boolean
}

export function CalendarGrid({
  year,
  month,
  selectedDate,
  hoveredDate,
  rangeStart,
  rangeEnd,
  onDateSelect,
  onDateHover,
  locale,
  minDate,
  maxDate,
  focusedDate,
  onFocusedDateChange,
  showWeekdays = false,
}: CalendarGridProps) {
  const config = locales[locale]
  const isRTL = config.direction === "rtl"
  const gridRef = useRef<HTMLDivElement>(null)

  const daysInMonth = getDaysInMonth(year, month)
  const firstDayOfMonth = getFirstDayOfMonth(year, month)

  // Get days from previous month to fill the first week
  const prevMonth = month === 0 ? 11 : month - 1
  const prevMonthYear = month === 0 ? year - 1 : year
  const daysInPrevMonth = getDaysInMonth(prevMonthYear, prevMonth)

  // Helper to create dates at noon to avoid DST/timezone edge cases
  const createDate = (y: number, m: number, d: number) => new Date(y, m, d, 12, 0, 0)

  const days: { date: Date; isCurrentMonth: boolean }[] = []

  // Previous month days
  for (let i = firstDayOfMonth - 1; i >= 0; i--) {
    days.push({
      date: createDate(prevMonthYear, prevMonth, daysInPrevMonth - i),
      isCurrentMonth: false,
    })
  }

  // Current month days
  for (let i = 1; i <= daysInMonth; i++) {
    days.push({
      date: createDate(year, month, i),
      isCurrentMonth: true,
    })
  }

  // Next month days to fill the grid
  const remainingDays = 42 - days.length
  const nextMonth = month === 11 ? 0 : month + 1
  const nextMonthYear = month === 11 ? year + 1 : year

  for (let i = 1; i <= remainingDays; i++) {
    days.push({
      date: createDate(nextMonthYear, nextMonth, i),
      isCurrentMonth: false,
    })
  }

  // Compare dates by year/month/day only, ignoring time
  const compareDateOnly = (a: Date, b: Date): number => {
    const ay = a.getFullYear(), am = a.getMonth(), ad = a.getDate()
    const by = b.getFullYear(), bm = b.getMonth(), bd = b.getDate()
    if (ay !== by) return ay - by
    if (am !== bm) return am - bm
    return ad - bd
  }

  const isDateDisabled = useCallback(
    (date: Date) => {
      if (minDate && compareDateOnly(date, minDate) < 0) return true
      if (maxDate && compareDateOnly(date, maxDate) > 0) return true
      return false
    },
    [minDate, maxDate],
  )

  const isDateInRange = useCallback(
    (date: Date) => {
      if (!rangeStart || !rangeEnd) return false
      return compareDateOnly(date, rangeStart) >= 0 && compareDateOnly(date, rangeEnd) <= 0
    },
    [rangeStart, rangeEnd],
  )

  const isDateRangeStart = useCallback(
    (date: Date) => {
      if (!rangeStart) return false
      return isSameDay(date, rangeStart)
    },
    [rangeStart],
  )

  const isDateRangeEnd = useCallback(
    (date: Date) => {
      if (!rangeEnd) return false
      return isSameDay(date, rangeEnd)
    },
    [rangeEnd],
  )

  // Keyboard navigation
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (!focusedDate) return

      let newDate: Date | null = null

      switch (e.key) {
        case "ArrowLeft":
          newDate = createDate(focusedDate.getFullYear(), focusedDate.getMonth(), focusedDate.getDate() + (isRTL ? 1 : -1))
          break
        case "ArrowRight":
          newDate = createDate(focusedDate.getFullYear(), focusedDate.getMonth(), focusedDate.getDate() + (isRTL ? -1 : 1))
          break
        case "ArrowUp":
          newDate = createDate(focusedDate.getFullYear(), focusedDate.getMonth(), focusedDate.getDate() - 7)
          break
        case "ArrowDown":
          newDate = createDate(focusedDate.getFullYear(), focusedDate.getMonth(), focusedDate.getDate() + 7)
          break
        case "Enter":
        case " ":
          e.preventDefault()
          if (!isDateDisabled(focusedDate)) {
            onDateSelect(focusedDate)
          }
          return
        case "Home":
          newDate = createDate(year, month, 1)
          break
        case "End":
          newDate = createDate(year, month, daysInMonth)
          break
        default:
          return
      }

      if (newDate && !isDateDisabled(newDate)) {
        e.preventDefault()
        onFocusedDateChange(newDate)
      }
    }

    const grid = gridRef.current
    if (grid) {
      grid.addEventListener("keydown", handleKeyDown)
      return () => grid.removeEventListener("keydown", handleKeyDown)
    }
  }, [focusedDate, isRTL, year, month, daysInMonth, isDateDisabled, onDateSelect, onFocusedDateChange])

  const weekdays = config.weekdaysShort

  return (
    <div ref={gridRef} className="w-full min-h-0" role="grid" aria-label={`${config.months[month]} ${year}`} tabIndex={0}>
      {showWeekdays && (
        <div className="mb-2 grid grid-cols-7 gap-1" role="row">
          {weekdays.map((day, index) => (
            <div
              key={index}
              className="py-2 text-center text-xs font-semibold tracking-tight text-muted-foreground sm:text-sm"
              role="columnheader"
              aria-label={config.weekdays[index]}
            >
              {day}
            </div>
          ))}
        </div>
      )}

      {/* Day grid */}
      <div className="grid grid-cols-7 gap-1" role="rowgroup">
        {days.map(({ date, isCurrentMonth }, index) => {
          const isSelected = selectedDate && isSameDay(date, selectedDate)
          const isHovered = hoveredDate && isSameDay(date, hoveredDate)
          const isTodayDate = isToday(date)
          const isDisabled = isDateDisabled(date)
          const isFocused = focusedDate && isSameDay(date, focusedDate)
          const inRange = isDateInRange(date)
          const isRangeStartDate = isDateRangeStart(date)
          const isRangeEndDate = isDateRangeEnd(date)
          const isSingleDayRange = isRangeStartDate && isRangeEndDate

          return (
            <button
              key={index}
              type="button"
              role="gridcell"
              aria-selected={isSelected || undefined}
              aria-disabled={isDisabled || undefined}
              aria-current={isTodayDate ? "date" : undefined}
              tabIndex={isFocused ? 0 : -1}
              className={cn(
                "relative h-9 w-full rounded-xl text-sm font-medium transition-all duration-150 sm:h-10",
                "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
                "hover:bg-accent hover:text-accent-foreground",
                !isCurrentMonth && "text-muted-foreground/50",
                isCurrentMonth && "text-foreground",
                isDisabled && "cursor-not-allowed opacity-30 hover:bg-transparent",
                isTodayDate && !isSelected && "ring-2 ring-primary text-primary",
                isSelected && "bg-primary text-primary-foreground hover:bg-primary/90",
                isHovered && !isSelected && !isDisabled && "bg-accent",
                inRange && !isSelected && !isRangeStartDate && !isRangeEndDate && "bg-accent/50 rounded-none",
                isSingleDayRange && "rounded-full bg-primary text-primary-foreground",
                isRangeStartDate &&
                  !isSingleDayRange &&
                  "rounded-s-full rounded-e-none bg-primary text-primary-foreground",
                isRangeEndDate &&
                  !isSingleDayRange &&
                  "rounded-e-full rounded-s-none bg-primary text-primary-foreground",
                isFocused && "ring-2 ring-ring ring-offset-2",
              )}
              onClick={() => !isDisabled && onDateSelect(date)}
              onMouseEnter={() => !isDisabled && onDateHover(date)}
              onMouseLeave={() => onDateHover(null)}
              disabled={isDisabled}
            >
              {date.getDate()}
            </button>
          )
        })}
      </div>
    </div>
  )
}
