import { type FC, useEffect } from 'react';
import { Helmet } from 'react-helmet-async';
import { useMutation, useQuery } from 'react-query';
import { useNavigate } from 'react-router-dom';

import { StreamVideo } from '@stream-io/video-react-sdk';
import CircularProgress from '@material-hu/mui/CircularProgress';
import Stack from '@material-hu/mui/Stack';

import { logEvent } from 'src/config/logging';
import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useAuth } from 'src/contexts/JWTContext';
import { useSocket } from 'src/contexts/SocketContext';
import useGeneralError from 'src/hooks/useGeneralError';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import { useMutationOnMount } from 'src/hooks/useMutationOnMount';
import useRequiredParams from 'src/hooks/useRequiredParams';
import useGetStreamVideoClient from 'src/pages/dashboard/liveStream/hooks/useGetStreamVideoClient';
import { getGroupDetails, getGroupPostDetails } from 'src/services/groups';
import { markNotificationAsRead } from 'src/pages/dashboard/notifications/services';
import { EventName } from 'src/types/amplitude';
import { type Reaction } from 'src/types/reaction';
import { UserTypeStream } from 'src/types/stream';
import { userIsOnGroupPostDetailPage } from 'src/utils/groups';
import { formatTitle } from 'src/utils/helmetUtils';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';
import { addReaction, removeReaction } from 'src/utils/reactions';

import {
  NotificationModuleCodes,
  NotificationTypeCodes,
} from '../notifications/constants';

import GroupPostCard from './components/GroupPostCard';
import { GroupMemberProvider } from './GroupMemberContext';
import {
  addGroupFeedDetailDataReaction,
  dropGroupChildComment,
  dropGroupComment,
  groupPostDeleted,
  groupsKeys,
  invalidateGroupPost,
  removeGroupFeedDetailDataReaction,
  unshiftGroupChildComment,
  unshiftGroupComment,
  updateGroupReactionCommentData,
} from './queries';
import { groupsRoutes } from './routes';

