import { useEffect, useRef, useState } from 'react';
import { socket } from '../../socket/socket.tsx';
import { useOutletContext } from 'react-router-dom';
import { UsernameType } from '../../utils/ProtectedRoutes.tsx';
import { sendContact } from '../../api/contactsApi.tsx';
import LoadingWheel from './LoadingWheel.tsx';

type ChatMessages = {
  sender: string;
  message: string;
  recipient: string;
  message_id: number;
  timestamp: string;
};

type ContactProps = {
  usernamecontact: string;
  read: boolean;
};
type ContactsProps = {
  usernamecontact: string;
  read: boolean;
};

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

function MessagesArea({
  messages,
  currentContact,
  updateContactStatus,
  setContactsList,
  messageHandler,
  fetchPreviousMessages,
  errorMessage,
}: MessagesAreaProps) {
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const { username }: UsernameType = useOutletContext();
  const prevScrollHeight = useRef(0);
  const [isFetchingHistory, setIsFetchingHistory] = useState(false);
  const [isLoading, setIsLoading] = useState<boolean>(false);

  const handleScroll = () => {
    const container = containerRef.current;
    if (container && container.scrollTop === 0) {
      setIsLoading(true);
      prevScrollHeight.current = container.scrollHeight;
      setIsFetchingHistory(true);
      fetchPreviousMessages(currentContact)
        .then(() => setIsLoading(false))
        .catch((e) => {
          console.error('Failed to fetch messages: ', e);
          setIsLoading(false);
        });
    }
  };

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

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

    socket.on('chat message', (msg: ChatMessages) => {
      console.log('Received message: ', msg);
      if (msg.sender !== currentContact && msg.sender !== username) {
        setContactsList((prevContacts) => {
          if (!prevContacts.some((c) => c.usernamecontact === msg.sender)) {
            sendContact(msg.sender);
            return [
              ...prevContacts,
              { usernamecontact: msg.sender, read: false },
            ];
          }
          return prevContacts;
        });
        updateContactStatus(
          { usernamecontact: msg.sender, read: false },
          false,
        );
        console.log('changed status to false for: ', msg.sender);
      }
      if (msg.sender == currentContact || msg.sender == username) {
        messageHandler(msg);
      }
    });

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

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

  useEffect(() => {
    const container = containerRef.current;
    if (container && isFetchingHistory) {
      container.scrollTop = container.scrollHeight - prevScrollHeight.current;
      setIsFetchingHistory(false);
    }
  }, [messages]);

  useEffect(() => {
    if (!isFetchingHistory) {
      messagesEndRef.current?.scrollIntoView();
    }
  }, [messages]);

  const messageList = messages.map((msg: ChatMessages) => (
    <li
      className="whitespace-pre-wrap ml-2 rounded p-1 hover:bg-gray-800"
      key={msg.message_id}
    >
      {msg.message_id} {msg.sender}: {msg.message}
    </li>
  ));

  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}
        {messageList}
      </ul>
      <div ref={messagesEndRef} />
    </div>
  );
}

export default MessagesArea;
