import { useState, useMemo, useEffect, useCallback, useRef } from 'react';
import { format, isToday, isTomorrow, isThisWeek } from 'date-fns';
import { useNavigate } from 'react-router-dom';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import {
  ArrowRight,
  Eye,
  EyeOff,
  Target,
  ChevronRight,
  Check,
  Clock,
  X,
} from 'lucide-react';
import type { UpcomingItem } from '@/types';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { ScrollArea } from '@/components/ui/scroll-area';
import { cn } from '@/lib/utils';
import { getRelativeTime, toLocalDatetime } from '@/lib/date-utils';
import api from '@/lib/api';

interface UpcomingWidgetProps {
  items: UpcomingItem[];
}

const typeConfig: Record<string, { hoverGlow: string; pillBg: string; pillText: string; label: string }> = {
  todo: { hoverGlow: 'hover:bg-blue-500/[0.08]', pillBg: 'bg-blue-500/15', pillText: 'text-blue-400', label: 'TODO' },
  event: { hoverGlow: 'hover:bg-purple-500/[0.08]', pillBg: 'bg-purple-500/15', pillText: 'text-purple-400', label: 'EVENT' },
  reminder: { hoverGlow: 'hover:bg-orange-500/[0.08]', pillBg: 'bg-orange-500/15', pillText: 'text-orange-400', label: 'REMINDER' },
};

function getMinutesUntilTomorrowMorning(): number {
  const now = new Date();
  const tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 9, 0, 0);
  return Math.min(1440, Math.max(1, Math.round((tomorrow.getTime() - now.getTime()) / 60000)));
}

function getDayLabel(dateStr: string): string {
  const d = new Date(dateStr + 'T00:00:00');
  if (isToday(d)) return 'Today';
  if (isTomorrow(d)) return 'Tomorrow';
  if (isThisWeek(d, { weekStartsOn: 1 })) return format(d, 'EEEE');
  return format(d, 'EEE, MMM d');
}

function isEventPast(item: UpcomingItem, now: Date): boolean {
  if (item.type !== 'event') return false;
  const endStr = item.end_datetime || item.datetime;
  if (!endStr) return false;
  return new Date(endStr) < now;
}

