import { useCallback, useEffect, useRef } from 'react';
import { useMessaging as useMessagingContext } from '../context/MessagingContext';
import { Message, Conversation, Notification } from '../types';

// Main messaging hook
export const useMessaging = () => {
  return useMessagingContext();
};

// Hook for managing conversations
export const useConversations = () => {
  const {
    conversations,
    currentConversation,
    isLoading,
    error,
    refreshConversations,
    createConversation,
    setCurrentConversation
  } = useMessagingContext();

  return {
    conversations,
    currentConversation,
    isLoading,
    error,
    refreshConversations,
    createConversation,
    setCurrentConversation
  };
};

// Hook for managing messages
export const useMessages = (conversationId?: number) => {
  const {
    messages,
    isLoading,
    error,
    getMessages,
    sendMessage,
    markMessagesAsRead,
    searchMessages,
    updateMessage,
    deleteMessage,
    setTyping
  } = useMessagingContext();

  const loadMessages = useCallback(async (page: number = 1, limit: number = 50) => {
    if (conversationId) {
      await getMessages(conversationId, page, limit);
    }
  }, [conversationId, getMessages]);

  const sendMessageToConversation = useCallback(async (
    content: string,
    type: 'text' | 'system' | 'file' | 'image' = 'text',
    replyTo?: number
  ) => {
    if (conversationId) {
      await sendMessage(conversationId, content, type, replyTo);
    }
  }, [conversationId, sendMessage]);

  const markAsRead = useCallback(async (messageIds?: number[]) => {
    if (conversationId) {
      await markMessagesAsRead(conversationId, messageIds);
    }
  }, [conversationId, markMessagesAsRead]);

  const searchInMessages = useCallback(async (query: string) => {
    return await searchMessages(query, conversationId);
  }, [conversationId, searchMessages]);

  const handleTyping = useCallback((isTyping: boolean) => {
    if (conversationId) {
      setTyping(conversationId, isTyping);
    }
  }, [conversationId, setTyping]);

  return {
    messages: conversationId ? messages.filter(m => m.conversation_id === conversationId) : messages,
    isLoading,
    error,
    loadMessages,
    sendMessage: sendMessageToConversation,
    markAsRead,
    searchMessages: searchInMessages,
    updateMessage,
    deleteMessage,
    setTyping: handleTyping
  };
};

// Hook for managing notifications
export const useNotifications = () => {
  const {
    notifications,
    unreadCount,
    isLoading,
    error,
    getNotifications,
    markNotificationAsRead,
    markAllNotificationsAsRead,
    deleteNotification,
    getNotificationStatistics
  } = useMessagingContext();

  return {
    notifications,
    unreadCount,
    isLoading,
    error,
    getNotifications,
    markNotificationAsRead,
    markAllNotificationsAsRead,
    deleteNotification,
    getNotificationStatistics
  };
};

// Hook for real-time typing indicators
export const useTypingIndicator = (conversationId?: number) => {
  const { typingUsers } = useMessagingContext();

  const conversationTypingUsers = conversationId 
    ? typingUsers.filter(user => user.isTyping)
    : typingUsers;

  return {
    typingUsers: conversationTypingUsers,
    isAnyoneTyping: conversationTypingUsers.length > 0
  };
};

// Hook for online status
export const useOnlineStatus = () => {
  const { onlineUsers } = useMessagingContext();

  const getOnlineUsers = useCallback(() => {
    return onlineUsers.filter(user => user.status === 'online');
  }, [onlineUsers]);

  const getBusyUsers = useCallback(() => {
    return onlineUsers.filter(user => user.status === 'busy');
  }, [onlineUsers]);

  const getOfflineUsers = useCallback(() => {
    return onlineUsers.filter(user => user.status === 'offline');
  }, [onlineUsers]);

  const getUserStatus = useCallback((userId: number) => {
    return onlineUsers.find(user => user.user_id === userId)?.status || 'offline';
  }, [onlineUsers]);

  return {
    onlineUsers,
    getOnlineUsers,
    getBusyUsers,
    getOfflineUsers,
    getUserStatus
  };
};

