import React, { useState, useEffect, useRef } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import EventCard from './EventCard';
import { parseISO, startOfDay, isSameDay, isAfter, format, startOfMonth } from 'date-fns';
import { events, Event } from '../eventData';

export const formatTime = (dateString: string, time: string): string => {
  const date = parseISO(dateString);
  const [hours, minutes] = time.split(':');
  const eventDate = new Date(date.setHours(parseInt(hours, 10), parseInt(minutes, 10)));
  return format(eventDate, 'h:mm a');
};

export const formatDateRange = (startDate: string, startTime: string, endDate: string, endTime: string): string => {
  const start = parseISO(`${startDate}T${startTime}`);
  const end = parseISO(`${endDate}T${endTime}`);

  if (isSameDay(start, end)) {
    return `${format(start, 'MMMM d, yyyy')}\n${formatTime(startDate, startTime)} - ${formatTime(endDate, endTime)}`;
  } else {
    return `${format(start, 'MMMM d, yyyy')}\n${formatTime(startDate, startTime)} - ${format(end, 'MMMM d, yyyy')}\n${formatTime(endDate, endTime)}`;
  }
};

const EventPopup: React.FC<{ event: Event; position: { top: number; left: number }; onClose: () => void }> = ({ event, position, onClose }) => (
  <motion.div
    initial={{ opacity: 0, y: -20 }}
    animate={{ opacity: 1, y: 0 }}
    exit={{ opacity: 0, y: -20 }}
    className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 p-4"
    onClick={onClose}
    role="dialog"
    aria-modal="true"
    aria-label={`Event Details: ${event.title}`}
  >
    <motion.div
      className="bg-white p-4 rounded-lg shadow-lg max-w-xs w-full relative"
      onClick={(e) => e.stopPropagation()}
    >
      <button
        onClick={onClose}
        className="absolute top-2 right-2 p-2 text-gray-600 hover:text-gray-900"
        aria-label="Close event details"
      >
        ×
      </button>
      <h3 className="font-bold text-lg">{event.title}</h3>
      <p className="text-sm whitespace-pre-line">{formatDateRange(event.date, event.startTime, event.date, event.endTime)}</p>
      <p className="text-sm mt-2">{event.description}</p>
      <p className="text-sm mt-2">Address: {event.address}</p>
      <p className="text-sm mt-2">Contact: <a href={`mailto:${event.email}`} className="text-blue-500 hover:underline">{event.pointOfContact}</a></p>
    </motion.div>
  </motion.div>
);