export default function UpcomingWidget({ items }: UpcomingWidgetProps) {
  const navigate = useNavigate();
  const queryClient = useQueryClient();
  const [showPast, setShowPast] = useState(false);
  const [focusMode, setFocusMode] = useState(false);
  const [collapsedDays, setCollapsedDays] = useState<Set<string>>(new Set());
  const [clientNow, setClientNow] = useState(() => new Date());
  const [hoveredItem, setHoveredItem] = useState<string | null>(null);
  const [snoozeOpen, setSnoozeOpen] = useState<string | null>(null);
  const hasMounted = useRef(false);

  useEffect(() => {
    hasMounted.current = true;
  }, []);

  // Update clientNow every 60s for past-event detection
  useEffect(() => {
    const interval = setInterval(() => setClientNow(new Date()), 60_000);
    return () => clearInterval(interval);
  }, []);

  // Toggle todo completion with optimistic update
  const toggleTodo = useMutation({
    mutationFn: (id: number) => api.patch(`/todos/${id}/toggle`),
    onMutate: async (id: number) => {
      await queryClient.cancelQueries({ queryKey: ['upcoming'] });
      const previousData = queryClient.getQueryData(['upcoming']);
      queryClient.setQueryData(['upcoming'], (old: any) => {
        if (!old?.items) return old;
        return { ...old, items: old.items.filter((item: UpcomingItem) => !(item.type === 'todo' && item.id === id)) };
      });
      return { previousData };
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['upcoming'] });
      queryClient.invalidateQueries({ queryKey: ['dashboard'] });
      toast.success('Todo completed');
    },
    onError: (_err, _id, context) => {
      if (context?.previousData) {
        queryClient.setQueryData(['upcoming'], context.previousData);
      }
      toast.error('Failed to complete todo');
    },
  });

  // Snooze reminder
  const snoozeReminder = useMutation({
    mutationFn: ({ id, minutes }: { id: number; minutes: number }) =>
      api.patch(`/reminders/${id}/snooze`, { minutes, client_now: toLocalDatetime() }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['upcoming'] });
      toast.success('Reminder snoozed');
    },
    onError: () => toast.error('Failed to snooze reminder'),
  });

  // Dismiss reminder
  const dismissReminder = useMutation({
    mutationFn: (id: number) => api.patch(`/reminders/${id}/dismiss`),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['upcoming'] });
      queryClient.invalidateQueries({ queryKey: ['dashboard'] });
      toast.success('Reminder dismissed');
    },
    onError: () => toast.error('Failed to dismiss reminder'),
  });

  // Filter and group items
  const { grouped, filteredCount } = useMemo(() => {
    let filtered = items.filter((item) => {
      // Hide past events unless toggle is on
      if (!showPast && isEventPast(item, clientNow)) return false;
      return true;
    });

    // Focus mode: only Today + Tomorrow
    if (focusMode) {
      filtered = filtered.filter((item) => {
        const d = new Date(item.date + 'T00:00:00');
        return isToday(d) || isTomorrow(d);
      });
    }

    const map = new Map<string, UpcomingItem[]>();
    for (const item of filtered) {
      const key = item.date;
      if (!map.has(key)) map.set(key, []);
      map.get(key)!.push(item);
    }

    return { grouped: map, filteredCount: filtered.length };
  }, [items, showPast, focusMode, clientNow]);

  const handleItemClick = useCallback((item: UpcomingItem) => {
    switch (item.type) {
      case 'event': {
        const dateStr = item.datetime
          ? format(new Date(item.datetime), 'yyyy-MM-dd')
          : item.date;
        navigate('/calendar', { state: { date: dateStr, view: 'timeGridDay', eventId: item.id } });
        break;
      }
      case 'todo':
        navigate('/todos', { state: { todoId: item.id } });
        break;
      case 'reminder':
        navigate('/reminders', { state: { reminderId: item.id } });
        break;
    }
  }, [navigate]);

  const toggleDay = useCallback((dateKey: string) => {
    setCollapsedDays((prev) => {
      const next = new Set(prev);
      if (next.has(dateKey)) next.delete(dateKey);
      else next.add(dateKey);
      return next;
    });
  }, []);

  const handleSnooze = useCallback((id: number, minutes: number, e: React.MouseEvent) => {
    e.stopPropagation();
    setSnoozeOpen(null);
    snoozeReminder.mutate({ id, minutes });
  }, [snoozeReminder]);

  const formatTime = useCallback((item: UpcomingItem) => {
    if (item.type === 'todo') {
      const d = new Date(item.date + 'T00:00:00');
      if (isToday(d)) return 'Due today';
      return null; // date shown in header
    }
    if (item.type === 'event' && item.all_day) return 'All day';
    if (!item.datetime) return null;
    const d = new Date(item.date + 'T00:00:00');
    if (isToday(d)) return getRelativeTime(item.datetime);
    return format(new Date(item.datetime), 'h:mm a');
  }, []);

  const dayEntries = Array.from(grouped.entries());

  return (
    <Card className="flex flex-col h-full overflow-hidden">
      <CardHeader className="shrink-0">
        <div className="flex items-center justify-between">
          <CardTitle className="flex items-center gap-2">
            <div className="p-1.5 rounded-md bg-accent/10">
              <ArrowRight className="h-4 w-4 text-accent" />
            </div>
            Upcoming
            <span className="text-xs text-muted-foreground font-normal ml-1">
              {filteredCount} {filteredCount === 1 ? 'item' : 'items'}
            </span>
          </CardTitle>
          <div className="flex items-center gap-1">
            <button
              onClick={() => setFocusMode(!focusMode)}
              className={cn(
                'p-1.5 rounded-md transition-colors',
                focusMode ? 'bg-accent/15 text-accent' : 'text-muted-foreground hover:text-foreground hover:bg-white/5'
              )}
              title={focusMode ? 'Show all days' : 'Focus: Today + Tomorrow'}
              aria-label={focusMode ? 'Show all days' : 'Focus: Today + Tomorrow'}
            >
              <Target className="h-3.5 w-3.5" />
            </button>
            <button
              onClick={() => setShowPast(!showPast)}
              className={cn(
                'p-1.5 rounded-md transition-colors',
                showPast ? 'bg-accent/15 text-accent' : 'text-muted-foreground hover:text-foreground hover:bg-white/5'
              )}
              title={showPast ? 'Hide past events' : 'Show past events'}
              aria-label={showPast ? 'Hide past events' : 'Show past events'}
            >
              {showPast ? <Eye className="h-3.5 w-3.5" /> : <EyeOff className="h-3.5 w-3.5" />}
            </button>
          </div>
        </div>
      </CardHeader>
      <CardContent className="flex-1 min-h-0 flex flex-col">
        {filteredCount === 0 ? (
          <p className="text-sm text-muted-foreground text-center py-8">
            {focusMode ? 'Nothing for today or tomorrow' : 'Nothing upcoming'}
          </p>
        ) : (
          <ScrollArea className="flex-1 min-h-0 -mr-2 pr-2">
            <div>
              {dayEntries.map(([dateKey, dayItems], groupIdx) => {
                const isCollapsed = collapsedDays.has(dateKey);
                const label = getDayLabel(dateKey);
                const isTodayGroup = isToday(new Date(dateKey + 'T00:00:00'));

                return (
                  <div key={dateKey}>
                    {/* Sticky day header */}
                    <button
                      onClick={() => toggleDay(dateKey)}
                      className={cn(
                        'sticky top-0 bg-card z-10 w-full flex items-center gap-1.5 pb-1.5 border-b border-border cursor-pointer select-none',
                        groupIdx === 0 ? 'pt-0' : 'pt-3'
                      )}
                    >
                      <ChevronRight
                        className={cn(
                          'h-3 w-3 text-muted-foreground transition-transform duration-150',
                          !isCollapsed && 'rotate-90'
                        )}
                      />
                      <span
                        className={cn(
                          'text-xs font-semibold uppercase tracking-wider',
                          isTodayGroup ? 'text-accent' : 'text-muted-foreground'
                        )}
                      >
                        {label}
                      </span>
                      {isCollapsed && (
                        <span className="text-[10px] text-muted-foreground font-normal ml-auto mr-1">
                          {dayItems.length} {dayItems.length === 1 ? 'item' : 'items'}
                        </span>
                      )}
                    </button>

                    {/* Day items */}
                    {!isCollapsed && (
                      <div className="py-0.5">
                        {dayItems.map((item, idx) => {
                          const animDelay = Math.min(idx, 8) * 30;
                          const config = typeConfig[item.type] || typeConfig.todo;
                          const itemKey = `${item.type}-${item.id}-${idx}`;
                          const isPast = isEventPast(item, clientNow);
                          const isHovered = hoveredItem === itemKey;
                          const timeLabel = formatTime(item);

                          return (
                            <div
                              key={itemKey}
                              onClick={() => handleItemClick(item)}
                              onMouseEnter={() => setHoveredItem(itemKey)}
                              onMouseLeave={() => { setHoveredItem(null); setSnoozeOpen(null); }}
                              className={cn(
                                'flex items-center gap-2 py-1.5 px-2 rounded-md transition-colors duration-150 cursor-pointer',
                                !hasMounted.current && 'animate-slide-in-row',
                                config.hoverGlow,
                                isPast && 'opacity-50'
                              )}
                              style={!hasMounted.current ? { animationDelay: `${animDelay}ms`, animationFillMode: 'backwards' } : undefined}
                            >
                              {/* Title */}
                              <span className="text-sm font-medium truncate flex-1 min-w-0">{item.title}</span>

                              {/* Status pills */}
                              {item.is_overdue && item.type === 'todo' && (
                                <span className="text-[9px] px-1.5 py-0.5 rounded font-medium bg-red-500/10 text-red-400 shrink-0">
                                  OVERDUE
                                </span>
                              )}
                              {item.type === 'reminder' && item.snoozed_until && (
                                <span className="text-[9px] px-1.5 py-0.5 rounded font-medium bg-amber-500/10 text-amber-400 shrink-0">
                                  SNOOZED
                                </span>
                              )}
                              {item.type === 'reminder' && item.is_overdue && !item.snoozed_until && (
                                <span className="text-[9px] px-1.5 py-0.5 rounded font-medium bg-red-500/10 text-red-400 shrink-0">
                                  OVERDUE
                                </span>
                              )}

                              {/* Right side: static info + action overlay */}
                              <div className="relative flex items-center gap-1.5 shrink-0">
                                {/* Always-rendered labels (stable layout) */}
                                <div className={cn('flex items-center gap-1.5', isHovered && (item.type === 'todo' || item.type === 'reminder') && 'invisible')}>
                                  {timeLabel && (
                                    <span className="text-xs text-muted-foreground shrink-0 whitespace-nowrap tabular-nums">
                                      {timeLabel}
                                    </span>
                                  )}
                                  <span className={cn(
                                    'text-[9px] px-1.5 py-0.5 rounded font-medium shrink-0 hidden sm:inline-block',
                                    config.pillBg,
                                    config.pillText
                                  )}>
                                    {config.label}
                                  </span>
                                  {item.priority && item.priority !== 'none' && (
                                    <span className={cn(
                                      'text-[9px] font-semibold px-1.5 py-0.5 rounded shrink-0 hidden sm:inline-block',
                                      item.priority === 'high' ? 'bg-red-500/10 text-red-400' :
                                      item.priority === 'medium' ? 'bg-yellow-500/10 text-yellow-400' :
                                      'bg-green-500/10 text-green-400'
                                    )}>
                                      {item.priority}
                                    </span>
                                  )}
                                </div>

                                {/* Action buttons overlaid in same space */}
                                {isHovered && item.type === 'todo' && (
                                  <div className="absolute inset-0 flex items-center justify-end">
                                    <button
                                      onClick={(e) => {
                                        e.stopPropagation();
                                        toggleTodo.mutate(item.id);
                                      }}
                                      className="p-1 rounded hover:bg-green-500/15 text-muted-foreground hover:text-green-400 transition-colors"
                                      title="Complete todo"
                                    >
                                      <Check className="h-3.5 w-3.5" />
                                    </button>
                                  </div>
                                )}

                                {isHovered && item.type === 'reminder' && (
                                  <div className="absolute inset-0 flex items-center justify-end gap-0.5">
                                    <div className="relative">
                                      <button
                                        onClick={(e) => {
                                          e.stopPropagation();
                                          setSnoozeOpen(snoozeOpen === itemKey ? null : itemKey);
                                        }}
                                        className="p-1 rounded hover:bg-orange-500/15 text-muted-foreground hover:text-orange-400 transition-colors"
                                        title="Snooze reminder"
                                      >
                                        <Clock className="h-3.5 w-3.5" />
                                      </button>
                                      {snoozeOpen === itemKey && (
                                        <div className="absolute right-0 bottom-full mb-1 w-28 rounded-md border bg-popover shadow-lg z-50 py-1 animate-fade-in">
                                          <button
                                            onClick={(e) => handleSnooze(item.id, 60, e)}
                                            className="flex items-center w-full px-3 py-1.5 text-xs hover:bg-card-elevated transition-colors text-muted-foreground hover:text-foreground"
                                          >
                                            1 hour
                                          </button>
                                          <button
                                            onClick={(e) => handleSnooze(item.id, 180, e)}
                                            className="flex items-center w-full px-3 py-1.5 text-xs hover:bg-card-elevated transition-colors text-muted-foreground hover:text-foreground"
                                          >
                                            3 hours
                                          </button>
                                          <button
                                            onClick={(e) => handleSnooze(item.id, getMinutesUntilTomorrowMorning(), e)}
                                            className="flex items-center w-full px-3 py-1.5 text-xs hover:bg-card-elevated transition-colors text-muted-foreground hover:text-foreground"
                                          >
                                            Tomorrow
                                          </button>
                                        </div>
                                      )}
                                    </div>
                                    <button
                                      onClick={(e) => {
                                        e.stopPropagation();
                                        dismissReminder.mutate(item.id);
                                      }}
                                      className="p-1 rounded hover:bg-red-500/15 text-muted-foreground hover:text-red-400 transition-colors"
                                      title="Dismiss reminder"
                                    >
                                      <X className="h-3.5 w-3.5" />
                                    </button>
                                  </div>
                                )}
                              </div>
                            </div>
                          );
                        })}
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
          </ScrollArea>
        )}
      </CardContent>
    </Card>
  );
}
