import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { LoadingSpinner } from '@/components/ui/loading-spinner';
import { Select } from '@/components/ui/select';
import {
  Bell,
  Check,
  CheckCheck,
  MessageCircle,
  Music,
  UserPlus,
  Settings,
} from 'lucide-react';
import { formatDistanceToNow } from 'date-fns';
import { fr } from 'date-fns/locale';
import { useToast } from '@/hooks/useToast';
import {
  getNotifications,
  markNotificationAsRead,
  markAllNotificationsAsRead,
  type Notification,
  type NotificationsResponse,
} from '../services/notificationService';
import { Link } from 'react-router-dom';

// FE-PAGE-014: Add Notifications page

type FilterType = 'all' | 'unread' | 'read';
type NotificationTypeFilter =
  | 'all'
  | 'new_message'
  | 'track_uploaded'
  | 'user_mentioned'
  | 'system'
  | 'friend_request'
  | 'conversation_invite';

const NOTIFICATION_TYPE_LABELS: Record<string, string> = {
  new_message: 'Message',
  track_uploaded: 'Track',
  user_mentioned: 'Mention',
  system: 'System',
  friend_request: 'Friend Request',
  conversation_invite: 'Conversation Invite',
};

const NOTIFICATION_TYPE_ICONS: Record<string, React.ReactNode> = {
  new_message: <MessageCircle className="h-4 w-4" />,
  track_uploaded: <Music className="h-4 w-4" />,
  user_mentioned: <UserPlus className="h-4 w-4" />,
  system: <Settings className="h-4 w-4" />,
  friend_request: <UserPlus className="h-4 w-4" />,
  conversation_invite: <MessageCircle className="h-4 w-4" />,
};

