import React, {useCallback, useEffect, useRef, useState} from 'react';
import {FlatList, Keyboard, View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {useDispatch} from 'react-redux';
import {useMutation} from 'react-query';
import {
  CommentSkeleton,
  MarginKeyboardAwareView,
  ReactionsSummaryComments,
  Spinner,
  Typography,
  RefreshControl,
  AddComment,
  AddCommentRefType,
} from '@components';
import {PublishCommentData} from '@components/AddComment/interfaces';
import {MAX_ATTACHMENTS_SIZE} from '@components/AddComment/constants';
import {useGoBack} from '@hooks/useGoBack';
import {useReactionsSummary} from '@hooks/useReactionsSummary';
import {useQueryFetchIfEmpty} from '@hooks/queries/useQueryFetchIfEmpty';
import {UserPermissions} from '@interfaces/user';
import {Attachment} from '@interfaces/attachments';
import {Comment as CommentType} from '@interfaces/comments';
import {getCommonFormData} from '@modules/post/screens/PublishPost/utils';
import {
  useCommentActions,
  useCommentById,
  useCommentIds,
  useCommentSlice,
} from '@modules/group/store/useGroupPostCommentsStore';
import {styles} from '@modules/post/screens/CommentDetailRefactored/styles';
import GroupCommentItem from '@modules/group/components/GroupCommentItem';
import {
  createGroupPostComment,
  getGroupById,
  updateGroupPostComment,
} from '@modules/group/services';
import {GROUP_QUERY_KEYS} from '@modules/group/constants';
import {usePermission, useUserId} from '@redux/selectors';
import {showSnackbar} from '@redux/dispatchers';
import {setCommentToEdit} from '@redux/comment/comment.actions';
import {getCompleteName, isIos, wait} from '@shared/utils';
import {useTheme} from '@shared/theme';

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

const keyExtractor = (item: number) => `${item}`;

// Placing this in screens, since its going to be a route later
function GroupCommentDetail({
  groupId,
  postId,
  commentId,
  isReplying = false,
  comesFromPush = false,
}: Props) {
  const {t} = useTranslation();
  const {theme} = useTheme();
  const {goBack} = useGoBack();
  const userId = useUserId();
  const [showAddComment, setShowAddComment] = useState(false);
  const addCommentRef = useRef<AddCommentRefType>(null);
  const dispatch = useDispatch();
  const canCommentGeneral = usePermission(UserPermissions.CREATE_COMMENT);
  const canCommentInPosts = usePermission(
    UserPermissions.CREATE_COMMENT_IN_POSTS,
  );
  const flatListRef = useRef<FlatList>(null);
  const canComment = canCommentGeneral || canCommentInPosts;
  const commentsSlice = useCommentSlice(postId, commentId);
  const commentIds = useCommentIds(postId, commentId);
  const postComment = useCommentById(postId, commentId);
  const {refetch, getNextPage, addComment, updateComment} = useCommentActions();
  const {data: group} = useQueryFetchIfEmpty(
    GROUP_QUERY_KEYS.group(groupId),
    () => getGroupById(groupId),
    {
      onError: goBack,
    },
  );
  const isArchived = group?.isArchived;
  useEffect(() => {
    if (!postComment && !comesFromPush) goBack();
  }, [goBack, postComment, comesFromPush]);

  const onRefetch = useCallback(() => {
    refetch({groupId, postId, parentId: commentId});
  }, [commentId, groupId, postId, refetch]);

  useEffect(() => {
    onRefetch();
  }, [commentId, groupId, onRefetch, postId, refetch]);

  useEffect(() => {
    // On Android, mounting `AddComment` (it uses `KeyboardStickyView`) immediately can cause
    // a layout "jump" when the keyboard opens due to offset measurement timing.
    // Small delay to let the layout settle before rendering the sticky input.
    setTimeout(() => {
      setShowAddComment(true);
    }, 300);
  }, []);

  const onGetNextPage = useCallback(() => {
    getNextPage({groupId, postId, parentId: commentId});
  }, [commentId, getNextPage, groupId, postId]);

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

  const onReplyPress = useCallback(() => {
    addCommentRef.current?.focus();
  }, [addCommentRef]);

  const onCommentReplyPress = useCallback(
    (index: number) => (item: CommentType) => {
      flatListRef.current?.scrollToIndex({index, animated: true});
      addCommentRef.current?.initiateTag(
        item.user.id,
        getCompleteName(item.user),
      );
    },
    [addCommentRef],
  );

  const createPostCommentMutation = useMutation({
    mutationFn: createGroupPostComment,
    onMutate: scrollToBottom,
    onSuccess: response => {
      addComment({
        postId,
        comment: response,
        parentId: commentId,
      });
    },
  });
  const updateCommentMutation = useMutation({
    mutationFn: updateGroupPostComment,
    onSuccess: response => {
      updateComment({
        postId,
        commentId: response.id,
        parentId: commentId,
        updater: () => 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,
      }),
      groupId,
      parentId: commentId,
      id: commentableId,
    };

    return commentToEdit
      ? updateCommentMutation.mutateAsync({
          ...formData,
          postId,
        })
      : createPostCommentMutation.mutateAsync({
          ...formData,
        });
  };

  const {
    showReactionsSummary,
    selectedReaction,
    setSelectedReaction,
    onCloseReactionsSummary,
  } = useReactionsSummary();

  const renderComment = useCallback(
    ({item, index}: {item: number; index: number}) => (
      <GroupCommentItem
        postId={postId}
        groupId={groupId}
        parentId={commentId}
        commentId={item}
        onReplyPress={onCommentReplyPress(index)}
        userId={userId}
        isArchived={isArchived}
      />
    ),
    [commentId, groupId, isArchived, onCommentReplyPress, postId, userId],
  );

  if (!postComment) return null;

  return (
    <View
      style={[
        styles.commentDetailContainer,
        {backgroundColor: theme.background.elements.grey},
      ]}>
      <View style={styles.container}>
        <Typography weight="semiBold" color={theme.text.neutral.default}>
          {t('post.responses_to')}{' '}
          <Typography weight="semiBold" color={theme.text.neutral.default}>
            {getCompleteName(postComment.user)}
          </Typography>
        </Typography>
      </View>
      <MarginKeyboardAwareView>
        <FlatList
          keyboardDismissMode={isIos ? 'interactive' : 'on-drag'}
          style={[
            styles.listContainer,
            {backgroundColor: theme.background.elements.default},
          ]}
          data={commentIds}
          ListHeaderComponent={
            <GroupCommentItem
              postId={postId}
              groupId={groupId}
              commentId={commentId}
              onReplyPress={onReplyPress}
              userId={userId}
              isReply={false}
              isArchived={isArchived}
            />
          }
          keyExtractor={keyExtractor}
          ref={flatListRef}
          showsVerticalScrollIndicator={false}
          refreshControl={
            <RefreshControl
              refreshing={commentsSlice?.isLoading}
              onRefresh={onRefetch}
            />
          }
          renderItem={renderComment}
          onEndReached={onGetNextPage}
          ListFooterComponent={
            <View style={styles.footerContainer}>
              {createPostCommentMutation.isLoading && (
                <View style={styles.skeletonContainer}>
                  <CommentSkeleton />
                </View>
              )}
              {commentsSlice?.isFetchingNextPage && <Spinner />}
            </View>
          }
        />
      </MarginKeyboardAwareView>
      {!isArchived && canComment && showAddComment && (
        <AddComment
          keyProp="group-comment-screen-add-comment"
          autoFocus={isReplying}
          onPublishComment={handlePublishComment}
          ref={addCommentRef}
          groupId={groupId}
        />
      )}
      {showReactionsSummary && (
        <ReactionsSummaryComments
          showReactionsSummary
          setSelectedReaction={setSelectedReaction}
          reactions={postComment?.reactions}
          id={commentId}
          selectedReaction={selectedReaction}
          onCloseReactionsSummary={onCloseReactionsSummary}
          groupId={groupId}
          postId={postId}
        />
      )}
    </View>
  );
}

export default GroupCommentDetail;
