import React, { useMemo } from 'react';
import { ChevronLeft, ChevronRight, Calendar as CalendarIcon, Loader2, XCircle } from 'lucide-react';
import { usePublicAvailability, usePublicBusinessHours } from '../../hooks/useBooking';
import { formatTimeForDisplay, getTimezoneAbbreviation, getUserTimezone } from '../../utils/dateUtils';

interface DateTimeSelectionProps {
  serviceId?: number;
  selectedDate: Date | null;
  selectedTimeSlot: string | null;
  onDateChange: (date: Date) => void;
  onTimeChange: (time: string) => void;
}

export const DateTimeSelection: React.FC<DateTimeSelectionProps> = ({
  serviceId,
  selectedDate,
  selectedTimeSlot,
  onDateChange,
  onTimeChange
}) => {
  const today = new Date();
  const [currentMonth, setCurrentMonth] = React.useState(today.getMonth());
  const [currentYear, setCurrentYear] = React.useState(today.getFullYear());

  // Calculate date range for business hours query (current month view)
  const { startDate, endDate } = useMemo(() => {
    const start = new Date(currentYear, currentMonth, 1);
    const end = new Date(currentYear, currentMonth + 1, 0);
    return {
      startDate: `${start.getFullYear()}-${String(start.getMonth() + 1).padStart(2, '0')}-01`,
      endDate: `${end.getFullYear()}-${String(end.getMonth() + 1).padStart(2, '0')}-${String(end.getDate()).padStart(2, '0')}`
    };
  }, [currentMonth, currentYear]);

  // Fetch business hours for the month
  const { data: businessHours, isLoading: businessHoursLoading } = usePublicBusinessHours(startDate, endDate);

  // Create a map of dates to their open status
  const openDaysMap = useMemo(() => {
    const map = new Map<string, boolean>();
    if (businessHours?.dates) {
      businessHours.dates.forEach(day => {
        map.set(day.date, day.is_open);
      });
    }
    return map;
  }, [businessHours]);

  // Format selected date for API query (YYYY-MM-DD)
  const dateString = selectedDate
    ? `${selectedDate.getFullYear()}-${String(selectedDate.getMonth() + 1).padStart(2, '0')}-${String(selectedDate.getDate()).padStart(2, '0')}`
    : undefined;

  // Fetch availability when both serviceId and date are set
  const { data: availability, isLoading: availabilityLoading, isError, error } = usePublicAvailability(serviceId, dateString);

  const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate();
  const firstDayOfMonth = new Date(currentYear, currentMonth, 1).getDay();

  const handlePrevMonth = () => {
    if (currentMonth === 0) {
      setCurrentMonth(11);
      setCurrentYear(currentYear - 1);
    } else {
      setCurrentMonth(currentMonth - 1);
    }
  };

  const handleNextMonth = () => {
    if (currentMonth === 11) {
      setCurrentMonth(0);
      setCurrentYear(currentYear + 1);
    } else {
      setCurrentMonth(currentMonth + 1);
    }
  };

  const days = Array.from({ length: daysInMonth }, (_, i) => i + 1);
  const monthName = new Date(currentYear, currentMonth).toLocaleString('default', { month: 'long' });

  const isSelected = (day: number) => {
    return selectedDate?.getDate() === day &&
           selectedDate?.getMonth() === currentMonth &&
           selectedDate?.getFullYear() === currentYear;
  };

  const isPast = (day: number) => {
    const d = new Date(currentYear, currentMonth, day);
    const now = new Date();
    now.setHours(0, 0, 0, 0);
    return d < now;
  };

  const isClosed = (day: number) => {
    const dateStr = `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
    // If we have business hours data, use it. Otherwise default to open (except past dates)
    if (openDaysMap.size > 0) {
      return openDaysMap.get(dateStr) === false;
    }
    return false;
  };

  const isDisabled = (day: number) => {
    return isPast(day) || isClosed(day);
  };

  return (
    <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
      {/* Calendar Section */}
      <div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 shadow-sm">
        <div className="flex items-center justify-between mb-6">
          <h3 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center">
            <CalendarIcon className="w-5 h-5 mr-2 text-indigo-600 dark:text-indigo-400" />
            Select Date
          </h3>
          <div className="flex space-x-2">
            <button onClick={handlePrevMonth} className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full text-gray-600 dark:text-gray-400">
              <ChevronLeft className="w-5 h-5" />
            </button>
            <span className="font-medium text-gray-900 dark:text-white w-32 text-center">
              {monthName} {currentYear}
            </span>
            <button onClick={handleNextMonth} className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full text-gray-600 dark:text-gray-400">
              <ChevronRight className="w-5 h-5" />
            </button>
          </div>
        </div>

        <div className="grid grid-cols-7 gap-2 mb-2 text-center text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wide">
          <div>Sun</div><div>Mon</div><div>Tue</div><div>Wed</div><div>Thu</div><div>Fri</div><div>Sat</div>
        </div>

        {businessHoursLoading ? (
          <div className="flex items-center justify-center h-64">
            <Loader2 className="w-6 h-6 animate-spin text-indigo-600 dark:text-indigo-400" />
          </div>
        ) : (
          <div className="grid grid-cols-7 gap-2">
            {Array.from({ length: firstDayOfMonth }).map((_, i) => (
              <div key={`empty-${i}`} />
            ))}
            {days.map((day) => {
              const past = isPast(day);
              const closed = isClosed(day);
              const disabled = isDisabled(day);
              const selected = isSelected(day);

              return (
                <button
                  key={day}
                  disabled={disabled}
                  onClick={() => {
                    const newDate = new Date(currentYear, currentMonth, day);
                    onDateChange(newDate);
                  }}
                  className={`
                    h-10 w-10 rounded-full flex items-center justify-center text-sm font-medium transition-all relative
                    ${selected
                      ? 'bg-indigo-600 dark:bg-indigo-500 text-white shadow-md'
                      : closed
                        ? 'bg-gray-100 dark:bg-gray-700 text-gray-400 dark:text-gray-500 cursor-not-allowed'
                        : past
                          ? 'text-gray-300 dark:text-gray-600 cursor-not-allowed'
                          : 'text-gray-700 dark:text-gray-200 hover:bg-indigo-50 dark:hover:bg-indigo-900/30 hover:text-indigo-600 dark:hover:text-indigo-400'
                    }
                  `}
                  title={closed ? 'Business closed' : past ? 'Past date' : undefined}
                >
                  {day}
                </button>
              );
            })}
          </div>
        )}

        {/* Legend */}
        <div className="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700 flex items-center gap-4 text-xs text-gray-500 dark:text-gray-400">
          <div className="flex items-center gap-1.5">
            <div className="w-3 h-3 rounded-full bg-gray-100 dark:bg-gray-700"></div>
            <span>Closed</span>
          </div>
          <div className="flex items-center gap-1.5">
            <div className="w-3 h-3 rounded-full bg-indigo-600 dark:bg-indigo-500"></div>
            <span>Selected</span>
          </div>
        </div>
      </div>

      {/* Time Slots Section */}
      <div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 shadow-sm flex flex-col">
        <h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-6">Available Time Slots</h3>
        {!selectedDate ? (
          <div className="flex-1 flex items-center justify-center text-gray-400 dark:text-gray-500 italic">
            Please select a date first
          </div>
        ) : availabilityLoading ? (
          <div className="flex-1 flex items-center justify-center">
            <Loader2 className="w-6 h-6 animate-spin text-indigo-600 dark:text-indigo-400" />
          </div>
        ) : isError ? (
          <div className="flex-1 flex flex-col items-center justify-center text-red-500 dark:text-red-400">
            <XCircle className="w-12 h-12 mb-3" />
            <p className="font-medium">Failed to load availability</p>
            <p className="text-sm mt-1 text-gray-500 dark:text-gray-400">
              {error instanceof Error ? error.message : 'Please try again'}
            </p>
          </div>
        ) : availability?.is_open === false ? (
          <div className="flex-1 flex flex-col items-center justify-center text-gray-400 dark:text-gray-500">
            <XCircle className="w-12 h-12 mb-3 text-gray-300 dark:text-gray-600" />
            <p className="font-medium">Business Closed</p>
            <p className="text-sm mt-1">Please select another date</p>
          </div>
        ) : availability?.slots && availability.slots.length > 0 ? (
          <>
            {(() => {
              // Determine which timezone to display based on business settings
              const displayTimezone = availability.timezone_display_mode === 'viewer'
                ? getUserTimezone()
                : availability.business_timezone || getUserTimezone();
              const tzAbbrev = getTimezoneAbbreviation(displayTimezone);

              return (
                <>
                  <p className="text-xs text-gray-500 dark:text-gray-400 mb-4">
                    {availability.business_hours && (
                      <>Business hours: {availability.business_hours.start} - {availability.business_hours.end} • </>
                    )}
                    Times shown in {tzAbbrev}
                  </p>
                  <div className="grid grid-cols-2 gap-3">
                    {availability.slots.map((slot) => {
                      // Format time in the appropriate timezone
                      const displayTime = formatTimeForDisplay(
                        slot.time,
                        availability.timezone_display_mode === 'viewer' ? null : availability.business_timezone
                      );

                      return (
                        <button
                          key={slot.time}
                          disabled={!slot.available}
                          onClick={() => onTimeChange(displayTime)}
                          className={`
                            py-3 px-4 rounded-lg text-sm font-medium border transition-all duration-200
                            ${!slot.available
                              ? 'bg-gray-50 dark:bg-gray-700 text-gray-400 dark:text-gray-500 border-gray-100 dark:border-gray-600 cursor-not-allowed'
                              : selectedTimeSlot === displayTime
                                ? 'bg-indigo-600 dark:bg-indigo-500 text-white border-indigo-600 dark:border-indigo-500 shadow-sm'
                                : 'bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 border-gray-200 dark:border-gray-600 hover:border-indigo-500 dark:hover:border-indigo-400 hover:text-indigo-600 dark:hover:text-indigo-400'
                            }
                          `}
                        >
                          {displayTime}
                          {!slot.available && <span className="block text-[10px] font-normal">Booked</span>}
                        </button>
                      );
                    })}
                  </div>
                </>
              );
            })()}
          </>
        ) : !serviceId ? (
          <div className="flex-1 flex items-center justify-center text-gray-400 dark:text-gray-500 italic">
            Please select a service first
          </div>
        ) : (
          <div className="flex-1 flex items-center justify-center text-gray-400 dark:text-gray-500 italic">
            No available time slots for this date
          </div>
        )}
      </div>
    </div>
  );
};
