import { useState, useRef, useEffect } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { Bell, Check, CheckCheck, Loader2 } from 'lucide-react';
import { cn } from '@/lib/utils';
import {
  getNotifications,
  markNotificationAsRead,
  markAllNotificationsAsRead,
  type Notification,
  type NotificationsResponse,
} from '@/features/notifications/services/notificationService';
import { useToast } from '@/hooks/useToast';
import { formatDistanceToNow } from 'date-fns';
import { fr } from 'date-fns/locale';
import type { BaseComponentProps } from '../types';

/**
 * FE-COMP-014: Notification center component with real-time updates
 * FE-TYPE-013: Fully typed component props
 */

const POLL_INTERVAL = 30000; // 30 seconds
const MAX_NOTIFICATIONS = 50;

/**
 * Props for NotificationMenu component
 */
export interface NotificationMenuProps extends BaseComponentProps {
  // No additional props needed - uses global stores
}

export function NotificationMenu({
  className: _className,
}: NotificationMenuProps = {}) {
  const [isOpen, setIsOpen] = useState(false);
  const menuRef = useRef<HTMLDivElement>(null);
  const navigate = useNavigate();
  const queryClient = useQueryClient();
  const { success: showSuccess, error: showError } = useToast();

  // Fetch notifications with real-time polling
  const {
    data: notificationsData,
    isLoading,
    refetch,
  } = useQuery({
    queryKey: ['notifications', 'menu'],
    queryFn: () => getNotifications({ limit: MAX_NOTIFICATIONS }),
    refetchInterval: POLL_INTERVAL, // Poll every 30 seconds
    staleTime: 10000, // Consider data stale after 10 seconds
  });

  const notifications = notificationsData?.notifications || [];
  const unreadCount = notifications.filter((n) => !n.read).length;

  // Mark as read mutation
  // Action 4.4.1.5: Add optimistic update
  const markAsReadMutation = useMutation({
    mutationFn: markNotificationAsRead,
    onMutate: async (notificationId: string) => {
      // Cancel outgoing refetches
      await queryClient.cancelQueries({ queryKey: ['notifications'] });

      // Snapshot previous value
      const previousNotifications = queryClient.getQueryData<
        NotificationsResponse
      >(['notifications']);

      // Optimistically mark notification as read
      if (previousNotifications) {
        queryClient.setQueryData<NotificationsResponse>(['notifications'], {
          ...previousNotifications,
          notifications: previousNotifications.notifications.map((n) =>
            n.id === notificationId ? { ...n, read: true } : n,
          ),
          unreadCount: Math.max(
            (previousNotifications.unreadCount || 1) - 1,
            0,
          ),
        });
      }

      return { previousNotifications };
    },
    onError: (_error, _notificationId, context) => {
      // Rollback on error
      if (context?.previousNotifications) {
        queryClient.setQueryData(
          ['notifications'],
          context.previousNotifications,
        );
      }
      showError('Erreur lors du marquage');
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
    },
  });

  // Mark all as read mutation
  // Action 4.4.1.5: Add optimistic update
  const markAllAsReadMutation = useMutation({
    mutationFn: markAllNotificationsAsRead,
    onMutate: async () => {
      // Cancel outgoing refetches
      await queryClient.cancelQueries({ queryKey: ['notifications'] });

      // Snapshot previous value
      const previousNotifications = queryClient.getQueryData<
        NotificationsResponse
      >(['notifications']);

      // Optimistically mark all notifications as read
      if (previousNotifications) {
        queryClient.setQueryData<NotificationsResponse>(['notifications'], {
          ...previousNotifications,
          notifications: previousNotifications.notifications.map((n) => ({
            ...n,
            read: true,
          })),
          unreadCount: 0,
        });
      }

      return { previousNotifications };
    },
    onError: (_error, _variables, context) => {
      // Rollback on error
      if (context?.previousNotifications) {
        queryClient.setQueryData(
          ['notifications'],
          context.previousNotifications,
        );
      }
      showError('Erreur lors du marquage');
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
      showSuccess('Toutes les notifications ont été marquées comme lues');
    },
  });

  // Fermer le menu si on clique en dehors
  useEffect(() => {
    function handleClickOutside(event: MouseEvent) {
      if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
        setIsOpen(false);
      }
    }

    if (isOpen) {
      document.addEventListener('mousedown', handleClickOutside);
    }

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

  const handleMarkAsRead = (id: string) => {
    markAsReadMutation.mutate(id);
  };

  const handleMarkAllAsRead = () => {
    markAllAsReadMutation.mutate();
  };

  const handleNotificationClick = (notification: Notification) => {
    // Mark as read if unread
    if (!notification.read) {
      handleMarkAsRead(notification.id);
    }

    // Navigate to link if available
    if (notification.link) {
      navigate(notification.link);
      setIsOpen(false);
    }
  };

  // Refresh notifications when menu opens
  useEffect(() => {
    if (isOpen) {
      refetch();
    }
  }, [isOpen, refetch]);

  return (
    <div className="relative" ref={menuRef}>
      {/* Bouton de notifications */}
      <Button
        variant="ghost"
        size="icon"
        className="relative"
        onClick={() => setIsOpen(!isOpen)}
        aria-label="Notifications"
        aria-expanded={isOpen}
        aria-haspopup="true"
      >
        <Bell className="h-5 w-5" />
        {unreadCount > 0 && (
          <span
            className="absolute -top-1 -right-1 h-5 w-5 bg-destructive rounded-full text-xs text-destructive-foreground flex items-center justify-center font-semibold"
            aria-label={`${unreadCount} notifications non lues`}
          >
            {unreadCount > 9 ? '9+' : unreadCount}
          </span>
        )}
      </Button>

      {/* Menu dropdown */}
      {isOpen && (
        <div className="absolute right-0 mt-2 w-80 bg-background border rounded-lg shadow-lg z-50 max-h-[500px] flex flex-col">
          {/* En-tête */}
          <div className="p-4 border-b flex items-center justify-between">
            <h3 className="font-semibold text-sm">Notifications</h3>
            <div className="flex items-center space-x-2">
              {unreadCount > 0 && (
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={handleMarkAllAsRead}
                  className="h-7 text-xs"
                  disabled={markAllAsReadMutation.isPending}
                >
                  {markAllAsReadMutation.isPending ? (
                    <Loader2 className="h-3 w-3 mr-1 animate-spin" />
                  ) : (
                    <CheckCheck className="h-3 w-3 mr-1" />
                  )}
                  Tout marquer comme lu
                </Button>
              )}
            </div>
          </div>

          {/* Liste des notifications */}
          <div className="overflow-y-auto flex-1">
            {isLoading ? (
              <div className="flex items-center justify-center py-8">
                <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
              </div>
            ) : notifications.length === 0 ? (
              <div className="p-8 text-center text-muted-foreground">
                <Bell className="h-12 w-12 mx-auto mb-2 opacity-50" />
                <p className="text-sm">Aucune notification</p>
              </div>
            ) : (
              <div className="divide-y">
                {notifications.map((notification) => (
                  <div
                    key={notification.id}
                    className={cn(
                      'p-4 hover:bg-accent transition-colors cursor-pointer',
                      !notification.read && 'bg-accent/50',
                    )}
                    onClick={() => handleNotificationClick(notification)}
                  >
                    <div className="flex items-start justify-between gap-2">
                      <div className="flex-1 min-w-0">
                        <div className="flex items-center space-x-2 mb-1">
                          {!notification.read && (
                            <span className="h-2 w-2 bg-primary rounded-full flex-shrink-0 mt-1.5" />
                          )}
                          <p
                            className={cn(
                              'text-sm font-medium',
                              !notification.read && 'font-semibold',
                            )}
                          >
                            {notification.title}
                          </p>
                        </div>
                        {notification.content && (
                          <p className="text-sm text-muted-foreground mb-2 line-clamp-2">
                            {notification.content}
                          </p>
                        )}
                        <p className="text-xs text-muted-foreground">
                          {formatDistanceToNow(
                            new Date(notification.created_at),
                            {
                              addSuffix: true,
                              locale: fr,
                            },
                          )}
                        </p>
                      </div>
                      <div className="flex items-center space-x-1 ml-2 shrink-0">
                        {!notification.read && (
                          <Button
                            variant="ghost"
                            size="icon"
                            className="h-6 w-6"
                            onClick={(e) => {
                              e.stopPropagation();
                              handleMarkAsRead(notification.id);
                            }}
                            aria-label="Marquer comme lu"
                            disabled={markAsReadMutation.isPending}
                          >
                            {markAsReadMutation.isPending ? (
                              <Loader2 className="h-3 w-3 animate-spin" />
                            ) : (
                              <Check className="h-3 w-3" />
                            )}
                          </Button>
                        )}
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>

          {/* Footer with link to all notifications */}
          {notifications.length > 0 && (
            <div className="p-4 border-t">
              <Button
                variant="ghost"
                size="sm"
                className="w-full"
                onClick={() => {
                  navigate('/notifications');
                  setIsOpen(false);
                }}
              >
                Voir toutes les notifications
              </Button>
            </div>
          )}
        </div>
      )}
    </div>
  );
}