const Calendar: React.FC = () => {
  const [currentMonth, setCurrentMonth] = useState(() => {
    const now = new Date();
    return startOfMonth(now);
  });
  const [selectedEvent, setSelectedEvent] = useState<Event | null>(null);
  const calendarRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent | TouchEvent) => {
      if (selectedEvent && calendarRef.current && !calendarRef.current.contains(event.target as Node)) {
        setSelectedEvent(null);
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    document.addEventListener('touchstart', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
      document.removeEventListener('touchstart', handleClickOutside);
    };
  }, [selectedEvent]);

  useEffect(() => {
    const handleEscapeKey = (event: KeyboardEvent) => {
      if (event.key === 'Escape' && selectedEvent) {
        setSelectedEvent(null);
      }
    };

    document.addEventListener('keydown', handleEscapeKey);
    return () => {
      document.removeEventListener('keydown', handleEscapeKey);
    };
  }, [selectedEvent]);

  const isEventUpcoming = (eventDate: string) => {
    const today = startOfDay(new Date());
    const parsedEventDate = startOfDay(parseISO(eventDate));
    return isSameDay(parsedEventDate, today) || isAfter(parsedEventDate, today);
  };

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

  const days = Array.from({ length: daysInMonth }, (_, i) => i + 1);
  const emptyDays = Array.from({ length: firstDayOfMonth }, (_, i) => i);

  const monthNames = ["January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "November", "December"
  ];

  const nextMonth = () => {
    setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1));
  };

  const prevMonth = () => {
    setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1));
  };

  const handleEventClick = (event: Event) => {
    setSelectedEvent(event);
  };

  const upcomingEvents = events
    .filter(event => isEventUpcoming(event.date))
    .sort((a, b) => parseISO(a.date).getTime() - parseISO(b.date).getTime());

  return (
    <div className="max-w-4xl mx-auto p-4 sm:p-6 relative" ref={calendarRef}>
      <div className="flex justify-between items-center mb-6">
        <motion.button
          whileHover={{ scale: 1.1 }}
          whileTap={{ scale: 0.9 }}
          className="text-2xl text-[#8C1D40]"
          onClick={prevMonth}
          aria-label={`Previous month: ${monthNames[(currentMonth.getMonth() - 1 + 12) % 12]}`}
        >
          ←
        </motion.button>
        <h2 className="text-xl sm:text-2xl font-bold text-[#8C1D40]" role="heading" aria-level={2}>
          {monthNames[currentMonth.getMonth()]} {currentMonth.getFullYear()}
        </h2>
        <motion.button
          whileHover={{ scale: 1.1 }}
          whileTap={{ scale: 0.9 }}
          className="text-2xl text-[#8C1D40]"
          onClick={nextMonth}
          aria-label={`Next month: ${monthNames[(currentMonth.getMonth() + 1) % 12]}`}
        >
          →
        </motion.button>
      </div>
      <div 
        className="grid grid-cols-7 gap-1 bg-gray-200 rounded-lg overflow-hidden"
        role="grid"
        aria-label="Calendar"
      >
        {['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'].map(day => (
          <div 
            key={day} 
            className="bg-[#8C1D40] text-white font-bold p-2 text-center text-xs sm:text-sm"
            role="columnheader"
            aria-label={day}
          >
            {day.charAt(0)}
          </div>
        ))}
        {emptyDays.map(day => (
          <div 
            key={`empty-${day}`} 
            className="bg-white p-2 h-16 sm:h-24"
            role="gridcell"
            aria-hidden="true"
          ></div>
        ))}
        {days.map(day => {
          const currentDate = new Date(currentMonth.getFullYear(), currentMonth.getMonth(), day);
          const dateString = format(currentDate, 'yyyy-MM-dd');
          const dayEvents = events.filter(event => event.date === dateString);

          return (
            <motion.div
              key={day}
              className="bg-white p-1 sm:p-2 h-16 sm:h-24 cursor-pointer flex flex-col items-start justify-start overflow-hidden"
              whileHover={{ backgroundColor: '#FFCCCB' }}
              role="gridcell"
              aria-label={`${format(currentDate, 'MMMM d, yyyy')}${dayEvents.length ? `. ${dayEvents.length} events scheduled` : '. No events'}`}
            >
              <span className="font-semibold text-xs sm:text-sm">{day}</span>
              {dayEvents.map((event, index) => (
                <button 
                  key={index} 
                  className="text-xs bg-[#8C1D40] text-white p-1 mt-1 rounded w-full truncate"
                  onClick={() => handleEventClick(event)}
                  aria-label={`${event.title} on ${format(parseISO(event.date), 'MMMM d')} from ${formatTime(event.date, event.startTime)} to ${formatTime(event.date, event.endTime)}`}
                >
                  <div className="truncate">{event.title}</div>
                  <div className="hidden sm:block">
                    {formatTime(event.date, event.startTime)} - {formatTime(event.date, event.endTime)}
                  </div>
                </button>
              ))}
            </motion.div>
          );
        })}
      </div>
      <AnimatePresence>
        {selectedEvent && (
          <EventPopup 
            event={selectedEvent} 
            position={{ top: 0, left: 0 }}
            onClose={() => setSelectedEvent(null)}
          />
        )}
      </AnimatePresence>
      
      <div className="mt-12">
        <h2 className="text-xl sm:text-2xl font-bold text-[#8C1D40] mb-6" role="heading" aria-level={2}>
          Upcoming Events
        </h2>
        <div 
          className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 justify-items-center"
          role="list"
          aria-label="List of upcoming events"
        >
          {upcomingEvents.map((event, index) => (
            <div key={index} role="listitem">
              <EventCard
                event={{
                  ...event,
                  formattedDateRange: formatDateRange(event.date, event.startTime, event.date, event.endTime)
                }}
              />
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

export default Calendar;