import { useEffect, useRef, useState } from 'react';
import { socket } from '../../socket/socket.tsx';
import { useOutletContext } from 'react-router-dom';
import { sendContact } from '../../api/contactsApi.tsx';
import LoadingWheel from './LoadingWheel.tsx';
import { ChatMessagesProps, MeProps } from '../../pages/Chat.tsx';
import { ContactsProps } from '../../pages/Chat.tsx';
import { UsernameType } from '@/utils/ProtectedRoutes.tsx';
import AnimatedMessage from '@/components/chat/AnimatedMessage.tsx';

type MessagesAreaProps = {
  messages: ChatMessagesProps[];
  setMessages: React.Dispatch<React.SetStateAction<ChatMessagesProps[]>>;
  currentContact: ContactsProps | null;
  updateContactStatus: (contact: ContactsProps, read: boolean) => void;
  messageHandler: (msg: ChatMessagesProps) => void;
  setContactsList: React.Dispatch<React.SetStateAction<ContactsProps[]>>;
  fetchPreviousMessages: (contact: string | null) => Promise<void>;
  errorMessage: string | null;
  contactsList: ContactsProps[];
  me: MeProps;
};

function MessagesArea({
  messages,
  currentContact,
  updateContactStatus,
  setContactsList,
  messageHandler,
  fetchPreviousMessages,
  errorMessage,
  setMessages,
  contactsList,
  me,
}: MessagesAreaProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const user: UsernameType = useOutletContext();
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [shouldScrollToBottom, setShouldScrollToBottom] = useState(true);
  const previousMessagesLength = useRef(messages.length);

  const scrollToBottom = () => {
    const container = containerRef.current;
    if (container && shouldScrollToBottom) {
      container.scrollTop = container.scrollHeight;
    }
  };

  const handleScroll = async () => {
    const container = containerRef.current;
    if (!container) return;

    if (container.scrollTop === 0) {
      setIsLoading(true);
      setShouldScrollToBottom(false);
      const previousScrollHeight = container.scrollHeight;

      try {
        await fetchPreviousMessages(currentContact!.conversation_id);

        container.scrollTop = container.scrollHeight - previousScrollHeight;
      } catch (e) {
        console.error('Error fetching previous messages:', e);
      } finally {
        setIsLoading(false);
      }
    }

    const isAtBottom =
      container.scrollHeight - container.scrollTop <=
      container.clientHeight + 100;
    setShouldScrollToBottom(isAtBottom);
  };

  const deleteMessage = async (message_id: number) => {
    try {
      socket?.emit(
        'delete message',
        {
          message_id,
          conversation_id: currentContact?.conversation_id,
        },
        (response: { status: string; message: string }) => {
          if (response.status !== 'ok') {
            console.error('Failed to delete message: ', response.message);
          }
        },
      );
    } catch (e) {
      if (e instanceof Error) {
        console.error('Failed to delete message');
      }
    }
  };

  useEffect(() => {
    if (!socket) return;

    const currentContainer = containerRef.current;
    if (currentContainer) {
      currentContainer.addEventListener('scroll', handleScroll);
    }

    socket.on('chat message', (msg: ChatMessagesProps) => {
      console.log('Received message: ', msg);
      if (
        msg.conversation_id !== currentContact?.conversation_id &&
        msg.sender !== user.username
      ) {
        setContactsList((prevContacts) => {
          // Find if contact already exists
          const existingContact = prevContacts.find(
            (c) => c.conversation_id === msg.conversation_id,
          );

          if (!existingContact) {
            sendContact(msg.sender);
            return [
              ...prevContacts,
              {
                username: msg.sender,
                read: false,
                id: msg.message_id,
                user_id: msg.sender_id,
                conversation_id: msg.conversation_id,
                type: 'direct',
                last_active: new Date().toString(),
              },
            ];
          } else if (existingContact) {
            return prevContacts.map((contact) =>
              contact.conversation_id === msg.conversation_id
                ? { ...contact, last_active: new Date().toString() }
                : contact,
            );
          }

          return prevContacts;
        });

        // Find the existing contact from contactsList
        const existingContact = contactsList.find(
          (c) => c.conversation_id === msg.conversation_id,
        );

        updateContactStatus(
          {
            username: msg.sender,
            read: false,
            id: existingContact ? existingContact.id : msg.message_id, // Use existing contact's ID if found
            user_id: msg.sender_id,
            type: 'direct',
            conversation_id: msg.conversation_id,
            last_active: new Date().toString(),
          },
          false,
        );
      } else {
        if (msg.conversation_id == currentContact?.conversation_id) {
          messageHandler(msg);

          setContactsList((prevContacts) => {
            // Find if contact already exists
            const existingContact = prevContacts.find(
              (c) => c.conversation_id === msg.conversation_id,
            );

            if (!existingContact) {
              sendContact(msg.sender);
              return [
                ...prevContacts,
                {
                  username: msg.sender,
                  read: false,
                  id: msg.message_id,
                  user_id: msg.sender_id,
                  conversation_id: msg.conversation_id,
                  type: 'direct',
                  last_active: new Date().toString(),
                },
              ];
            } else if (existingContact) {
              return prevContacts.map((contact) =>
                contact.conversation_id === msg.conversation_id
                  ? { ...contact, last_active: new Date().toString() }
                  : contact,
              );
            }
            return prevContacts;
          });
        }
      }
    });

    socket.on(
      'delete message',
      (msg: { conversation_id: string; message_id: number }) => {
        console.log('deleted message from state');
        setMessages((prevMessages) =>
          prevMessages.filter(
            (message) => message.message_id !== msg.message_id,
          ),
        );
      },
    );

    return () => {
      if (!socket) {
        console.error('Socket not initialized');
        return;
      }

      if (currentContainer) {
        currentContainer.removeEventListener('scroll', handleScroll);
      }
      socket.off('chat message');
    };
  }, [currentContact, user.username, setContactsList, updateContactStatus]);

  // Handle auto-scrolling when new messages arrive
  useEffect(() => {
    const hasNewMessages = messages.length > previousMessagesLength.current;
    previousMessagesLength.current = messages.length;

    if (hasNewMessages && shouldScrollToBottom) {
      scrollToBottom();

      setTimeout(scrollToBottom, 100);
    }
  }, [messages, shouldScrollToBottom]);

  useEffect(() => {
    scrollToBottom();
  }, []);

  return (
    <div ref={containerRef} className="flex flex-col h-full overflow-y-auto">
      <p className="text-center text-gray-400">{errorMessage}</p>
      <ul className="flex-grow list-none">
        {isLoading ? <LoadingWheel /> : null}
        {messages.map((msg: ChatMessagesProps) => (
          <AnimatedMessage
            key={msg.message_id}
            message={msg}
            isAdmin={me.isGroupAdmin || me.isGroupOwner}
            currentUsername={user.username}
            onDelete={deleteMessage}
          />
        ))}
      </ul>
    </div>
  );
}

export default MessagesArea;
