import React, { useState, useEffect } from 'react';
import { ChevronLeft, ChevronRight, Calendar, Clock } from 'lucide-react';

interface DateTimePickerProps {
  mode?: 'date' | 'time' | 'datetime';
  value?: Date | null;
  onChange?: (date: Date) => void;
  placeholder?: string;
  minDate?: Date | null;
  maxDate?: Date | null;
  size?: 'sm' | 'md';
  iconOnly?: boolean;
}

interface DayObject {
  day: number;
  isCurrentMonth: boolean;
  date: Date;
}

export const DateTimePicker: React.FC<DateTimePickerProps> = ({
  mode = 'datetime',
  value = null,
  onChange = () => {},
  placeholder = 'Select...',
  minDate = null,
  maxDate = null,
  size = 'md',
  iconOnly = false,
}) => {
  const [isOpen, setIsOpen] = useState<boolean>(false);
  const [openUpward, setOpenUpward] = useState<boolean>(false);
  const triggerRef = React.useRef<HTMLButtonElement | null>(null);
  // Normalizer: for pure date mode, keep time at midday to avoid timezone boundary shifting (off-by-one issue)
  const normalizeDate = (d: Date) => {
    if (mode === 'date') return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 12, 0, 0, 0);
    return d;
  };
  const [selectedDate, setSelectedDate] = useState<Date | null>(
    value ? normalizeDate(new Date(value)) : null,
  );
  const [viewDate, setViewDate] = useState<Date>(
    value ? normalizeDate(new Date(value)) : normalizeDate(new Date()),
  );
  const [viewMode, setViewMode] = useState<'days' | 'months' | 'years'>('days');
  const [selectedHour, setSelectedHour] = useState<number>(value ? new Date(value).getHours() : 12);
  const [selectedMinute, setSelectedMinute] = useState<number>(
    value ? new Date(value).getMinutes() : 0,
  );

  const months: string[] = [
    'Jan',
    'Feb',
    'Mar',
    'Apr',
    'May',
    'Jun',
    'Jul',
    'Aug',
    'Sep',
    'Oct',
    'Nov',
    'Dec',
  ];
  const daysOfWeek: string[] = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];

  useEffect(() => {
    if (value) {
      const date = normalizeDate(new Date(value));
      setSelectedDate(date);
      setViewDate(date);
      setSelectedHour(date.getHours());
      setSelectedMinute(date.getMinutes());
    } else {
      setSelectedDate(null);
    }
  }, [value]);

  const getDaysInMonth = (year: number, month: number): number => {
    return new Date(year, month + 1, 0).getDate();
  };

  const getFirstDayOfMonth = (year: number, month: number): number => {
    return new Date(year, month, 1).getDay();
  };

  const generateCalendarDays = (): DayObject[] => {
    const year = viewDate.getFullYear();
    const month = viewDate.getMonth();
    const daysInMonth = getDaysInMonth(year, month);
    const firstDay = getFirstDayOfMonth(year, month);
    const daysInPrevMonth = getDaysInMonth(year, month - 1);

    const days: DayObject[] = [];

    // Previous month days
    for (let i = firstDay - 1; i >= 0; i--) {
      days.push({
        day: daysInPrevMonth - i,
        isCurrentMonth: false,
        date: new Date(year, month - 1, daysInPrevMonth - i),
      });
    }

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

    // Next month days
    const remainingDays = 42 - days.length;
    for (let i = 1; i <= remainingDays; i++) {
      days.push({
        day: i,
        isCurrentMonth: false,
        date: new Date(year, month + 1, i),
      });
    }

    return days;
  };

  const isDateDisabled = (date: Date): boolean => {
    if (minDate && date < new Date(minDate)) return true;
    if (maxDate && date > new Date(maxDate)) return true;
    return false;
  };

  const isSameDay = (date1: Date, date2: Date | null): boolean => {
    if (!date2) return false;
    return (
      date1.getDate() === date2.getDate() &&
      date1.getMonth() === date2.getMonth() &&
      date1.getFullYear() === date2.getFullYear()
    );
  };

  const handleDayClick = (dayObj: DayObject): void => {
    if (!dayObj.isCurrentMonth || isDateDisabled(dayObj.date)) return;

    const base = new Date(
      dayObj.date.getFullYear(),
      dayObj.date.getMonth(),
      dayObj.date.getDate(),
      mode === 'date' ? 12 : selectedHour,
      mode === 'date' ? 0 : selectedMinute,
      0,
      0,
    );
    if (mode !== 'date') {
      base.setHours(selectedHour);
      base.setMinutes(selectedMinute);
    }
    const newDate = normalizeDate(base);
    setSelectedDate(newDate);

    if (mode === 'date') {
      onChange(newDate);
      setIsOpen(false);
    }
  };

  const handleMonthClick = (monthIndex: number): void => {
    const newDate = new Date(viewDate);
    newDate.setMonth(monthIndex);
    setViewDate(newDate);
    setViewMode('days');
  };

  const handleYearClick = (year: number): void => {
    const newDate = new Date(viewDate);
    newDate.setFullYear(year);
    setViewDate(newDate);
    setViewMode('months');
  };

  const handleTimeChange = (): void => {
    const baseDate = selectedDate ?? normalizeDate(new Date(viewDate));
    const newDate = new Date(
      baseDate.getFullYear(),
      baseDate.getMonth(),
      baseDate.getDate(),
      selectedHour,
      selectedMinute,
      0,
      0,
    );
    const normalized = normalizeDate(newDate);
    setSelectedDate(normalized);
    onChange(normalized);
    setIsOpen(false);
  };

  const formatDisplayValue = (): string => {
    const date = value ? new Date(value) : selectedDate;
    if (!date) return placeholder;

    if (mode === 'date') {
      return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
    } else if (mode === 'time') {
      return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
    } else {
      return date.toLocaleString('en-US', {
        year: 'numeric',
        month: 'short',
        day: 'numeric',
        hour: '2-digit',
        minute: '2-digit',
      });
    }
  };

  const changeMonth = (delta: number): void => {
    const newDate = new Date(viewDate);
    newDate.setMonth(newDate.getMonth() + delta);
    setViewDate(newDate);
  };

  const changeYear = (delta: number): void => {
    const newDate = new Date(viewDate);
    newDate.setFullYear(newDate.getFullYear() + delta);
    setViewDate(newDate);
  };

  const handlePrevious = (): void => {
    if (viewMode === 'days') {
      changeMonth(-1);
    } else if (viewMode === 'months') {
      changeYear(-1);
    } else {
      changeYear(-12);
    }
  };

  const handleNext = (): void => {
    if (viewMode === 'days') {
      changeMonth(1);
    } else if (viewMode === 'months') {
      changeYear(1);
    } else {
      changeYear(12);
    }
  };

  const generateYears = (): number[] => {
    const currentYear = viewDate.getFullYear();
    const startYear = Math.floor(currentYear / 12) * 12;
    return Array.from({ length: 12 }, (_, i) => startYear + i);
  };

  const getHeaderText = (): string => {
    if (viewMode === 'days') {
      return `${months[viewDate.getMonth()]} ${viewDate.getFullYear()}`;
    } else if (viewMode === 'months') {
      return viewDate.getFullYear().toString();
    } else {
      const startYear = Math.floor(viewDate.getFullYear() / 12) * 12;
      return `${startYear} - ${startYear + 11}`;
    }
  };

  const handleHeaderClick = (): void => {
    if (viewMode === 'days') {
      setViewMode('months');
    } else if (viewMode === 'months') {
      setViewMode('years');
    } else {
      setViewMode('months');
    }
  };

  const handleHourChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
    const value = parseInt(e.target.value) || 0;
    setSelectedHour(Math.min(23, Math.max(0, value)));
  };

  const handleMinuteChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
    const value = parseInt(e.target.value) || 0;
    setSelectedMinute(Math.min(59, Math.max(0, value)));
  };

  return (
    <div className="relative w-full max-w-sm">
      <button
        ref={triggerRef}
        type="button"
        aria-label={iconOnly ? placeholder : undefined}
        onClick={() => {
          const willOpen = !isOpen;
          if (!isOpen && triggerRef.current) {
            const rect = triggerRef.current.getBoundingClientRect();
            const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
            const spaceBelow = viewportHeight - rect.bottom;
            const spaceAbove = rect.top;
            let estimatedHeight: number;
            if (mode === 'time') {
              estimatedHeight = size === 'sm' ? 220 : 260;
            } else if (mode === 'date') {
              estimatedHeight = size === 'sm' ? 300 : 340;
            } else {
              // datetime
              estimatedHeight = size === 'sm' ? 420 : 480;
            }
            // Open upward if there's not enough space below AND there's more space above
            setOpenUpward(spaceBelow < estimatedHeight && spaceAbove > spaceBelow);
          }
          setIsOpen(willOpen);
        }}
        className={`w-full ${size === 'sm' ? 'px-3 py-2' : 'px-4 py-2.5'} bg-white dark:bg-gray-900 border border-gray-300 dark:border-gray-700 rounded-lg text-left flex items-center ${iconOnly ? 'justify-center' : 'justify-between'} hover:border-brand-400 dark:hover:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500 focus:border-transparent transition-all`}
      >
        {!iconOnly && (
          <span
            className={`text-gray-700 dark:text-gray-200 truncate ${size === 'sm' ? 'text-sm' : ''}`}
          >
            {formatDisplayValue()}
          </span>
        )}
        {mode === 'time' ? (
          <Clock
            className={`${size === 'sm' ? 'w-4 h-4' : 'w-5 h-5'} text-gray-400 dark:text-gray-500 flex-shrink-0 ${iconOnly ? '' : 'ml-2'}`}
          />
        ) : (
          <Calendar
            className={`${size === 'sm' ? 'w-4 h-4' : 'w-5 h-5'} text-gray-400 dark:text-gray-500 flex-shrink-0 ${iconOnly ? '' : 'ml-2'}`}
          />
        )}
      </button>

      {isOpen && (
        <>
          <button
            type="button"
            className="fixed inset-0 z-40 cursor-default focus:outline-none"
            aria-label="Close date picker"
            onClick={() => setIsOpen(false)}
            onKeyDown={(e) => {
              if (e.key === 'Escape' || e.key === 'Enter' || e.key === ' ') {
                setIsOpen(false);
              }
            }}
          />
          <div
            className={`absolute z-50 ${openUpward ? 'bottom-full mb-2' : 'mt-2'} bg-white dark:bg-gray-900 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 ${size === 'sm' ? 'p-3' : 'p-4'} w-full min-w-[260px] ${size === 'sm' ? 'max-w-xs' : 'max-w-sm'} max-h-[70vh] overflow-y-auto overscroll-contain`}
            style={{
              scrollbarWidth: 'thin',
            }}
          >
            {(mode === 'date' || mode === 'datetime') && (
              <div className="mb-4">
                {/* Header */}
                <div className="flex items-center justify-between mb-4">
                  <button
                    type="button"
                    onClick={handlePrevious}
                    className={`p-1 hover:bg-gray-100 dark:hover:bg-gray-800 rounded transition-colors`}
                  >
                    <ChevronLeft
                      className={`${size === 'sm' ? 'w-4 h-4' : 'w-5 h-5'} text-gray-600 dark:text-gray-300`}
                    />
                  </button>

                  <div className="flex gap-2">
                    <button
                      type="button"
                      onClick={handleHeaderClick}
                      className={`${size === 'sm' ? 'px-2 py-1 text-sm' : 'px-3 py-1'} hover:bg-gray-100 dark:hover:bg-gray-800 rounded font-medium text-gray-700 dark:text-gray-200 transition-colors`}
                    >
                      {getHeaderText()}
                    </button>
                  </div>

                  <button
                    type="button"
                    onClick={handleNext}
                    className={`p-1 hover:bg-gray-100 dark:hover:bg-gray-800 rounded transition-colors`}
                  >
                    <ChevronRight
                      className={`${size === 'sm' ? 'w-4 h-4' : 'w-5 h-5'} text-gray-600 dark:text-gray-300`}
                    />
                  </button>
                </div>

                {/* Days View */}
                {viewMode === 'days' && (
                  <>
                    <div className="grid grid-cols-7 gap-1 mb-2">
                      {daysOfWeek.map((day) => (
                        <div
                          key={day}
                          className={`text-center ${size === 'sm' ? 'text-[10px]' : 'text-xs'} font-medium text-gray-500 dark:text-gray-400 py-1`}
                        >
                          {day}
                        </div>
                      ))}
                    </div>
                    <div className={`grid grid-cols-7 gap-1`}>
                      {generateCalendarDays().map((dayObj) => (
                        <button
                          key={dayObj.date.toISOString()}
                          type="button"
                          onClick={() => handleDayClick(dayObj)}
                          disabled={!dayObj.isCurrentMonth || isDateDisabled(dayObj.date)}
                          className={`
                            ${size === 'sm' ? 'p-1.5 text-[13px]' : 'p-2 text-sm'} rounded transition-all
                            ${!dayObj.isCurrentMonth ? 'text-gray-300 dark:text-gray-600 cursor-default' : 'text-gray-700 dark:text-gray-200 hover:bg-brand-50 dark:hover:bg-brand-500/10'}
                            ${isSameDay(dayObj.date, selectedDate) && dayObj.isCurrentMonth ? 'bg-brand-500 text-white hover:bg-brand-600' : ''}
                            ${isSameDay(dayObj.date, new Date()) && dayObj.isCurrentMonth && !isSameDay(dayObj.date, selectedDate) ? 'border border-brand-500 dark:border-brand-400' : ''}
                            ${isDateDisabled(dayObj.date) && dayObj.isCurrentMonth ? 'text-gray-300 dark:text-gray-600 cursor-not-allowed' : ''}
                          `}
                        >
                          {dayObj.day}
                        </button>
                      ))}
                    </div>
                  </>
                )}

                {/* Months View */}
                {viewMode === 'months' && (
                  <div className={`grid grid-cols-3 ${size === 'sm' ? 'gap-1.5' : 'gap-2'}`}>
                    {months.map((month, idx) => (
                      <button
                        key={month}
                        type="button"
                        onClick={() => handleMonthClick(idx)}
                        className={`
                          ${size === 'sm' ? 'p-2 text-[13px]' : 'p-3 text-sm'} rounded transition-all hover:bg-brand-50 dark:hover:bg-brand-500/10
                          ${viewDate.getMonth() === idx ? 'bg-brand-500 text-white hover:bg-brand-600' : 'text-gray-700 dark:text-gray-200'}
                        `}
                      >
                        {month}
                      </button>
                    ))}
                  </div>
                )}

                {/* Years View */}
                {viewMode === 'years' && (
                  <div className={`grid grid-cols-3 ${size === 'sm' ? 'gap-1.5' : 'gap-2'}`}>
                    {generateYears().map((year) => (
                      <button
                        key={year}
                        type="button"
                        onClick={() => handleYearClick(year)}
                        className={`
                          ${size === 'sm' ? 'p-2 text-[13px]' : 'p-3 text-sm'} rounded transition-all hover:bg-brand-50 dark:hover:bg-brand-500/10
                          ${viewDate.getFullYear() === year ? 'bg-brand-500 text-white hover:bg-brand-600' : 'text-gray-700 dark:text-gray-200'}
                        `}
                      >
                        {year}
                      </button>
                    ))}
                  </div>
                )}
              </div>
            )}

            {(mode === 'time' || mode === 'datetime') && (
              <div className="space-y-3">
                {mode === 'datetime' && (
                  <div className="border-t border-gray-200 dark:border-gray-700 pt-3" />
                )}
                <div
                  className={`flex items-center justify-center ${size === 'sm' ? 'gap-3' : 'gap-4'}`}
                >
                  <div className="flex flex-col items-center">
                    <label
                      htmlFor="dtp-hour"
                      className={`${size === 'sm' ? 'text-[11px]' : 'text-xs'} text-gray-500 dark:text-gray-400 mb-2`}
                    >
                      Hour
                    </label>
                    <input
                      id="dtp-hour"
                      type="number"
                      min="0"
                      max="23"
                      value={selectedHour}
                      onChange={handleHourChange}
                      className={`${size === 'sm' ? 'w-14 px-2.5 py-1.5 text-sm' : 'w-16 px-3 py-2'} border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 rounded text-center focus:outline-none focus:ring-2 focus:ring-brand-500`}
                    />
                  </div>
                  <span
                    className={`${size === 'sm' ? 'text-xl mt-5' : 'text-2xl mt-6'} text-gray-400 dark:text-gray-500`}
                  >
                    :
                  </span>
                  <div className="flex flex-col items-center">
                    <label
                      htmlFor="dtp-minute"
                      className={`${size === 'sm' ? 'text-[11px]' : 'text-xs'} text-gray-500 dark:text-gray-400 mb-2`}
                    >
                      Minute
                    </label>
                    <input
                      id="dtp-minute"
                      type="number"
                      min="0"
                      max="59"
                      value={selectedMinute.toString().padStart(2, '0')}
                      onChange={handleMinuteChange}
                      className={`${size === 'sm' ? 'w-14 px-2.5 py-1.5 text-sm' : 'w-16 px-3 py-2'} border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 rounded text-center focus:outline-none focus:ring-2 focus:ring-brand-500`}
                    />
                  </div>
                </div>
                <button
                  type="button"
                  onClick={handleTimeChange}
                  className={`w-full ${size === 'sm' ? 'py-1.5 text-sm' : 'py-2'} bg-brand-500 text-white rounded hover:bg-brand-600 transition-colors font-medium`}
                >
                  Confirm
                </button>
              </div>
            )}
          </div>
        </>
      )}
    </div>
  );
};
