import {
  useGetThreadDetails,
  useGetThreadMessages,
  setMessagesCache,
  deleteMessageFromCache,
} from "../../requestHandler/use-chat-hooks";
import { useState, useRef, useEffect } from "react";
import { Loader2 } from "lucide-react";
import { useServiceGetProfile } from "../../requestHandler/use-profile-hooks";
import MessageList from "./MessageList";
import ChatHeader from "./ChatHeader";
import MessageInput from "./MessageInput";
import {
  MessageList as MessageListType,
  ThreadDetail,
  ThreadParticipant,
} from "../../../src/api/types/models";
import useWebSocket from "../../hooks/useWebSocket";
import { useQueryClient } from "@tanstack/react-query";
import { toast } from "../../hooks/use-toast";

interface ThreadChatPageProps {
  threadId: string;
}

export default function ThreadChatPage({ threadId }: ThreadChatPageProps) {
  // Scroll to bottom on initial load
  const [isInitialLoad, setIsInitialLoad] = useState(true);
  const { data: threadDetails, isLoading: isLoadingThread } =
    useGetThreadDetails(threadId);
  const [replyToMessage, setReplyToMessage] = useState<
    MessageListType | undefined
  >(undefined);

  // Load messages using infinite query
  const {
    data: messagesData,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
    isLoading: isLoadingMessages,
  } = useGetThreadMessages(threadId);

  // Flatten all pages of messages into a single array
  const allMessages = messagesData?.pages
    ? messagesData.pages.flatMap((page) => page.results)
    : [];

  const messageListRef = useRef<{
    scrollToBottom: () => void;
    getContainer: () => HTMLDivElement | null;
  }>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  const [messageText, setMessageText] = useState("");
  const { data: user } = useServiceGetProfile();
  const [prevScrollHeight, setPrevScrollHeight] = useState(0);
  const queryClient = useQueryClient();

  // WebSocket implementation
  const {
    isConnected,
    sendWebSocketMessage,
    markMessagesAsRead,
    deleteMessage,
    newMessage,
    readReceipt,
    messageDeleted,
    resetReadReceipt,
    resetNewMessage,
    resetMessageDeleted,
  } = useWebSocket(threadId, user?.id);

  // Handle new messages from WebSocket
  useEffect(() => {
    if (newMessage) {
      setMessagesCache(queryClient, threadId, {
        id: newMessage.message_id,
        content: newMessage.content,
        sender: newMessage.sender_id,
        createdAt: new Date().toISOString(),
        replyTo: newMessage.reply_to_id,
        replyContent: newMessage.reply_content || "",
      });
      resetNewMessage();
      setTimeout(() => {
        if (messageListRef.current) {
          messageListRef.current.scrollToBottom();
        }
      }, 100);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [newMessage]);

  const otherParticipant =
    threadDetails?.participants?.find(
      (participant) => participant.username !== user?.username
    ) || undefined;

  useEffect(() => {
    if (isConnected && !isLoadingMessages && allMessages.length > 0) {
      markMessagesAsRead();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isConnected, isLoadingMessages, allMessages.length]);

  useEffect(() => {
    return () => {
      queryClient.removeQueries({
        queryKey: ["getThreadMessages", threadId],
      });
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (readReceipt) {
      queryClient.setQueryData(
        ["getThreadDetails", threadId],
        (oldData: ThreadDetail) => {
          if (!oldData) return oldData;

          return {
            ...oldData,
            participants: oldData.participants?.map(
              (participant: ThreadParticipant) => {
                if (
                  participant.username &&
                  participant.username.toString() ===
                    readReceipt.reader_username
                ) {
                  return {
                    ...participant,
                    lastReadAt: new Date().toISOString(),
                  };
                }
                return participant;
              }
            ),
          };
        }
      );
      resetReadReceipt();
    }
  }, [readReceipt, threadId, queryClient, resetReadReceipt]);

  useEffect(() => {
    if (
      !isLoadingMessages &&
      messageListRef.current &&
      allMessages.length > 0 &&
      isConnected
    ) {
      if (isInitialLoad) {
        setIsInitialLoad(false);
        setTimeout(() => {
          if (messageListRef.current) {
            messageListRef.current.scrollToBottom();
          }
        }, 100);
      }
    }
  }, [isLoadingMessages, allMessages.length, isInitialLoad, isConnected]);

  // Add effect to handle message deleted events
  useEffect(() => {
    if (messageDeleted) {
      deleteMessageFromCache(queryClient, threadId, messageDeleted.message_id);
      resetMessageDeleted();
      const isOwner = messageDeleted.sender_id === user?.id;
      if (isOwner) {
        toast({
          title: "پیام با موفقیت حذف شد",
          description: "پیام شما با موفقیت حذف شد.",
        });
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [messageDeleted]);

  // Handle scroll to load more messages
  const handleScroll = () => {
    if (!messageListRef.current || isInitialLoad) return;
    const container = messageListRef.current.getContainer();
    if (!container) return;

    const { scrollTop } = container;
    // Load more messages when scrolled near the top
    if (scrollTop < 100 && hasNextPage && !isFetchingNextPage) {
      // Save the current scroll height before loading more messages
      setPrevScrollHeight(container.scrollHeight);
      fetchNextPage();
    }
  };

  // Maintain scroll position after loading more messages
  useEffect(() => {
    if (!isFetchingNextPage && prevScrollHeight > 0 && messageListRef.current) {
      const container = messageListRef.current.getContainer();
      if (!container) return;

      // Calculate the new position by finding the difference in height
      const newScrollHeight = container.scrollHeight;
      const scrollDifference = newScrollHeight - prevScrollHeight;

      // Adjust scroll position to maintain the view
      container.scrollTop = scrollDifference;

      // Reset the previous height
      setPrevScrollHeight(0);
    }
  }, [isFetchingNextPage, prevScrollHeight]);

  // Handle sending message
  const handleSendMessage = (text: string) => {
    if (isConnected) {
      sendWebSocketMessage(text, replyToMessage?.id, replyToMessage?.content);
    }
    setReplyToMessage(undefined);
    setMessageText("");
  };

  // Handle reply to message
  const handleReplyClick = (message: MessageListType) => {
    setReplyToMessage(message);
    // Focus on the input field
    setTimeout(() => {
      if (inputRef.current) {
        inputRef.current.focus();
      }
    }, 0);
  };

  // Handle message deletion
  const handleDeleteMessage = (messageId: string) => {
    if (isConnected) {
      deleteMessage(messageId);
    }
  };

  return (
    <div className="flex flex-col">
      <ChatHeader
        isConnected={isConnected}
        otherParticipant={otherParticipant}
        threadDetails={threadDetails}
      />
      {!isConnected ? (
        <div className="flex flex-col items-center justify-center h-[300px] w-full">
          <Loader2 size={24} className="animate-spin mt-10" />
          <p className="text-R12 text-GRAY">
            در حال اتصال به سرور پیام‌رسانی...
          </p>
        </div>
      ) : (
        <>
          <div
            className={`hide-scrollbar flex-grow w-full max-h-[calc(100vh_-_${replyToMessage ? "120px" : "75px"}_-_env(safe-area-inset-top)_-_env(safe-area-inset-bottom))] flex flex-col`}
          >
            {/* Messages list */}
            <MessageList
              otherParticipant={otherParticipant}
              ref={messageListRef}
              messages={[...allMessages].reverse()}
              isLoading={isLoadingMessages || isLoadingThread}
              isFetching={isFetchingNextPage}
              userId={user?.id}
              onReply={handleReplyClick}
              onDelete={handleDeleteMessage}
              onScroll={handleScroll}
            />
          </div>
          {/* Message input component */}
          <MessageInput
            setReplyToMessage={setReplyToMessage}
            isSendingMessage={false}
            messageText={messageText}
            setMessageText={setMessageText}
            onSend={handleSendMessage}
            replyToMessage={replyToMessage}
            onCancelReply={() => setReplyToMessage(undefined)}
            inputRef={inputRef}
          />
        </>
      )}
    </div>
  );
}
