"use client";

import { createContext, useContext, useEffect, useState, ReactNode } from "react";
import { io, Socket } from "socket.io-client";
import { useAuth } from "./auth-context";

// Define the SocketContext type
interface SocketContextType {
  socket: Socket | null;
  isConnected: boolean;
  joinProject: (projectId: string) => void;
  leaveProject: (projectId: string) => void;
  // Event listeners
  onProjectUpdated: (callback: (data: any) => void) => () => void;
  onCollaboratorAdded: (callback: (data: any) => void) => () => void;
  onGroupCreated: (callback: (data: any) => void) => () => void;
  onGroupUpdated: (callback: (data: any) => void) => () => void;
  onPersonAddedToGroup: (callback: (data: any) => void) => () => void;
  onPersonRemovedFromGroup: (callback: (data: any) => void) => () => void;
  onNotification: (callback: (data: any) => void) => () => void;
}

// Create the SocketContext
const SocketContext = createContext<SocketContextType | undefined>(undefined);

// Create a provider component
export function SocketProvider({ children }: { children: ReactNode }) {
  const [socket, setSocket] = useState<Socket | null>(null);
  const [isConnected, setIsConnected] = useState<boolean>(false);
  const { user, isAuthenticated } = useAuth();

  // Initialize socket connection when user is authenticated
  useEffect(() => {
    if (!isAuthenticated || !user) {
      return;
    }

    const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000';
    
    // Create socket connection
    const socketInstance = io(API_URL, {
      withCredentials: true,
      query: {
        userId: user.id,
      },
    });

    // Set up event listeners
    socketInstance.on('connect', () => {
      console.log('Socket connected');
      setIsConnected(true);
    });

    socketInstance.on('disconnect', () => {
      console.log('Socket disconnected');
      setIsConnected(false);
    });

    socketInstance.on('connect_error', (error) => {
      console.error('Socket connection error:', error);
      setIsConnected(false);
    });

    // Save socket instance
    setSocket(socketInstance);

    // Clean up on unmount
    return () => {
      socketInstance.disconnect();
      setSocket(null);
      setIsConnected(false);
    };
  }, [isAuthenticated, user]);

  // Join a project room
  const joinProject = (projectId: string) => {
    if (socket && isConnected) {
      socket.emit('project:join', projectId);
    }
  };

  // Leave a project room
  const leaveProject = (projectId: string) => {
    if (socket && isConnected) {
      socket.emit('project:leave', projectId);
    }
  };

  // Event listeners with cleanup
  const onProjectUpdated = (callback: (data: any) => void) => {
    if (socket) {
      socket.on('project:updated', callback);
    }
    return () => {
      if (socket) {
        socket.off('project:updated', callback);
      }
    };
  };

  const onCollaboratorAdded = (callback: (data: any) => void) => {
    if (socket) {
      socket.on('project:collaboratorAdded', callback);
    }
    return () => {
      if (socket) {
        socket.off('project:collaboratorAdded', callback);
      }
    };
  };

  const onGroupCreated = (callback: (data: any) => void) => {
    if (socket) {
      socket.on('group:created', callback);
    }
    return () => {
      if (socket) {
        socket.off('group:created', callback);
      }
    };
  };

  const onGroupUpdated = (callback: (data: any) => void) => {
    if (socket) {
      socket.on('group:updated', callback);
    }
    return () => {
      if (socket) {
        socket.off('group:updated', callback);
      }
    };
  };

  const onPersonAddedToGroup = (callback: (data: any) => void) => {
    if (socket) {
      socket.on('group:personAdded', callback);
    }
    return () => {
      if (socket) {
        socket.off('group:personAdded', callback);
      }
    };
  };

  const onPersonRemovedFromGroup = (callback: (data: any) => void) => {
    if (socket) {
      socket.on('group:personRemoved', callback);
    }
    return () => {
      if (socket) {
        socket.off('group:personRemoved', callback);
      }
    };
  };

  const onNotification = (callback: (data: any) => void) => {
    if (socket) {
      socket.on('notification:new', callback);
    }
    return () => {
      if (socket) {
        socket.off('notification:new', callback);
      }
    };
  };

  // Create the context value
  const value = {
    socket,
    isConnected,
    joinProject,
    leaveProject,
    onProjectUpdated,
    onCollaboratorAdded,
    onGroupCreated,
    onGroupUpdated,
    onPersonAddedToGroup,
    onPersonRemovedFromGroup,
    onNotification,
  };

  return <SocketContext.Provider value={value}>{children}</SocketContext.Provider>;
}

// Create a hook to use the SocketContext
export function useSocket() {
  const context = useContext(SocketContext);
  if (context === undefined) {
    throw new Error("useSocket must be used within a SocketProvider");
  }
  return context;
}