import React, {useCallback, useEffect, useRef} from 'react';
import {FlatList, Keyboard} from 'react-native';
import {useTranslation} from 'react-i18next';
import {useDispatch} from 'react-redux';
import {useMutation} from 'react-query';
import {useShallow} from 'zustand/react/shallow';
import {PublishCommentData} from '@components/AddComment/interfaces';
import {MAX_ATTACHMENTS_SIZE} from '@components/AddComment/constants';
import {useGoBack} from '@hooks/useGoBack';
import {Comment, CommentableType} from '@interfaces/comments';
import {UserPermissions} from '@interfaces/user';
import {Attachment} from '@interfaces/attachments';
import {Reaction} from '@interfaces/reaction';
import {createPostComment} from '@modules/post/services';
import {useCommentsStore} from '@modules/post/store/useCommentsStore';
import {
  insertPostCommentReplyInStore,
  updatePostCommentInStore,
} from '@modules/post/utils';
import {openReactionPicker} from '@modules/app/redux';
import useReactToComments from '@modules/post/hooks/useReactToComments';
import {getCommonFormData} from '@modules/post/screens/PublishPost/utils';
import {usePostById} from '@modules/post/store/useFeedStore';
import {usePermission} from '@redux/selectors';
import {showSnackbar} from '@redux/dispatchers';
import {setCommentToEdit} from '@redux/comment/comment.actions';
import {updateComment} from '@services/comment';
import {wait} from '@shared/utils';

import CommentScreen from '../CommentScreen';

interface Props {
  postId: number;
  commentId: number;
  isReplying?: boolean;
  comesFromPush?: boolean;
}

function FeedCommentDetail({
  postId,
  commentId,
  isReplying = false,
  comesFromPush = false,
}: Props) {
  const {goBack} = useGoBack();
  const dispatch = useDispatch();
  const {t} = useTranslation();
  const canCommentGeneral = usePermission(UserPermissions.CREATE_COMMENT);
  const canCommentInPosts = usePermission(
    UserPermissions.CREATE_COMMENT_IN_POSTS,
  );
  const flatListRef = useRef<FlatList>(null);
  const canComment = canCommentGeneral || canCommentInPosts;
  const lastComment = usePostById(postId)?.lastComments?.[0];
  const {
    postComment,
    commentIds,
    isLoadingComments,
    isFetchingNextPageComments,
    refetchComments,
    fetchNextPage,
  } = useCommentsStore(
    useShallow(state => {
      const postComments = state.comments[postId]?.root;
      const commentReplies = state.comments[postId]?.replies[commentId];

      return {
        postComment:
          postComments?.items[commentId] || lastComment?.id === commentId
            ? lastComment
            : null,
        commentIds: commentReplies?.ids || [],
        isLoadingComments: commentReplies?.isLoading ?? false,
        isFetchingNextPageComments: commentReplies?.isFetchingNextPage ?? false,
        refetchComments: state.refetch,
        fetchNextPage: state.getNextPage,
      };
    }),
  );
  const {toggleCommentReaction} = useReactToComments();

  useEffect(() => {
    if (canComment && postId && commentId) {
      refetchComments({postId, parentId: commentId});
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (!postComment && !comesFromPush) {
      goBack();
    }
  }, [goBack, postComment, comesFromPush]);

  const onToggleSelectNewReaction = useCallback(
    ({comment}: {comment: Comment}) =>
      dispatch(
        openReactionPicker({
          commentId: comment.id,
          commentableType: CommentableType.POST,
          postId,
          parentId: comment?.id === commentId ? undefined : commentId,
          reactions: comment?.reactions || [],
          onReactionSelected: reaction =>
            toggleCommentReaction({
              postId,
              commentId: comment.id,
              parentId: comment?.id === commentId ? undefined : commentId,
              reaction,
              reactions: comment?.reactions || [],
            }),
        }),
      ),
    [dispatch, commentId, postId, toggleCommentReaction],
  );
  const onReactionPress = useCallback(
    ({
      reaction,
      commentId: commentIdToReact,
      reactions,
    }: {
      reaction: string;
      commentId: number;
      reactions: Reaction[];
    }) => {
      toggleCommentReaction({
        postId,
        commentId: commentIdToReact,
        parentId: commentIdToReact === commentId ? undefined : commentId,
        reaction,
        reactions: reactions || postComment?.reactions || [],
      });
    },
    [toggleCommentReaction, postId, commentId, postComment?.reactions],
  );

  const scrollToBottom = useCallback(async () => {
    await wait(300);
    flatListRef.current?.scrollToEnd({animated: true});
  }, []);

  const createPostCommentMutation = useMutation({
    mutationFn: createPostComment,
    onMutate: scrollToBottom,
    onSuccess: response => {
      insertPostCommentReplyInStore({
        postId,
        parentId: commentId,
        comment: response,
      });
    },
  });
  const updateCommentMutation = useMutation({
    mutationFn: updateComment,
    onSuccess: response => {
      updatePostCommentInStore(postId, response);
    },
    onSettled: () => {
      dispatch(setCommentToEdit(null));
    },
  });
  const handlePublishComment = ({
    attachmentsSize,
    commentToEdit,
    messageBody,
    images,
    videos,
    taggedUsers,
    gif,
  }: PublishCommentData) => {
    Keyboard.dismiss();
    if (attachmentsSize > MAX_ATTACHMENTS_SIZE) {
      showSnackbar({
        title: t('post.max_size_error'),
        variant: 'info',
      });
      return;
    }

    const commentableId = commentToEdit?.id || postId;
    const formData = {
      ...getCommonFormData({
        body: messageBody,
        images: images as Attachment[],
        videos: videos as Attachment[],
        taggedUsers,
        gif,
      }),
      id: commentableId,
    };

    return commentToEdit
      ? updateCommentMutation.mutateAsync({
          ...formData,
          commentableId,
          parentId: commentId,
        })
      : createPostCommentMutation.mutateAsync({
          ...formData,
          parentId: commentId,
        });
  };

  // Create wrapper functions for the CommentScreen props
  const handleRefresh = useCallback(() => {
    refetchComments({postId, parentId: commentId});
  }, [refetchComments, postId, commentId]);

  const handleGetNextPage = useCallback(() => {
    fetchNextPage({postId, parentId: commentId});
  }, [fetchNextPage, postId, commentId]);

  if (!postComment) return null;

  return (
    <CommentScreen
      ref={flatListRef}
      commentIds={commentIds}
      isAddingNewComment={createPostCommentMutation.isLoading}
      isLoading={isLoadingComments}
      isLoadingNextPage={isFetchingNextPageComments}
      getNextPage={handleGetNextPage}
      onRefresh={handleRefresh}
      postId={postId}
      parentId={commentId}
      user={postComment.user}
      handlePublishComment={handlePublishComment}
      onToggleSelectNewReaction={onToggleSelectNewReaction}
      onReactionPress={onReactionPress}
      isReplying={isReplying}
      canComment={canComment}
      canInteract
    />
  );
}

export default FeedCommentDetail;
