import { useEffect, useRef } from "react";
import { socketInstance } from "./socket";
import { useAppDispatch, useAppSelector } from "../utils/hooks";
import {
  removeChatById,
  updateByChatId,
  updateChatList,
  updateChatListForNewMessage,
  updateUnreadCountByChatId,
} from "../store/Slices/ChatListSlice";
import { ChatListRes, OuterChat } from "../types/ChatListType";
import { MessageList, MessageListRes } from "../types/MessageListType";
import {
  appendMessage,
  appendPinnedMessages,
  removePinnedMessagesByIds,
  updateMessagesByIds,
  // updatePollVote,
} from "../store/Slices/MessageListSlice";
import { updateMessageOptions } from "../store/Slices/MessageOptionsSlice";
import {
  addOnlineUser,
  initialOnlineUser,
  removeOnlineUser,
} from "../store/Slices/OnlineUserSlice";
import {
  removeArchiveChatById,
  updateArchiveList,
  updateArchiveListForNewMessage,
} from "../store/Slices/ArchiveListSlice";
import scrollToMessage from "../utils/scrollToMessage";
import {
  ArchiveChatRes,
  BlockedUpdateRes,
  CallData,
  CallEndedRes,
  ConnectedUserListRes,
  DeleteForEveryoneRes,
  PinUnpinRes,
  RealTimeMessageSeenRes,
  ReceivingCallRes,
  UserJoinedRes,
} from "../types/ResType";
import {
  addConnectedUser,
  updateConnectedUserList,
} from "../store/Slices/ConnectedUserSlice";
import { updateViewState } from "../store/Slices/ViewManagerSlice";
import { updateCallData } from "../store/Slices/CallDataSlice";
import { updatePeerData } from "../store/Slices/PeerJsSlice";
import { updateCurrentConversation } from "../store/Slices/CurrentConversationSlice";
import { SingleMessageRes } from "../types/SingleMessageType";
import { useQueryClient } from "react-query";
import { OnlineUser, OnlineUserRes } from "../types/OnlineUserType";
import {
  addTypingUser,
  removeTypingUser,
  TypingUser,
} from "../store/Slices/TypingUserListSlice";
import { store } from "../store/store";
import { addUnSeenMessages } from "../store/Slices/UnSeenMessagesSlice";