export function NotificationsPage() {
  const [filterType, setFilterType] = useState<FilterType>('all');
  const [typeFilter, setTypeFilter] = useState<NotificationTypeFilter>('all');
  const { success, error: toastError } = useToast();
  const queryClient = useQueryClient();

  // Fetch notifications
  const {
    data: notificationsData,
    isLoading,
    isError,
    error,
  } = useQuery({
    queryKey: ['notifications', filterType, typeFilter],
    queryFn: () =>
      getNotifications({
        read: filterType === 'all' ? undefined : filterType === 'read',
        type: typeFilter === 'all' ? undefined : typeFilter,
      }),
  });

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

  // 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', filterType, typeFilter]);

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

      return { previousNotifications };
    },
    onError: (err: Error, _notificationId, context) => {
      // Rollback on error
      if (context?.previousNotifications) {
        queryClient.setQueryData(
          ['notifications', filterType, typeFilter],
          context.previousNotifications,
        );
      }
      toastError(err.message || 'Failed to mark notification as read');
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
      success('Notification marked as read');
    },
  });

  // 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', filterType, typeFilter]);

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

      return { previousNotifications };
    },
    onError: (err: Error, _variables, context) => {
      // Rollback on error
      if (context?.previousNotifications) {
        queryClient.setQueryData(
          ['notifications', filterType, typeFilter],
          context.previousNotifications,
        );
      }
      toastError(err.message || 'Failed to mark all notifications as read');
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
      success('All notifications marked as read');
    },
  });

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

  const handleMarkAllAsRead = () => {
    if (unreadNotifications.length === 0) return;
    markAllAsReadMutation.mutate();
  };

  const handleNotificationClick = (notification: Notification) => {
    if (!notification.read) {
      handleMarkAsRead(notification.id);
    }
    if (notification.link) {
      // Navigation handled by Link component
    }
  };

  const filteredNotifications =
    filterType === 'all'
      ? notifications
      : filterType === 'unread'
        ? unreadNotifications
        : readNotifications;

  const hasUnread = unreadNotifications.length > 0;

  return (
    <div className="container mx-auto px-4 py-8">
      <div className="max-w-4xl mx-auto">
        {/* Header */}
        <div className="mb-6 flex items-center justify-between">
          <div>
            <h1 className="text-3xl font-bold mb-2">Notifications</h1>
            <p className="text-muted-foreground">
              Manage your notifications and stay updated
            </p>
          </div>
          {hasUnread && (
            <Button
              onClick={handleMarkAllAsRead}
              disabled={markAllAsReadMutation.isPending}
              variant="outline"
            >
              {markAllAsReadMutation.isPending ? (
                <>
                  <LoadingSpinner className="mr-2 h-4 w-4" />
                  Marking...
                </>
              ) : (
                <>
                  <CheckCheck className="mr-2 h-4 w-4" />
                  Mark All as Read
                </>
              )}
            </Button>
          )}
        </div>

        {/* Filters */}
        <Card className="mb-6">
          <CardContent className="pt-6">
            <div className="flex flex-col md:flex-row gap-4">
              <div className="flex-1">
                <label className="text-sm font-medium mb-2 block">Status</label>
                <Select
                  options={[
                    { value: 'all', label: 'All' },
                    { value: 'unread', label: 'Unread' },
                    { value: 'read', label: 'Read' },
                  ]}
                  value={filterType}
                  onChange={(value) =>
                    setFilterType(
                      (Array.isArray(value) ? value[0] : value) as FilterType,
                    )
                  }
                />
              </div>
              <div className="flex-1">
                <label className="text-sm font-medium mb-2 block">Type</label>
                <Select
                  options={[
                    { value: 'all', label: 'All Types' },
                    { value: 'new_message', label: 'Messages' },
                    { value: 'track_uploaded', label: 'Tracks' },
                    { value: 'user_mentioned', label: 'Mentions' },
                    { value: 'system', label: 'System' },
                    { value: 'friend_request', label: 'Friend Requests' },
                    { value: 'conversation_invite', label: 'Conversations' },
                  ]}
                  value={typeFilter}
                  onChange={(value) =>
                    setTypeFilter(
                      (Array.isArray(value)
                        ? value[0]
                        : value) as NotificationTypeFilter,
                    )
                  }
                />
              </div>
            </div>
          </CardContent>
        </Card>

        {/* Notifications List */}
        {isLoading ? (
          <Card>
            <CardContent className="pt-6">
              <div className="flex justify-center py-12">
                <LoadingSpinner />
              </div>
            </CardContent>
          </Card>
        ) : isError ? (
          <Card>
            <CardContent className="pt-6">
              <div className="text-center text-destructive">
                <p>Failed to load notifications</p>
                {error instanceof Error && (
                  <p className="text-sm mt-2">{error.message}</p>
                )}
              </div>
            </CardContent>
          </Card>
        ) : filteredNotifications.length === 0 ? (
          <Card>
            <CardContent className="pt-6">
              <div className="text-center py-12">
                <Bell className="h-16 w-16 mx-auto mb-4 text-muted-foreground opacity-50" />
                <h2 className="text-xl font-semibold mb-2">No Notifications</h2>
                <p className="text-muted-foreground">
                  {filterType === 'unread'
                    ? "You're all caught up! No unread notifications."
                    : 'No notifications found.'}
                </p>
              </div>
            </CardContent>
          </Card>
        ) : (
          <div className="space-y-2">
            {filteredNotifications.map((notification) => {
              const NotificationContent = notification.link ? (
                <Link
                  to={notification.link}
                  onClick={() => handleNotificationClick(notification)}
                  className="block"
                >
                  <NotificationItem
                    notification={notification}
                    onMarkAsRead={handleMarkAsRead}
                  />
                </Link>
              ) : (
                <NotificationItem
                  notification={notification}
                  onMarkAsRead={handleMarkAsRead}
                />
              );

              return (
                <Card
                  key={notification.id}
                  className={`transition-colors ${
                    !notification.read ? 'border-primary bg-primary/5' : ''
                  }`}
                >
                  {NotificationContent}
                </Card>
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
}

interface NotificationItemProps {
  notification: Notification;
  onMarkAsRead: (id: string) => void;
}

function NotificationItem({
  notification,
  onMarkAsRead,
}: NotificationItemProps) {
  const typeIcon = NOTIFICATION_TYPE_ICONS[notification.type] || (
    <Bell className="h-4 w-4" />
  );
  const typeLabel =
    NOTIFICATION_TYPE_LABELS[notification.type] || notification.type;

  return (
    <CardContent className="p-4">
      <div className="flex items-start gap-4">
        <div className="mt-1 flex-shrink-0">{typeIcon}</div>
        <div className="flex-1 min-w-0">
          <div className="flex items-start justify-between gap-2">
            <div className="flex-1">
              <div className="flex items-center gap-2 mb-1">
                {!notification.read && (
                  <span className="h-2 w-2 bg-primary rounded-full flex-shrink-0" />
                )}
                <h3
                  className={`text-sm font-medium ${!notification.read ? 'font-semibold' : ''}`}
                >
                  {notification.title}
                </h3>
                <Badge variant="secondary" className="text-xs">
                  {typeLabel}
                </Badge>
              </div>
              <p className="text-sm text-muted-foreground mb-2">
                {notification.content}
              </p>
              <p className="text-xs text-muted-foreground">
                {formatDistanceToNow(new Date(notification.created_at), {
                  addSuffix: true,
                  locale: fr,
                })}
              </p>
            </div>
            {!notification.read && (
              <Button
                variant="ghost"
                size="icon"
                className="h-8 w-8 flex-shrink-0"
                onClick={(e) => {
                  e.preventDefault();
                  e.stopPropagation();
                  onMarkAsRead(notification.id);
                }}
                aria-label="Mark as read"
              >
                <Check className="h-4 w-4" />
              </Button>
            )}
          </div>
        </div>
      </div>
    </CardContent>
  );
}
