import { createContext, useContext, useEffect, useState } from "react";
import { useToast } from "@/hooks/use-toast";
import Pusher from 'pusher-js';
import { useAuth } from "@/hooks/use-auth";
import { useLocation } from "wouter";

interface Notification {
  id: string;
  title: string;
  body: string;
  timestamp: Date;
  read: boolean;
  url?: string;
  type?: string;
}

interface NotificationContextType {
  notifications: Notification[];
  markAsRead: (id: string) => void;
  removeNotification: (id: string) => void;
  sendNotification: (notification: { title: string; body: string; url?: string }) => Promise<void>;
  isConnected: boolean;
}

const NotificationContext = createContext<NotificationContextType | null>(null);

export function NotificationProvider({ children }: { children: React.ReactNode }) {
  const [notifications, setNotifications] = useState<Notification[]>(() => {
    const saved = localStorage.getItem('notifications');
    return saved ? JSON.parse(saved, (key, value) => {
      if (key === 'timestamp') return new Date(value);
      return value;
    }) : [];
  });
  const [isConnected, setIsConnected] = useState(false);
  const { toast } = useToast();
  const { user } = useAuth();
  const [, setLocation] = useLocation();

  useEffect(() => {
    localStorage.setItem('notifications', JSON.stringify(notifications));
  }, [notifications]);

  const markAsRead = (id: string) => {
    setNotifications(prev => {
      const updated = prev.map(n =>
        n.id === id ? { ...n, read: true } : n
      );
      localStorage.setItem('notifications', JSON.stringify(updated));
      return updated;
    });
  };

  const removeNotification = (id: string) => {
    setNotifications(prev => {
      const updated = prev.filter(n => n.id !== id);
      localStorage.setItem('notifications', JSON.stringify(updated));
      return updated;
    });
  };

  const sendNotification = async (notification: { title: string; body: string; url?: string }) => {
    try {
      const response = await fetch('/api/notifications/send', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          title: notification.title,
          message: notification.body,
          type: "info",
          userId: user?.id,
          url: notification.url
        }),
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.message || 'Failed to send notification');
      }

      const result = await response.json();
      console.log('Notification sent successfully:', result);
    } catch (error) {
      console.error('Failed to send notification:', error);
      toast({
        title: "Error",
        description: error instanceof Error ? error.message : "Failed to send notification",
        variant: "destructive",
      });
      throw error;
    }
  };

  useEffect(() => {
    let pusher: Pusher | null = null;

    const initializePusher = async () => {
      try {
        if (!user) {
          console.log('No user logged in, skipping Pusher initialization');
          setIsConnected(false);
          return;
        }

        const pusherKey = import.meta.env.VITE_PUSHER_KEY;
        const pusherCluster = import.meta.env.VITE_PUSHER_CLUSTER;

        if (!pusherKey || !pusherCluster) {
          console.error('Missing Pusher credentials:', { pusherKey, pusherCluster });
          setIsConnected(false);
          return;
        }

        pusher = new Pusher(pusherKey, {
          cluster: pusherCluster,
        });

        const channelName = `user-${user.id}-notifications`;
        const channel = pusher.subscribe(channelName);

        channel.bind('notification', (data: { 
          title: string; 
          message: string; 
          type?: string; 
          url?: string;
          sessionId?: number;
          isLiveStream?: boolean 
        }) => {
          console.log('Received notification:', data);

          // Construct the correct URL based on the notification type
          let notificationUrl = data.url;
          if (data.sessionId && data.isLiveStream) {
            notificationUrl = `/live-streams/${data.sessionId}`;
          } else if (data.sessionId) {
            notificationUrl = `/sessions/${data.sessionId}`;
          }

          const newNotification: Notification = {
            id: Date.now().toString(),
            title: data.title,
            body: data.message,
            timestamp: new Date(),
            read: false,
            url: notificationUrl,
            type: data.type
          };

          setNotifications(prev => {
            const updated = [newNotification, ...prev];
            localStorage.setItem('notifications', JSON.stringify(updated));
            return updated;
          });

          toast({
            title: newNotification.title,
            description: newNotification.body,
            onClick: () => {
              if (newNotification.url) {
                console.log('Navigating to:', newNotification.url);
                markAsRead(newNotification.id);
                setLocation(newNotification.url);
              } else {
                console.log('No URL to navigate to');
                markAsRead(newNotification.id);
              }
            }
          });
        });

        pusher.connection.bind('connected', () => {
          console.log('Successfully connected to Pusher');
          setIsConnected(true);
        });

        pusher.connection.bind('error', (err: any) => {
          console.error('Pusher connection error:', err);
          setIsConnected(false);
        });

      } catch (error) {
        console.error('Error setting up notifications:', error);
        setIsConnected(false);
      }
    };

    initializePusher();

    return () => {
      if (pusher) {
        const channel = pusher.channel(`user-${user?.id}-notifications`);
        if (channel) {
          channel.unbind_all();
          channel.unsubscribe();
        }
        pusher.disconnect();
      }
    };
  }, [toast, user, setLocation]);

  return (
    <NotificationContext.Provider value={{
      notifications,
      markAsRead,
      removeNotification,
      sendNotification,
      isConnected
    }}>
      {children}
    </NotificationContext.Provider>
  );
}

export function useNotifications() {
  const context = useContext(NotificationContext);
  if (!context) {
    throw new Error("useNotifications must be used within a NotificationProvider");
  }
  return context;
}