export default function ListenAllEvents() {
  const dispatch = useAppDispatch();
  const currentConversationData = useAppSelector(
    (state) => state.CurrentConversation,
  );
  const userData = useAppSelector((state) => state.userData);
  const intervalRef = useRef<NodeJS.Timeout | null>(null);
  const MessageList = useAppSelector((state) => state.MessageList);
  // Use useRef to store the latest value of currentConversationData.chat_id
  const currentChatRef = useRef(currentConversationData);
  const messageListRef = useRef(MessageList);
  const userDataRef = useRef(userData);
  const queryClient = useQueryClient();

  useEffect(() => {
    messageListRef.current = MessageList;
  }, [MessageList]);

  useEffect(() => {
    userDataRef.current = userData;
  }, [userData]);

  // Keep ref updated with the latest chat_id
  useEffect(() => {
    currentChatRef.current = currentConversationData;
  }, [currentConversationData]);

  function newMessageCommingSound() {
    const audio = new Audio("/audio/achive-sound-132273.mp3");
    audio.play().catch((error) => {
      console.error("Error playing sound:", error);
    });
  }

  function appendMessageToMessageList(SingleMessageRes: SingleMessageRes) {
    if (
      SingleMessageRes?.Records?.[0]?.sender_id != userDataRef.current?.user_id && SingleMessageRes?.Records?.[0]?.message_type != "call"
    ) {
      newMessageCommingSound();
    }
    if (
      String(currentChatRef.current.chat_id) ==
      String(SingleMessageRes?.Records?.[0]?.chat_id)
    ) {
      dispatch(appendMessage(SingleMessageRes));
      setTimeout(() => {
        scrollToMessage(
          SingleMessageRes?.Records?.[0]?.message_id,
          false,
          true,
        );
      }, 10);

      //     // notify other user that you have seen the message in real-time ===================================================================
      intervalRef.current = setInterval(() => {
        if (document.hidden) return; // Skip if the tab is not visible
        // Emit the event if the tab is visible
        socketInstance().emit("real_time_message_seen", {
          chat_id: currentChatRef.current.chat_id,
          message_id: SingleMessageRes?.Records?.[0]?.message_id,
          status: "seen",
        });
        // Clear the interval once the messageViewed is emitted
        if (intervalRef.current) {
          clearInterval(intervalRef.current);
          intervalRef.current = null;
        }
      }, 1000);
    } else {
      if (
        SingleMessageRes?.Records?.[0]?.sender_id !=
        userDataRef.current?.user_id
      ) {
        dispatch(
          addUnSeenMessages({
            chat_id: SingleMessageRes?.Records?.[0]?.chat_id,
            message_id: SingleMessageRes?.Records?.[0]?.message_id,
          }),
        );
        console.log(
          SingleMessageRes?.Records?.[0]?.peerUserData.user_id,
          "SingleMessageRes?.Records?.[0]?.peerUserData.user_id",
        );
        console.log(
          currentChatRef.current.user_id,
          "currentChatRef.current.user_id",
        );

        if (
          currentChatRef.current.user_id !=
          SingleMessageRes?.Records?.[0]?.peerUserData.user_id
        ) {
          dispatch(
            updateUnreadCountByChatId({
              chat_id: SingleMessageRes?.Records?.[0]?.chat_id,
              mode: "increment",
            }),
          );
        }
      }
    }

    if (
      SingleMessageRes?.Records?.[0]?.Chat.archived_for.includes(
        userDataRef.current.user_id.toString(),
      )
    ) {
      dispatch(
        updateArchiveListForNewMessage({
          chat_id: SingleMessageRes?.Records?.[0]?.chat_id,
          last_message: SingleMessageRes?.Records?.[0]?.message_content,
          last_message_type: SingleMessageRes?.Records?.[0]?.message_type,
          peerUserData: SingleMessageRes?.Records?.[0]?.peerUserData,
          createdAt: SingleMessageRes?.Records?.[0]?.createdAt,
          cleared_for: [],
        }),
      );
    } else {
      dispatch(
        updateChatListForNewMessage({
          chat_id: SingleMessageRes?.Records?.[0]?.chat_id,
          last_message: SingleMessageRes?.Records?.[0]?.message_content,
          last_message_type: SingleMessageRes?.Records?.[0]?.message_type,
          peerUserData: SingleMessageRes?.Records?.[0]?.peerUserData,
          createdAt: SingleMessageRes?.Records?.[0]?.createdAt,
          Chat: SingleMessageRes?.Records?.[0]?.Chat,
          cleared_for: [],
          unseen_count:
            SingleMessageRes?.Records?.[0]?.User.user_id ==
            userDataRef.current.user_id
              ? 0
              : 1,
        }),
      );
    }
  }

  function updateMessageListCacheData(newMessage: SingleMessageRes) {
    const message = newMessage.Records[0];

    if (message.message_type === "group-created") return;

    const cacheKey = ["message_list", message.chat_id, 1];

    // ✅ First, get the current cached data
    const oldData = queryClient.getQueryData<any>(cacheKey);

    // ❌ If no cached data, don't touch anything
    if (!oldData || !oldData.message_list?.Records) {
      console.warn("No previous message list found in cache. Skipping update.");
      return;
    }

    // ✅ Proceed to update cache
    const updatedRecords = [message, ...oldData.message_list.Records];

    queryClient.setQueryData(cacheKey, {
      ...oldData,
      message_list: {
        ...oldData.message_list,
        Records: updatedRecords,
      },
    });

    console.log("Updated message list length:", updatedRecords.length);
  }

  function updateCachedMessageInAllPages({
    chat_id,
    message_id,
    updates,
  }: {
    chat_id: number;
    message_id: number;
    updates: {
      message?: string;
      delete_from_everyone?: boolean;
      pinned?: boolean;
      message_seen_status?: "seen" | "sent";
    };
  }) {
    const cache = queryClient.getQueryCache();

    // Get all queries related to this chat
    const cachedQueries = cache.findAll(["message_list"]).filter((q) => {
      const queryKey = q.queryKey;
      return queryKey[1] === chat_id;
    });

    cachedQueries.forEach((query) => {
      queryClient.setQueryData(query.queryKey, (oldData: any) => {
        if (!oldData || !oldData.message_list?.Records) return oldData;

        const updatedRecords = oldData.message_list.Records.map((msg: any) => {
          if (msg.message_id !== message_id) return msg;

          return {
            ...msg,
            message_content: updates.message ?? msg.message_content,
            deleted_for_everyone:
              updates.delete_from_everyone ?? msg.deleted_for_everyone,
            pinned: updates.pinned ?? msg.pinned,
            message_seen_status:
              updates.message_seen_status ?? msg.message_seen_status,
          };
        });

        return {
          ...oldData,
          message_list: {
            ...oldData.message_list,
            Records: updatedRecords,
          },
        };
      });
    });
  }

  useEffect(() => {
    const socket = socketInstance();

    socket.on("initial_online_user", (onlineUsers: OnlineUserRes) => {
      dispatch(initialOnlineUser(onlineUsers));
    });
    socket.on("online_user", (onlineUser: OnlineUser) => {
      dispatch(addOnlineUser(onlineUser));
    });
    socket.on("offline_user", (offlineUser: OnlineUser) => {
      dispatch(removeOnlineUser(offlineUser.user_id));
    });

    socket.on("typing", (typingUserData: TypingUser) => {
      if (typingUserData.typing) {
        dispatch(addTypingUser(typingUserData));
      } else {
        dispatch(removeTypingUser(typingUserData));
      }
    });

    socket.on("chat_list", (ChatListRes: ChatListRes) => {
      dispatch(updateChatList(ChatListRes));
      dispatch(
        updateViewState({
          is_chatlist_loading: false,
        }),
      );
    });

    socket.on("archived_chat_list", (ArchiveListRes: ChatListRes) => {
      dispatch(updateArchiveList(ArchiveListRes));
    });
    socket.on("archive_chat", (archiveChatRes: ArchiveChatRes) => {
      const { chat_id, isArchived } = archiveChatRes;
      if (isArchived) {
        dispatch(removeChatById(chat_id));
        socket.emit("archived_chat_list", {});
      } else {
        dispatch(removeArchiveChatById(chat_id));
        socket.emit("chat_list", {});
      }
    });

    // Below logic working but it is appending message at top instead of it's position ==================================================================================
    // socket.on("archive_chat", (archiveChatRes: ArchiveChatRes) => {
    //   const { chat_id, isArchived } = archiveChatRes;

    //   // Find the chat in whichever list it currently exists
    //   let chatToMove: OuterChat | undefined;

    //   if (isArchived) {
    //     const conversation = store
    //       .getState()
    //       .chatList.Chats.find((c) => c.Records[0].chat_id === chat_id);
    //     if (conversation) {
    //       chatToMove = conversation;
    //       dispatch(moveChatToArchive({ chat: chatToMove }));
    //       dispatch(addToArchiveList({ chat: chatToMove })); // add into archive
    //     }
    //   } else {
    //     const conversation = store
    //       .getState()
    //       .archiveList.Chats.find((c) => c.Records[0].chat_id === chat_id);
    //     if (conversation) {
    //       chatToMove = conversation;
    //       dispatch(moveChatFromArchive({ chat: chatToMove }));
    //       dispatch(addToChatList({ chat: chatToMove })); // add into chatlist
    //     }
    //   }
    // });

    socket.on("receive", (SingleMessageRes: SingleMessageRes) => {
      appendMessageToMessageList(SingleMessageRes);
      setTimeout(() => {
        updateMessageListCacheData(SingleMessageRes);
      }, 100);
    });

    socket.on(
      "connected-user-list",
      (ConnectedUserListRes: ConnectedUserListRes) => {
        dispatch(updateConnectedUserList(ConnectedUserListRes.connectedUsers));
      },
    );

    socket.on(
      "update_poll_vote",
      ({
        message_id,
        poll_option_id,
        chat_id,
        user_id,
      }: {
        message_id: number;
        poll_option_id: number;
        chat_id: number;
        user_id: number;
      }) => {
        console.log(message_id, poll_option_id, chat_id, user_id);

        // dispatch(
        //   updatePollVote({
        //     message_id: message_id,
        //     new_option_id: poll_option_id,
        //     user_id: user_id,
        //   }),
        // );
      },
    );

    // socket.on(
    //   "update_data",
    //   ({
    //     chat_id,
    //     delete_from_everyone_ids,
    //   }: {
    //     chat_id: number;
    //     delete_from_everyone_ids: number[];
    //   }) => {
    //     const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
    //     socketInstance().emit("chat_list", {});
    //     // console.log(chat_id, "chat_id");
    //     // console.log(
    //     //   currentChatRef.current.chat_id,
    //     //   "currentChatRef.current.chat_id",
    //     // );

    //     // Use the current value from the ref
    //     if (chat_id === currentChatRef.current.chat_id) {
    //       console.log(delete_from_everyone_ids, "delete_from_everyone_ids");

    //       console.log(chat_id, "remote chat_id");

    //       if (
    //         delete_from_everyone_ids?.length != 0 &&
    //         delete_from_everyone_ids?.length != undefined
    //       ) {
    //         console.log(MessageList, "MessageList+++++++++++++++++++");

    //         // update messages in message list ========================================================
    //         delete_from_everyone_ids.map((message_id) => {
    //           console.log(
    //             typeof message_id,
    //             "type of message_id +++++++++++++++++++++++++++++++",
    //           );

    //           dispatch(
    //             updateMessagesByIds({
    //               message: "🚫 This message was deleted!",
    //               message_id: Number(message_id),
    //               delete_from_everyone: true,
    //             }),
    //           );
    //           console.log(
    //             messageListRef.current.message_list.Records[
    //               messageListRef.current.message_list.Records.length - 1
    //             ],
    //             "messageListRef.current.message_list.Records.length - 1",
    //           );
    //           console.log(message_id, "message_id++++++++++++++");

    //           // Update chatlist if message is last message in messagelist =============================================
    //           if (
    //             messageListRef.current.message_list.Records[
    //               messageListRef.current.message_list.Records.length - 1
    //             ].message_id == message_id
    //           ) {
    //             dispatch(
    //               updateByChatId({
    //                 chat_id: currentChatRef.current.chat_id,
    //                 last_message: "🚫 This message was deleted!",
    //                 last_message_type: "text",
    //               }),
    //             );
    //           }
    //         });
    //       } else {
    //         socket.emit("message_list", {
    //           chat_id: chat_id,
    //           user_timezone: timeZone,
    //           per_page_message: 1,
    //         });
    //       }
    //     }

    //     // update messages in message list ========================================================
    //     // delete_from_everyone_ids.map((message_id) => {
    //     //   // Update chatlist if message is last message in messagelist =============================================
    //     //   if (
    //     //     messageListRef.current[messageListRef.current.length - 1]
    //     //       .message_id == message_id
    //     //   ) {
    //     //     dispatch(
    //     //       updateByChatId({
    //     //         chat_id: currentChatRef.current.chat_id,
    //     //         last_message: "🚫 This message was deleted!",
    //     //         last_message_type: "text",
    //     //       }),
    //     //     );
    //     //   }
    //     // });
    //   },
    // );

    socket.on(
      "delete_for_everyone",
      (deleteForEveryoneData: DeleteForEveryoneRes) => {
        const { chat_id, message_id } = deleteForEveryoneData;

        // Use the current value from the ref
        if (chat_id === currentChatRef.current.chat_id) {
          dispatch(
            updateMessagesByIds({
              message: "🚫 This message was deleted!",
              message_id: Number(message_id),
              delete_from_everyone: true,
            }),
          );

          // Update chatlist if message is last message in messagelist =============================================
          console.log(
            messageListRef.current.message_list.Records[
              messageListRef.current.message_list.Records.length - 1
            ].message_id,
            "messageListRef.current.message_list.Records.length - 1",
          );
          console.log(message_id, "message_id");
          if (
            messageListRef.current.message_list.Records[
              messageListRef.current.message_list.Records.length - 1
            ].message_id == message_id
          ) {
            dispatch(
              updateByChatId({
                chat_id: currentChatRef.current.chat_id,
                last_message: "🚫 This message was deleted!",
                last_message_type: "text",
              }),
            );
          }

          console.log(chat_id, "remote chat_id");

          console.log(MessageList, "MessageList+++++++++++++++++++");
        }

        // Update Cached Data
        updateCachedMessageInAllPages({
          chat_id: chat_id,
          message_id: message_id,
          updates: {
            delete_from_everyone: true,
            message: "🚫 This message was deleted!",
          },
        });
      },
    );

    socket.on(
      "real_time_message_seen",
      (realTimeMessageSeenData: RealTimeMessageSeenRes) => {
        dispatch(
          updateMessagesByIds({
            message_id: realTimeMessageSeenData.message_id,
            message_seen_status: "seen",
          }),
        );
        updateCachedMessageInAllPages({
          chat_id: realTimeMessageSeenData.chat_id,
          message_id: realTimeMessageSeenData.message_id,
          updates: {
            message_seen_status: "seen",
          },
        });
      },
    );

    socket.on("receiving_call", (callData: ReceivingCallRes) => {
      // Add user to connected user
      dispatch(
        addConnectedUser({
          profile_image: callData.user.profile_pic,
          user_id: callData.user.user_id,
          full_name: callData.user.full_name,
          user_name: callData.user.user_name,
        }),
      );
      dispatch(updateCallData(callData));
      const conversationData = {
        chat_id: callData.chat.chat_id,
        chat_type: callData.chat.chat_type,
        full_name: callData.user.full_name,
        group_name: callData.chat.group_name,
        group_icon: callData.chat.group_icon,
        profile_pic: callData.user.profile_pic,
        user_id: callData.user.user_id,
        user_name: callData.user.user_name,
      };

      // To Update current conversation
      dispatch(updateCurrentConversation(conversationData));
      // sessionStorage.setItem(
      //   "currentConversation",
      //   JSON.stringify(conversationData),
      // );

      // To show accept call modal
      dispatch(
        updateViewState({
          show_accept_call_modal: true,
        }),
      );

      // To store call data in session storage
      sessionStorage.setItem("call_type", callData.call.call_type);
      sessionStorage.setItem("is_caller", "true");
      sessionStorage.setItem("room_id", callData.call.room_id);
      sessionStorage.setItem("call_id", callData.call.call_id.toString());
      sessionStorage.setItem("chat_id", callData.chat.chat_id.toString());

      // To update peer data
      dispatch(
        updatePeerData({
          room_id: callData.call.room_id,
          call_id: callData.call.call_id,
          chat_id: callData.chat.chat_id.toString(),
        }),
      );
    });

    // When call declined
    // NOTE: callDecline event will not receive peer_id like UserJoinedRes
    socket.on("call_declined", (callDeclinedData: UserJoinedRes) => {
      dispatch(
        updateViewState({
          show_call_declined_modal: true,
        }),
      );
    });
    socket.on("missed_call", (missedCallData: CallEndedRes) => {
      dispatch(
        updateViewState({
          show_missed_call_modal: true,
        }),
      );
    });

    socket.on("pinned_unpinned_message", (pinUnpinData: MessageList) => {
      if (pinUnpinData.Records[0].chat_id == currentChatRef.current.chat_id) {
        if (pinUnpinData.Records[0].pinned) {
          dispatch(
            updateMessagesByIds({
              message_id: pinUnpinData.Records[0].message_id,
              pinned: true,
            }),
          );
          dispatch(appendPinnedMessages(pinUnpinData.Records[0]));
        } else {
          dispatch(
            updateMessagesByIds({
              message_id: pinUnpinData.Records[0].message_id,
              pinned: false,
            }),
          );
          dispatch(
            removePinnedMessagesByIds([pinUnpinData.Records[0].message_id]),
          );
        }
      }
    });
    socket.on("block_updates", (blockedUpdateData: BlockedUpdateRes) => {
      dispatch(
        updateByChatId({
          chat_id: blockedUpdateData.chat_id,
          last_message: "",
          last_message_type: "",
          blocked_by: blockedUpdateData.is_blocked
            ? [blockedUpdateData.user_id.toString()]
            : [],
        }),
      );
      if (blockedUpdateData.chat_id == currentChatRef.current.chat_id) {
        // sessionStorage.removeItem("currentConversation");
        if (userDataRef.current?.user_id == blockedUpdateData.user_id) {
          dispatch(
            updateCurrentConversation({
              is_group_blocked: blockedUpdateData.is_blocked,
            }),
          );
        } else {
          dispatch(
            updateCurrentConversation({
              other_user_blocked_you: blockedUpdateData.is_blocked,
            }),
          );
        }
      }
    });
  }, []);

  return <></>;
}
