import { useState } from "react";
import conferencesData from "@/data/conferences.yml";
import { Conference } from "@/types/conference";
import { Calendar as CalendarIcon, Tag } from "lucide-react";
import { Calendar } from "@/components/ui/calendar";
import { parseISO, format, isValid, isSameMonth, isSameYear, isSameDay, isSameWeek } from "date-fns";
import { Toggle } from "@/components/ui/toggle";
import Header from "@/components/Header";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";

const categoryColors: Record<string, string> = {
  "computer-vision": "bg-orange-500",
  "machine-learning": "bg-purple-500",
  "natural-language-processing": "bg-blue-500",
  "robotics": "bg-green-500",
  "data-mining": "bg-pink-500",
  "signal-processing": "bg-cyan-500",
  "human-computer-interaction": "bg-indigo-500",
  "web-search": "bg-yellow-500",
};

const categoryNames: Record<string, string> = {
  "computer-vision": "Computer Vision",
  "machine-learning": "Machine Learning",
  "natural-language-processing": "NLP",
  "robotics": "Robotics",
  "data-mining": "Data Mining",
  "signal-processing": "Signal Processing",
  "human-computer-interaction": "HCI",
  "web-search": "Web Search",
};

const CalendarPage = () => {
  const [selectedDate, setSelectedDate] = useState<Date | undefined>(new Date());
  const [isYearView, setIsYearView] = useState(true);
  const [searchQuery, setSearchQuery] = useState("");
  const [selectedDayEvents, setSelectedDayEvents] = useState<{ date: Date | null, events: { deadlines: Conference[], conferences: Conference[] } }>({
    date: null,
    events: { deadlines: [], conferences: [] }
  });
  const [selectedCategories, setSelectedCategories] = useState<Set<string>>(
    new Set(Object.keys(categoryColors))
  );
  const [showDeadlines, setShowDeadlines] = useState(true);
  
  const safeParseISO = (dateString: string | undefined | number): Date | null => {
    if (!dateString) return null;
    if (dateString === 'TBD') return null;
    
    const isDate = (value: any): value is Date => {
      return value && Object.prototype.toString.call(value) === '[object Date]';
    };

    if (isDate(dateString)) return dateString;
    
    try {
      if (typeof dateString === 'object') {
        return null;
      }
      
      const dateStr = typeof dateString === 'number' ? dateString.toString() : dateString;
      
      let normalizedDate = dateStr;
      const parts = dateStr.split('-');
      if (parts.length === 3) {
        normalizedDate = `${parts[0]}-${parts[1].padStart(2, '0')}-${parts[2].padStart(2, '0')}`;
      }
      
      const parsedDate = parseISO(normalizedDate);
      return isValid(parsedDate) ? parsedDate : null;
    } catch (error) {
      console.error("Error parsing date:", dateString);
      return null;
    }
  };

  const getEvents = (date: Date) => {
    return conferencesData.filter((conf: Conference) => {
      const matchesSearch = searchQuery === "" || 
        conf.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
        (conf.full_name && conf.full_name.toLowerCase().includes(searchQuery.toLowerCase()));

      const matchesCategory = selectedCategories.size === 0 || 
        (Array.isArray(conf.tags) && conf.tags.some(tag => selectedCategories.has(tag)));

      if (!matchesSearch || !matchesCategory) return false;

      const deadlineDate = safeParseISO(conf.deadline);
      const startDate = safeParseISO(conf.start);
      const endDate = safeParseISO(conf.end);

      const dateMatches = isYearView ? isSameYear : isSameMonth;

      const deadlineInPeriod = showDeadlines && deadlineDate && dateMatches(deadlineDate, date);
      
      let conferenceInPeriod = false;
      if (startDate && endDate) {
        let currentDate = new Date(startDate);
        while (currentDate <= endDate) {
          if (dateMatches(currentDate, date)) {
            conferenceInPeriod = true;
            break;
          }
          currentDate.setDate(currentDate.getDate() + 1);
        }
      } else if (startDate) {
        conferenceInPeriod = dateMatches(startDate, date);
      }

      return deadlineInPeriod || conferenceInPeriod;
    });
  };

  const getDayEvents = (date: Date) => {
    const deadlines = showDeadlines ? conferencesData.filter(conf => {
      const deadlineDate = safeParseISO(conf.deadline);
      const matchesCategory = selectedCategories.size === 0 || 
        (Array.isArray(conf.tags) && conf.tags.some(tag => selectedCategories.has(tag)));
      return deadlineDate && isSameDay(deadlineDate, date) && matchesCategory;
    }) : [];

    const conferences = conferencesData.filter(conf => {
      const startDate = safeParseISO(conf.start);
      const endDate = safeParseISO(conf.end);
      const matchesCategory = selectedCategories.size === 0 || 
        (Array.isArray(conf.tags) && conf.tags.some(tag => selectedCategories.has(tag)));
      return startDate && endDate && 
             date >= startDate && 
             date <= endDate && 
             matchesCategory;
    });

    return {
      deadlines,
      conferences
    };
  };

  const renderEventPreview = (events: { deadlines: Conference[], conferences: Conference[] }) => {
    if (events.deadlines.length === 0 && events.conferences.length === 0) return null;
    
    return (
      <div className="p-2 max-w-[200px]">
        {events.deadlines.length > 0 && (
          <div className="mb-2">
            <p className="font-semibold text-red-500">Deadlines:</p>
            {events.deadlines.map(conf => (
              <div key={conf.id} className="text-sm">{conf.title}</div>
            ))}
          </div>
        )}
        {events.conferences.length > 0 && (
          <div>
            <p className="font-semibold text-purple-600">Conferences:</p>
            {events.conferences.map(conf => (
              <div key={conf.id} className="text-sm">{conf.title}</div>
            ))}
          </div>
        )}
      </div>
    );
  };

  const isEndOfWeek = (date: Date) => date.getDay() === 6; // Saturday
  const isStartOfWeek = (date: Date) => date.getDay() === 0; // Sunday

  const getConferenceLineStyle = (date: Date) => {
    return conferencesData
      .filter(conf => {
        const startDate = safeParseISO(conf.start);
        const endDate = safeParseISO(conf.end);
        const matchesCategory = selectedCategories.size === 0 || 
          (Array.isArray(conf.tags) && conf.tags.some(tag => selectedCategories.has(tag)));
        return startDate && endDate && date >= startDate && date <= endDate && matchesCategory;
      })
      .map(conf => {
        const startDate = safeParseISO(conf.start);
        const endDate = safeParseISO(conf.end);
        
        if (!startDate || !endDate) return null;

        let style = "w-[calc(100%+1rem)] -left-2 relative";
        
        if (isSameDay(date, startDate)) {
          style += " rounded-l-sm";
        }
        if (isSameDay(date, endDate)) {
          style += " rounded-r-sm";
        }
        
        const color = conf.tags && conf.tags[0] ? categoryColors[conf.tags[0]] : "bg-gray-500";

        return { style, color };
      })
      .filter(Boolean);
  };

  const renderDayContent = (date: Date) => {
    const dayEvents = getDayEvents(date);
    const hasEvents = dayEvents.deadlines.length > 0 || dayEvents.conferences.length > 0;

    const conferenceStyles = getConferenceLineStyle(date);

    const hasDeadline = showDeadlines && dayEvents.deadlines.length > 0;

    const handleDayClick = (e: React.MouseEvent) => {
      e.preventDefault(); // Prevent default calendar behavior
      e.stopPropagation(); // Stop event propagation
      setSelectedDayEvents({
        date,
        events: dayEvents
      });
    };

    return (
      <div 
        className="relative w-full h-full flex flex-col"
        onClick={handleDayClick}
      >
        <div className="h-10 flex items-center justify-center">
          <span>{format(date, 'd')}</span>
        </div>

        <div className="absolute bottom-2 left-0 right-0 flex flex-col-reverse gap-[1px]">
          {conferenceStyles.map((style, index) => (
            <div 
              key={`conf-${index}`} 
              className={`h-[2px] ${style.style} ${style.color}`} 
            />
          ))}
          {hasDeadline && (
            <div className="h-[2px] w-[calc(100%+1rem)] -left-2 relative bg-red-500" />
          )}
        </div>

        {hasEvents && (
          <TooltipProvider>
            <Tooltip>
              <TooltipTrigger className="absolute inset-0" />
              <TooltipContent>
                {renderEventPreview(dayEvents)}
              </TooltipContent>
            </Tooltip>
          </TooltipProvider>
        )}
      </div>
    );
  };

  const renderEventDetails = (conf: Conference) => {
    const deadlineDate = safeParseISO(conf.deadline);
    const startDate = safeParseISO(conf.start);
    const endDate = safeParseISO(conf.end);

    return (
      <div className="border-b last:border-b-0 pb-4 last:pb-0 mb-4 last:mb-0">
        <div className="flex justify-between items-start">
          <div>
            <h3 className="font-semibold text-lg text-neutral-900">{conf.title}</h3>
            {conf.full_name && (
              <p className="text-sm text-neutral-600 mb-2">{conf.full_name}</p>
            )}
          </div>
          {conf.link && (
            <a 
              href={conf.link} 
              target="_blank" 
              rel="noopener noreferrer" 
              className="text-blue-500 hover:text-blue-600 flex items-center gap-1 text-sm"
            >
              Website
              <svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor">
                <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
                <polyline points="15 3 21 3 21 9" />
                <line x1="10" y1="14" x2="21" y2="3" />
              </svg>
            </a>
          )}
        </div>
        
        <div className="space-y-2 mt-3">
          {deadlineDate && (
            <div className="flex items-start gap-2">
              <span className="font-medium text-sm text-neutral-900">Deadline:</span>
              <div className="text-sm text-neutral-900">
                <div>{format(deadlineDate, 'MMMM d, yyyy')}</div>
                {conf.timezone && (
                  <div className="text-neutral-500 text-xs">
                    Timezone: {conf.timezone}
                  </div>
                )}
              </div>
            </div>
          )}
          
          {startDate && (
            <div className="flex items-start gap-2">
              <span className="font-medium text-sm text-neutral-900">Date:</span>
              <div className="text-sm text-neutral-900">
                <div>
                  {format(startDate, 'MMMM d')}
                  {endDate ? ` - ${format(endDate, 'MMMM d, yyyy')}` : 
                    `, ${format(startDate, 'yyyy')}`}
                </div>
              </div>
            </div>
          )}

          {conf.place && (
            <div className="flex items-start gap-2">
              <span className="font-medium text-sm text-neutral-900">Location:</span>
              <span className="text-sm text-neutral-900">{conf.place}</span>
            </div>
          )}

          {conf.note && (
            <div className="flex items-start gap-2 mt-2">
              <span className="font-medium text-sm text-neutral-900">Note:</span>
              <div className="text-sm text-neutral-900" 
                dangerouslySetInnerHTML={{ __html: conf.note }} 
              />
            </div>
          )}
        </div>

        <div className="mt-3 flex flex-wrap gap-2">
          {Array.isArray(conf.tags) && conf.tags.map((tag) => (
            <span 
              key={tag} 
              className="inline-flex items-center px-2 py-1 rounded-full text-xs bg-neutral-100 text-neutral-900"
            >
              <Tag className="h-3 w-3 mr-1" />
              {categoryNames[tag] || tag}
            </span>
          ))}
        </div>
      </div>
    );
  };

  const categories = Object.entries(categoryColors).filter(([category]) => 
    conferencesData.some(conf => conf.tags?.includes(category))
  );

  const renderLegend = () => {
    return (
      <div className="flex flex-wrap gap-3 justify-center items-center mb-4">
        <TooltipProvider>
          <Tooltip>
            <TooltipTrigger asChild>
              <button
                onClick={() => setShowDeadlines(!showDeadlines)}
                className={`
                  flex items-center gap-2 px-3 py-1.5 
                  rounded-lg border border-red-200 
                  bg-white hover:bg-red-50 
                  transition-all duration-200
                  cursor-pointer
                  ${showDeadlines ? 'ring-2 ring-primary ring-offset-2' : ''}
                `}
              >
                <div className="w-3 h-3 bg-red-500 rounded-full" />
                <span className="text-sm">Submission Deadlines</span>
              </button>
            </TooltipTrigger>
            <TooltipContent>
              <p>Click to toggle submission deadlines</p>
            </TooltipContent>
          </Tooltip>
        </TooltipProvider>
        
        {Object.entries(categoryColors).map(([tag, color]) => (
          <TooltipProvider key={tag}>
            <Tooltip>
              <TooltipTrigger asChild>
                <button
                  onClick={() => {
                    const newCategories = new Set(selectedCategories);
                    if (newCategories.has(tag)) {
                      newCategories.delete(tag);
                    } else {
                      newCategories.add(tag);
                    }
                    setSelectedCategories(newCategories);
                  }}
                  className={`
                    flex items-center gap-2 px-3 py-1.5 
                    rounded-lg border border-neutral-200 
                    bg-white hover:bg-neutral-50 
                    transition-all duration-200
                    cursor-pointer
                    ${selectedCategories.has(tag) ? 'ring-2 ring-primary ring-offset-2' : ''}
                  `}
                >
                  <div className={`w-3 h-3 rounded-full ${color}`} />
                  <span className="text-sm">{categoryNames[tag] || tag}</span>
                </button>
              </TooltipTrigger>
              <TooltipContent>
                <p>Click to toggle {categoryNames[tag] || tag}</p>
              </TooltipContent>
            </Tooltip>
          </TooltipProvider>
        ))}
        
        {(selectedCategories.size < Object.keys(categoryColors).length || !showDeadlines) && (
          <button
            onClick={() => {
              setSelectedCategories(new Set(Object.keys(categoryColors)));
              setShowDeadlines(true);
            }}
            className="text-sm text-neutral-500 hover:text-neutral-700 
              px-3 py-1.5 rounded-lg border border-neutral-200 
              hover:bg-neutral-50 transition-colors"
          >
            Reset filters
          </button>
        )}
      </div>
    );
  };

  return (
    <div className="min-h-screen bg-neutral-light">
      <Header onSearch={setSearchQuery} />

      {searchQuery && (
        <div className="p-6 bg-white border-b">
          <div className="max-w-4xl mx-auto">
            <h2 className="text-lg font-semibold mb-4">
              Search Results for "{searchQuery}"
            </h2>
            <div className="space-y-4">
              {getEvents(new Date()).map((conf: Conference) => (
                <div 
                  key={conf.id || conf.title} 
                  className="p-4 border rounded-lg hover:bg-neutral-50 cursor-pointer"
                  onClick={() => {
                    const deadlineDate = safeParseISO(conf.deadline);
                    const startDate = safeParseISO(conf.start);
                    
                    if (deadlineDate) {
                      setSelectedDate(deadlineDate);
                      setSelectedDayEvents({
                        date: deadlineDate,
                        events: getDayEvents(deadlineDate)
                      });
                    } else if (startDate) {
                      setSelectedDate(startDate);
                      setSelectedDayEvents({
                        date: startDate,
                        events: getDayEvents(startDate)
                      });
                    }
                  }}
                >
                  <div className="flex justify-between items-start">
                    <div>
                      <h3 className="font-semibold">{conf.title}</h3>
                      {conf.full_name && (
                        <p className="text-sm text-neutral-600">{conf.full_name}</p>
                      )}
                    </div>
                    {conf.deadline && conf.deadline !== 'TBD' && (
                      <span className="text-sm text-red-500">
                        Deadline: {format(safeParseISO(conf.deadline)!, 'MMM d, yyyy')}
                      </span>
                    )}
                  </div>
                  {Array.isArray(conf.tags) && conf.tags.length > 0 && (
                    <div className="mt-2 flex flex-wrap gap-2">
                      {conf.tags.map(tag => (
                        <span 
                          key={tag}
                          className="inline-flex items-center px-2 py-1 rounded-full text-xs bg-neutral-100"
                        >
                          <Tag className="h-3 w-3 mr-1" />
                          {categoryNames[tag] || tag}
                        </span>
                      ))}
                    </div>
                  )}
                </div>
              ))}
              {getEvents(new Date()).length === 0 && (
                <p className="text-neutral-600">No conferences found matching your search.</p>
              )}
            </div>
          </div>
        </div>
      )}

      <div className="p-6">
        <div className="max-w-7xl mx-auto">
          <div className="flex flex-col items-center mb-8">
            <h1 className="text-3xl font-bold mb-4">Calendar Overview</h1>
            <div className="flex items-center gap-4 mb-6">
              <Toggle 
                pressed={!isYearView} 
                onPressedChange={() => setIsYearView(false)}
                variant="outline"
              >
                Month View
              </Toggle>
              <Toggle 
                pressed={isYearView} 
                onPressedChange={() => setIsYearView(true)}
                variant="outline"
              >
                Year View
              </Toggle>
            </div>
            {renderLegend()}
          </div>

          <div className="grid grid-cols-1 gap-8">
            <div className="mx-auto w-full max-w-4xl">
              <Calendar
                mode="single"
                selected={selectedDate}
                onSelect={setSelectedDate}
                numberOfMonths={isYearView ? 12 : 1}
                showOutsideDays={false}
                className="bg-white rounded-lg p-6 shadow-sm mx-auto w-full"
                components={{
                  Day: ({ date, displayMonth, ...props }) => {
                    const isOutsideDay = date.getMonth() !== displayMonth.getMonth();
                    if (isOutsideDay) {
                      return null;
                    }
                    return (
                      <div 
                        role="button"
                        tabIndex={0}
                        {...props} 
                        className="w-full h-full p-2 cursor-pointer"
                      >
                        {renderDayContent(date)}
                      </div>
                    );
                  },
                }}
                classNames={{
                  months: `grid ${isYearView ? 'grid-cols-3 gap-4' : ''} justify-center`,
                  month: "space-y-4",
                  caption: "flex justify-center pt-1 relative items-center mb-4",
                  caption_label: "text-lg font-semibold",
                  head_row: "flex",
                  head_cell: "text-muted-foreground rounded-md w-10 font-normal text-[0.8rem]",
                  row: "flex w-full mt-2",
                  cell: "h-16 w-10 text-center text-sm p-0 relative focus-within:relative focus-within:z-20 hover:bg-neutral-50",
                  day: "h-16 w-10 p-0 font-normal hover:bg-neutral-100 rounded-lg transition-colors",
                  day_today: "bg-neutral-100 text-primary font-semibold",
                  day_outside: "hidden",
                  nav: "space-x-1 flex items-center",
                  nav_button: "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
                  nav_button_previous: "absolute left-1",
                  nav_button_next: "absolute right-1"
                }}
              />
            </div>
          </div>
        </div>
      </div>

      <Dialog 
        open={selectedDayEvents.date !== null}
        onOpenChange={() => setSelectedDayEvents({ date: null, events: { deadlines: [], conferences: [] } })}
      >
        <DialogContent 
          className="max-w-2xl max-h-[80vh] overflow-y-auto"
          aria-describedby="dialog-description"
        >
          <DialogHeader>
            <DialogTitle>
              Events for {selectedDayEvents.date ? format(selectedDayEvents.date, 'MMMM d, yyyy') : ''}
            </DialogTitle>
            <div id="dialog-description" className="text-sm text-neutral-600">
              View conference details and deadlines for this date.
            </div>
          </DialogHeader>
          <div className="space-y-4">
            {selectedDayEvents.events.deadlines.length > 0 && (
              <div>
                <h3 className="text-lg font-semibold text-red-500 mb-3">Submission Deadlines</h3>
                <div className="space-y-4">
                  {selectedDayEvents.events.deadlines.map(conf => (
                    <div key={conf.id || conf.title}>
                      {renderEventDetails(conf)}
                    </div>
                  ))}
                </div>
              </div>
            )}
            {selectedDayEvents.events.conferences.length > 0 && (
              <div>
                <h3 className="text-lg font-semibold text-purple-600 mb-3">Conferences</h3>
                <div className="space-y-4">
                  {selectedDayEvents.events.conferences.map(conf => (
                    <div key={conf.id || conf.title}>
                      {renderEventDetails(conf)}
                    </div>
                  ))}
                </div>
              </div>
            )}
          </div>
        </DialogContent>
      </Dialog>
    </div>
  );
};

export default CalendarPage;