const GroupPostDetail: FC = () => {
  const { id, postId } = useRequiredParams(['id', 'postId'], -1);
  const socket = useSocket();
  const { user } = useAuth();
  const navigate = useNavigate();

  const { t } = useTranslation(['post']);

  const HugoThemeProvider = useHuGoTheme();

  const showGeneralError = useGeneralError();

  const client = useGetStreamVideoClient(UserTypeStream.VIEWER);

  const { data, isLoading } = useQuery(
    groupsKeys.detail(id),
    () => getGroupDetails(id),
    {
      onError: err => {
        showGeneralError(err, t('error_loading_group'));
      },
    },
  );

  const { data: postData, isLoading: isLoadingPost } = useQuery(
    groupsKeys.postDetail(id, postId),
    () => getGroupPostDetails(id, postId),
    {
      onSuccess: () => {
        logEvent(EventName.GROUPS_POST_DETAILS_VIEWED, {
          postId: postId,
          groupId: Number(id),
        });
      },
      select: response => response.data,
      onError: err => {
        showGeneralError(err, t('error_loading_post'));
      },
    },
  );

  const mutation = useMutation(() =>
    markNotificationAsRead(
      NotificationModuleCodes.GROUPS,
      NotificationTypeCodes.NEW_GROUP_POST,
      {
        refId: postId,
      },
    ),
  );

  useMutationOnMount(mutation, postId);

  useEffect(() => {
    const addNewComent = ({
      comment,
      groupId,
      postId: updatedPostId,
    }: {
      comment: any;
      groupId: number;
      postId: number;
    }) => {
      const isOnUpdatedGroupPost = userIsOnGroupPostDetailPage(
        groupId,
        updatedPostId,
      );
      if (isOnUpdatedGroupPost)
        comment.parentId
          ? unshiftGroupChildComment(
              updatedPostId,
              `${groupId}`,
              comment.parentId,
              comment,
            )
          : unshiftGroupComment(updatedPostId, `${groupId}`, comment);
    };

    const addNewReaction = ({
      reaction,
      groupId,
      postId: updatedPostId,
    }: {
      reaction: Reaction;
      groupId: number;
      postId: number;
    }) => {
      const isOnUpdatedGroupPost = userIsOnGroupPostDetailPage(
        groupId,
        updatedPostId,
      );
      if (isOnUpdatedGroupPost)
        addGroupFeedDetailDataReaction(
          updatedPostId,
          `${groupId}`,
          reaction.emoji,
          reaction.unified,
          reaction.isLoggedUserReaction,
        );
    };

    const removePost = ({
      groupId,
      postId: updatedPostId,
    }: {
      groupId: number;
      postId: number;
    }) => {
      const isOnUpdatedGroupPost = userIsOnGroupPostDetailPage(
        groupId,
        updatedPostId,
      );
      if (isOnUpdatedGroupPost) {
        groupPostDeleted(`${groupId}`);
        navigate(groupsRoutes.detail(groupId));
      }
    };

    const updatePost = ({
      groupId,
      id: updatedPostId,
    }: {
      groupId: number;
      id: number;
    }) => {
      const isOnUpdatedGroupPost = userIsOnGroupPostDetailPage(
        groupId,
        updatedPostId,
      );
      if (isOnUpdatedGroupPost) {
        invalidateGroupPost(`${groupId}`, `${updatedPostId}`);
      }
    };

    const removeComment = ({
      commentId,
      parentId,
      groupId,
      postId: updatedPostId,
    }: {
      commentId: number;
      parentId: number;
      groupId: number;
      postId: number;
    }) => {
      const isOnUpdatedGroupPost = userIsOnGroupPostDetailPage(
        groupId,
        updatedPostId,
      );
      if (isOnUpdatedGroupPost) {
        parentId
          ? dropGroupChildComment(
              updatedPostId,
              `${groupId}`,
              parentId,
              commentId,
            )
          : dropGroupComment(updatedPostId, `${groupId}`, commentId);
      }
    };

    const removePostReaction = ({
      emoji,
      groupId,
      postId: updatedPostId,
      userId,
    }: {
      emoji: string;
      groupId: number;
      postId: number;
      userId: number;
    }) => {
      const isOnUpdatedGroupPost = userIsOnGroupPostDetailPage(
        groupId,
        updatedPostId,
      );
      if (isOnUpdatedGroupPost)
        removeGroupFeedDetailDataReaction(
          updatedPostId,
          `${groupId}`,
          emoji,
          userId === user?.id,
        );
    };

    const addCommentReaction = ({
      commentId,
      groupId,
      postId: updatedPostId,
      reaction,
    }: {
      commentId: number;
      groupId: number;
      postId: number;
      reaction: Reaction;
    }) => {
      const isOnUpdatedGroupPost = userIsOnGroupPostDetailPage(
        groupId,
        updatedPostId,
      );
      if (isOnUpdatedGroupPost) {
        updateGroupReactionCommentData(
          updatedPostId,
          `${groupId}`,
          commentId,
          reactions =>
            addReaction(
              reactions,
              reaction.emoji,
              reaction.unified,
              reaction.isLoggedUserReaction,
            ),
        );
      }
    };

    const removeCommentReaction = ({
      commentId,
      emoji,
      groupId,
      postId: updatedPostId,
      userId,
    }: {
      commentId: number;
      emoji: string;
      groupId: number;
      postId: number;
      userId: number;
    }) => {
      const isOnUpdatedGroupPost = userIsOnGroupPostDetailPage(
        groupId,
        updatedPostId,
      );
      if (isOnUpdatedGroupPost) {
        updateGroupReactionCommentData(
          updatedPostId,
          `${groupId}`,
          commentId,
          reactions => removeReaction(reactions, emoji, userId === user?.id),
        );
      }
    };

    socket.listenEvent(EVENTS_SOCKETS.GROUP_POST_COMMENT_CREATED, addNewComent);

    socket.listenEvent(
      EVENTS_SOCKETS.GROUP_POST_REACTION_CREATED,
      addNewReaction,
    );

    socket.listenEvent(EVENTS_SOCKETS.GROUP_POST_DELETED, removePost);

    socket.listenEvent(EVENTS_SOCKETS.GROUP_POST_EDITED, updatePost);

    socket.listenEvent(
      EVENTS_SOCKETS.GROUP_POST_COMMENT_DELETED,
      removeComment,
    );

    socket.listenEvent(
      EVENTS_SOCKETS.GROUP_POST_REACTION_DELETED,
      removePostReaction,
    );

    socket.listenEvent(
      EVENTS_SOCKETS.GROUP_POST_COMMENT_REACTION_CREATED,
      addCommentReaction,
    );

    socket.listenEvent(
      EVENTS_SOCKETS.GROUP_POST_COMMENT_REACTION_DELETED,
      removeCommentReaction,
    );

    return () => {
      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_POST_COMMENT_CREATED,
        addNewComent,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_POST_REACTION_CREATED,
        addNewReaction,
      );

      socket.closeEvent(EVENTS_SOCKETS.GROUP_POST_DELETED, removePost);

      socket.closeEvent(EVENTS_SOCKETS.GROUP_POST_EDITED, updatePost);

      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_POST_COMMENT_DELETED,
        removeComment,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_POST_REACTION_DELETED,
        removePostReaction,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_POST_COMMENT_REACTION_CREATED,
        addCommentReaction,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_POST_COMMENT_REACTION_DELETED,
        removeCommentReaction,
      );
    };
  }, [socket]);

  const handleAddReaction = (
    addPostId: number,
    emoji: string,
    unified: string,
  ) => addGroupFeedDetailDataReaction(addPostId, id, emoji, unified);

  const handleRemoveReaction = (removePostId: number, emoji: string) =>
    removeGroupFeedDetailDataReaction(removePostId, id, emoji);

  const isLoadingResource = isLoading || isLoadingPost;

  return (
    <StreamVideo client={client}>
      <HugoThemeProvider>
        <Helmet>
          <title>{formatTitle(t('group:groups'))}</title>
        </Helmet>
        <Stack
          sx={{
            backgroundColor: theme =>
              theme.palette.new.background.layout.default,
            alignItems: 'center',
            pt: 3,
            pb: 8,
          }}
        >
          {isLoadingResource && (
            <Stack sx={{ textAlign: 'center' }}>
              <CircularProgress />
            </Stack>
          )}
          {!isLoadingResource && data?.data && (
            <GroupMemberProvider
              members={data?.data.members}
              publicationPolicy={data?.data.publicationPolicy}
              approvalPolicy={data?.data.approvalPolicy}
              privacyPolicy={data?.data.privacyPolicy}
              isArchived={data?.data.isArchived}
            >
              <Stack sx={{ width: '80%', mt: 3 }}>
                <Stack sx={{ mt: 3 }}>
                  {postData && (
                    <GroupPostCard
                      onAddReaction={handleAddReaction}
                      onRemoveReaction={handleRemoveReaction}
                      showBreadcrumb
                      post={postData}
                    />
                  )}
                </Stack>
              </Stack>
            </GroupMemberProvider>
          )}
        </Stack>
      </HugoThemeProvider>
    </StreamVideo>
  );
};

export default GroupPostDetail;