// Hook for message pagination
export const useMessagePagination = (conversationId: number) => {
  const { messages, isLoading, getMessages } = useMessagingContext();
  const currentPage = useRef(1);
  const hasMore = useRef(true);
  const isLoadingMore = useRef(false);

  const conversationMessages = messages.filter(m => m.conversation_id === conversationId);

  const loadMoreMessages = useCallback(async () => {
    if (isLoadingMore.current || !hasMore.current) return;

    isLoadingMore.current = true;
    currentPage.current += 1;

    try {
      const response = await getMessages(conversationId, currentPage.current, 50);
      // The response handling is done in the context
    } catch (error) {
      console.error('Failed to load more messages:', error);
      currentPage.current -= 1; // Revert page on error
    } finally {
      isLoadingMore.current = false;
    }
  }, [conversationId, getMessages]);

  const resetPagination = useCallback(() => {
    currentPage.current = 1;
    hasMore.current = true;
    isLoadingMore.current = false;
  }, []);

  return {
    messages: conversationMessages,
    isLoading: isLoading || isLoadingMore.current,
    hasMore: hasMore.current,
    loadMoreMessages,
    resetPagination
  };
};

// Hook for message search
export const useMessageSearch = () => {
  const { searchMessages } = useMessagingContext();
  const searchResults = useRef<Message[]>([]);
  const isSearching = useRef(false);

  const search = useCallback(async (
    query: string,
    conversationId?: number
  ): Promise<Message[]> => {
    if (!query.trim()) {
      searchResults.current = [];
      return [];
    }

    isSearching.current = true;
    try {
      const results = await searchMessages(query, conversationId);
      searchResults.current = results;
      return results;
    } catch (error) {
      console.error('Search failed:', error);
      searchResults.current = [];
      return [];
    } finally {
      isSearching.current = false;
    }
  }, [searchMessages]);

  const clearSearch = useCallback(() => {
    searchResults.current = [];
  }, []);

  return {
    searchResults: searchResults.current,
    isSearching: isSearching.current,
    search,
    clearSearch
  };
};

// Hook for message composition
export const useMessageComposition = (conversationId?: number) => {
  const { sendMessage, setTyping } = useMessagingContext();
  const typingTimeout = useRef<NodeJS.Timeout | null>(null);

  const sendTypingIndicator = useCallback(() => {
    if (!conversationId) return;

    setTyping(conversationId, true);

    // Clear existing timeout
    if (typingTimeout.current) {
      clearTimeout(typingTimeout.current);
    }

    // Set timeout to stop typing indicator
    typingTimeout.current = setTimeout(() => {
      setTyping(conversationId, false);
    }, 3000);
  }, [conversationId, setTyping]);

  const stopTypingIndicator = useCallback(() => {
    if (!conversationId) return;

    if (typingTimeout.current) {
      clearTimeout(typingTimeout.current);
      typingTimeout.current = null;
    }

    setTyping(conversationId, false);
  }, [conversationId, setTyping]);

  const sendMessageWithTyping = useCallback(async (
    content: string,
    type: 'text' | 'system' | 'file' | 'image' = 'text',
    replyTo?: number
  ) => {
    if (!conversationId) return;

    // Stop typing indicator
    stopTypingIndicator();

    // Send message
    await sendMessage(conversationId, content, type, replyTo);
  }, [conversationId, sendMessage, stopTypingIndicator]);

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      if (typingTimeout.current) {
        clearTimeout(typingTimeout.current);
      }
    };
  }, []);

  return {
    sendMessage: sendMessageWithTyping,
    sendTypingIndicator,
    stopTypingIndicator
  };
};

// Hook for conversation management
export const useConversationManagement = () => {
  const {
    conversations,
    currentConversation,
    createConversation,
    setCurrentConversation,
    refreshConversations
  } = useMessagingContext();

  const createDirectConversation = useCallback(async (participantId: number) => {
    return await createConversation('direct', [participantId]);
  }, [createConversation]);

  const createGroupConversation = useCallback(async (
    participantIds: number[],
    name: string,
    description?: string
  ) => {
    return await createConversation('group', participantIds, name, description);
  }, [createConversation]);

  const selectConversation = useCallback((conversation: Conversation | null) => {
    setCurrentConversation(conversation);
  }, [setCurrentConversation]);

  const getConversationById = useCallback((id: number) => {
    return conversations.find(c => c.id === id);
  }, [conversations]);

  const getDirectConversation = useCallback((participantId: number) => {
    return conversations.find(c => 
      c.type === 'direct' && 
      c.participants.some(p => p.user_id === participantId)
    );
  }, [conversations]);

  return {
    conversations,
    currentConversation,
    createDirectConversation,
    createGroupConversation,
    selectConversation,
    getConversationById,
    getDirectConversation,
    refreshConversations
  };
};

export default useMessaging;
