import React, {
  useCallback,
  useEffect,
  useLayoutEffect,
  useRef,
  useState,
} from 'react';
import {FlatList, Keyboard, LayoutChangeEvent, View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {useMutation} from 'react-query';
import {useDispatch} from 'react-redux';
import {IconLink} from '@tabler/icons-react-native';
import {
  CommentSkeleton,
  ListFooter,
  MarginKeyboardAwareView,
  PostCommentItem,
  RefreshControl,
  ArticleSkeleton,
  IconButton,
  AddComment,
  AddCommentRefType,
  PublishCommentData,
} from '@components';
import i18next, {Language} from '@config/i18n';
import {useTimeInScreen} from '@hooks/useTimeInScreen';
import {Comment} from '@interfaces/comments';
import {Navigation} from '@interfaces/navigation';
import {Attachment} from '@interfaces/attachments';
import {useGetArticle} from '@modules/article/hooks/useGetArticle';
import {useGetArticleComments} from '@modules/article/hooks/useGetArticleComments';
import {ArticleBody} from '@modules/article/components';
import {createArticleComment} from '@modules/article/services';
import {handleAddCommentEvent} from '@modules/article/utils';
import {ArticleCommentSocket} from '@modules/article/interfaces';
import {getCommonFormData} from '@modules/post/screens/PublishPost/utils';
import useReactToComments from '@modules/article/hooks/useReactToComments';
import {openReactionPicker} from '@modules/app/redux';
import {useAppSelector} from '@redux/utils';
import {copyToClipboard, isIos, wait} from '@shared/utils';
import {
  Screens,
  DEFAULT_THRESHOLD,
  windowDimensions,
  AMPLITUDE_EVENTS,
} from '@shared/constants';
import {useTheme} from '@shared/theme';
import {commonStyles} from '@shared/styles';
import {HUMAND_URL} from '@shared/keys';

import {styles} from './styles';

const WAITING_TIME = 500;

function NewsDetail({route, navigation}: Navigation<Screens.NEWS_DETAIL>) {
  const {theme, spacing} = useTheme();
  const {t} = useTranslation();
  const flatListRef = useRef<Nullable<FlatList>>(null);
  const scrolledToBottom = useRef<boolean>(false);
  const [articleLoaded, setArticleLoaded] = useState<boolean>(false);
  const [contentWidth, setContentWidth] = useState(windowDimensions.width);
  const {id: idParam, timeAgo, shouldScrollToComments} = route.params;
  const {
    CREATE_COMMENT,
    CREATE_COMMENT_IN_ARTICLES,
    MANAGE_POSTS,
    MANAGE_COMMENTS,
    MANAGE_ARTICLES_COMMENTS,
    CAN_REACT_CONTENT: canReactContentGeneral,
    CAN_REACT_ARTICLES: canReactArticles,
  } = useAppSelector(({user}) => user.permissions);
  const canCreateComment = CREATE_COMMENT || CREATE_COMMENT_IN_ARTICLES;
  const canReactContent = canReactContentGeneral || canReactArticles;
  const dispatch = useDispatch();
  const addCommentRef = useRef<AddCommentRefType>(null);
  const {toggleCommentReaction} = useReactToComments({articleId: idParam});
  const {
    article,
    isLoading: isLoadingArticle,
    refetch,
  } = useGetArticle(idParam);
  const {
    comments,
    isLoading: isLoadingComments,
    isLoadingNextPage,
    fetchNextPage,
    refetch: refetchComments,
  } = useGetArticleComments({articleId: idParam});
  const moduleNames = useAppSelector(({instance}) => instance.moduleNames);
  const i18nArticles =
    moduleNames?.[i18next.language as Language]?.ARTICLES || t('home.articles');
  const isLoading = isLoadingArticle || isLoadingComments;
  const showAddComment = !!(canCreateComment && article?.id);

  const onPressCopyLink = useCallback(() => {
    copyToClipboard(
      {
        text: `${HUMAND_URL}news/${idParam}`,
      },
      {
        variant: 'success',
        title: t('deeplinks.copy_success'),
      },
    );
  }, [idParam, t]);

  useLayoutEffect(() => {
    const headerRight = () => (
      <IconButton
        Icon={IconLink}
        iconColor={theme.text.neutral.default}
        onPress={onPressCopyLink}
        variant="tertiary"
      />
    );
    navigation.setOptions({
      title: i18nArticles,
      headerRight,
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [i18nArticles, theme.text.neutral.default, onPressCopyLink]);

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

  const createArticleMutation = useMutation({
    mutationFn: ({
      messageBody,
      images,
      videos,
      taggedUsers,
      gif,
    }: PublishCommentData) => {
      const formData = {
        ...getCommonFormData({
          body: messageBody,
          images: images as Attachment[],
          videos: videos as Attachment[],
          taggedUsers,
          gif,
        }),
        id: article!.id,
      };
      return createArticleComment(formData);
    },
    onMutate: handleScrollToEnd,
    onSuccess: response => {
      handleAddCommentEvent({
        tags: [],
        data: {
          articleId: article!.id,
          ...response,
        } as ArticleCommentSocket,
        shouldUpdateArticleList: false,
      });
    },
  });

  useTimeInScreen(AMPLITUDE_EVENTS.ARTICLE_VIEW, {
    newsId: article?.id,
    name: article?.title,
  });

  const handleArticleBodyLoaded = useCallback(() => setArticleLoaded(true), []);

  const handleScrollToFirstComment = useCallback(async () => {
    await wait(WAITING_TIME);
    flatListRef.current?.scrollToIndex({
      index: 0,
    });
  }, [flatListRef]);

  const handleLayout = useCallback((e: LayoutChangeEvent) => {
    setContentWidth(e.nativeEvent.layout.width);
  }, []);

  const keyExtractor = useCallback((item: Comment) => item.id.toString(), []);

  const onDetailPress = useCallback(
    (id: number) => () => {
      navigation.navigate(Screens.COMMENT_DETAIL, {
        parentCommentId: id,
        articleId: idParam,
        postId: idParam, // When refactor is finished, we should remove this prop
      });
    },
    [navigation, idParam],
  );

  const onReplyPress = useCallback(
    (id: number) => () => {
      navigation.navigate(Screens.COMMENT_DETAIL, {
        parentCommentId: id,
        articleId: idParam,
        postId: idParam,
        isReplying: true,
      });
    },
    [navigation, idParam],
  );

  const onCommentReactionPress = useCallback(
    (reaction: string, comment: Comment) => {
      toggleCommentReaction({
        commentId: comment.id,
        reactions: comment.reactions || [],
        reaction,
        parentId: comment.parentId || undefined,
      });
    },
    [toggleCommentReaction],
  );

  const toggleReactionsBottomSheet = useCallback(
    (comment: Comment) => {
      dispatch(
        openReactionPicker({
          commentId: comment.id,
          postId: idParam,
          reactions: comment.reactions || [],
          onReactionSelected: (reaction: string) =>
            toggleCommentReaction({
              commentId: comment.id,
              reactions: comment.reactions || [],
              reaction,
              parentId: comment.parentId || undefined,
            }),
        }),
      );
    },
    [dispatch, idParam, toggleCommentReaction],
  );
  const renderItem = useCallback(
    ({item}: {item: Comment}) => (
      <PostCommentItem
        item={item}
        canManagePosts={MANAGE_POSTS}
        canManageComments={MANAGE_COMMENTS || MANAGE_ARTICLES_COMMENTS}
        postId={item.id}
        articleId={idParam}
        onDetailPress={onDetailPress(item.id)}
        onReplyPress={onReplyPress(item.id)}
        onReactionPress={onCommentReactionPress}
        toggleReactionsBottomSheet={toggleReactionsBottomSheet}
      />
    ),
    [
      MANAGE_ARTICLES_COMMENTS,
      MANAGE_COMMENTS,
      MANAGE_POSTS,
      idParam,
      onCommentReactionPress,
      onDetailPress,
      onReplyPress,
      toggleReactionsBottomSheet,
    ],
  );

  useEffect(() => {
    if (
      shouldScrollToComments &&
      articleLoaded &&
      flatListRef.current &&
      !isLoading &&
      comments.length > 0 &&
      !scrolledToBottom.current
    ) {
      try {
        scrolledToBottom.current = true;

        handleScrollToFirstComment();
      } catch (error) {
        // Avoid crashes when scroll to item
      }
    }
  }, [
    flatListRef,
    shouldScrollToComments,
    articleLoaded,
    isLoading,
    comments.length,
    handleScrollToFirstComment,
  ]);

  const onRefreshPage = () => {
    refetch();
    refetchComments();
  };

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

  return (
    <View
      style={[
        commonStyles.flex,
        {backgroundColor: theme.background.elements.default},
      ]}>
      {isLoading || !article ? (
        <View style={styles.skeletonContainer}>
          <ArticleSkeleton />
        </View>
      ) : (
        <MarginKeyboardAwareView>
          <FlatList
            refreshControl={
              <RefreshControl
                refreshing={isLoading}
                onRefresh={onRefreshPage}
              />
            }
            keyboardDismissMode={isIos ? 'interactive' : 'on-drag'}
            ref={flatListRef}
            data={comments}
            keyExtractor={keyExtractor}
            renderItem={renderItem}
            style={commonStyles.flex}
            contentContainerStyle={{
              backgroundColor: theme.background.elements.default,
            }}
            onEndReached={fetchNextPage}
            onEndReachedThreshold={DEFAULT_THRESHOLD}
            alwaysBounceVertical={false}
            onLayout={handleLayout}
            ListHeaderComponent={
              article ? (
                <ArticleBody
                  article={article}
                  onPressComment={onPressComment}
                  showAddComment={showAddComment}
                  // Remove the padding from the content width to avoid the horizontal scroll
                  contentWidth={contentWidth - spacing.x4}
                  timeAgo={timeAgo}
                  showReactions={articleLoaded && !!canReactContent}
                  onLoaded={handleArticleBodyLoaded}
                />
              ) : null
            }
            ListFooterComponent={
              <View style={styles.footerContainer}>
                {createArticleMutation.isLoading && (
                  <View style={styles.commentSkeletonContainer}>
                    <CommentSkeleton />
                  </View>
                )}
                <ListFooter
                  paginationType="infiniteScroll"
                  isFetchingNextPage={isLoadingNextPage}
                  isVisible
                />
              </View>
            }
          />
        </MarginKeyboardAwareView>
      )}
      {showAddComment && (
        <AddComment
          ref={addCommentRef}
          keyProp="article-screen-add-comment"
          onPublishComment={createArticleMutation.mutateAsync}
          loading={createArticleMutation.isLoading}
        />
      )}
    </View>
  );
}

export default NewsDetail;
