import React, {useState, useMemo, memo, useCallback} from 'react';
import {View, StyleProp, TextStyle, ViewStyle, Pressable} from 'react-native';
import {useTranslation} from 'react-i18next';
import {shallowEqual, useDispatch} from 'react-redux';
import {StackActions, useNavigation} from '@react-navigation/native';
import {
  IconArrowsRightLeft,
  IconChevronRight,
  IconPinned,
} from '@tabler/icons-react-native';
import {
  Avatar,
  AvatarBorderVariant,
  BasePost,
  Button,
  Pill,
  Typography,
  KeyUpdateLabel,
} from '@components';
import Text from '@components/Text';
import {formatNumber} from '@components/_HuGo/Inputs/utils';
import {Comment, CommentableType} from '@interfaces/comments';
import {Attachment} from '@interfaces/attachments';
import {Post as PostType, FullPost} from '@modules/post/interfaces';
import {Article} from '@modules/article/interfaces';
import {
  addGroupPostReaction,
  removeGroupPostReaction,
} from '@modules/group/services';
import {Acknowledgement} from '@modules/acknowledgement/interfaces';
import {useMarketplaceStore} from '@modules/marketplace/stores/useMarketplaceStore';
import {reactToPost, unReactToPost} from '@modules/post/store';
import {getMarketplacePost} from '@modules/marketplace/services';
import {getPost} from '@modules/post/services';
import {PostStreamStatus} from '@modules/livestream/interfaces';
import {useInitializeChat} from '@modules/chats/hooks/useInitializeChat';
import {useAppSelector} from '@redux/utils';
import {
  addCommentReaction,
  removeCommentReaction,
  setCommentToEdit,
} from '@redux/comment/comment.actions';
import {getIsReactionLoggedUser} from '@shared/utils/generics';
import {
  wait,
  getCompleteName,
  shortenText,
  truncateHtml,
  getExactTimeAgo,
} from '@shared/utils';
import {Screens} from '@shared/constants';
import {useTheme} from '@shared/theme';

import {styles} from './styles';
import {
  COLLAPSED_POST_BODY_LIMIT,
  COMMENT_BODY_LIMIT,
  MAX_EXTERNAL_POST_TITLE_LENGTH,
  MAX_LIVESTREAM_POST_TITLE_LENGTH,
  MAX_POST_TITLE_LENGTH,
  POST_BODY_LIMIT,
  WAITING_TIME,
} from './constants';
import PostBody from './components/PostBody';
import PostOptions from './components/PostOptions';
import {PostBodyProps} from './components/PostBody/interfaces';

interface PostProps extends Pick<PostBodyProps, 'bodySizeLimit' | 'onPress'> {
  post: PostType | FullPost | Comment | Article | Acknowledgement;
  style?: StyleProp<ViewStyle>;
  canManagePosts?: boolean;
  canManageComments?: boolean;
  withImage?: boolean;
  collapsedByDefault?: boolean;
  canInteract?: boolean;
  isComment?: boolean;
  postId?: number;
  goBackOnDelete?: boolean;
  displayLastComment?: boolean;
  articleId?: number;
  groupId?: number;
  isMarketplace?: boolean;
  customNameStyle?: TextStyle;
  isPinned?: boolean;
  canEdit?: boolean;
  showComments?: boolean;
  showReactions?: boolean;
  onPressComment?: () => void;
  onOptionsPress?: () => void;
  hideMenuOptions?: boolean;
  onReactionPress?: (reaction: string) => void;
  onCommentReactionPress?: ({
    commentId,
    parentId,
    reactions,
  }: {
    commentId: number;
    parentId?: number;
    reactions: BasePost['reactions'];
    reaction: string;
  }) => void;
  isArchived?: boolean;
}

/**
 * TODO: Pending unification of components/Post and _custom/Post
 * @deprecated Use `_custom/Post` instead
 */
function Post({
  post,
  style,
  canManagePosts,
  canManageComments,
  bodySizeLimit,
  isComment,
  postId,
  articleId,
  isPinned,
  onPress = () => null,
  withImage = false,
  collapsedByDefault = false,
  goBackOnDelete = false,
  displayLastComment = false,
  groupId,
  isMarketplace = false,
  customNameStyle,
  canEdit,
  canInteract,
  showComments = true,
  showReactions = true,
  onPressComment,
  onOptionsPress,
  hideMenuOptions,
  onReactionPress,
  onCommentReactionPress,
  isArchived,
}: PostProps) {
  const {t} = useTranslation();
  const dispatch = useDispatch();
  const navigation = useNavigation();
  const {theme, iconSizes} = useTheme();
  const [textShown, setTextShown] = useState(false);
  const [showCollapsedMedia, setShowCollapsedMedia] = useState(false);
  const {userId, canChat, allowCreateChats, userCanDeleteMarketplacePosts} =
    useAppSelector(
      ({user, instance}) => ({
        userId: user.id,
        canChat: user.permissions.VIEW_REGULAR_CHATS,
        allowCreateChats: instance.allowCreateChats,
        userCanDeleteMarketplacePosts:
          user.permissions.MANAGE_MARKETPLACE_POSTS,
      }),
      shallowEqual,
    );
  const isStreaming =
    (post as PostType)?.stream?.status === PostStreamStatus.Live;
  const isStreamEnded =
    (post as PostType)?.stream?.status === PostStreamStatus.Ended;
  const isStreamPost = (post as PostType)?.stream;
  const avatarBorderVariant: AvatarBorderVariant = isStreaming
    ? 'live'
    : 'none';
  const {initializeChat, isLoading: isInitializingChat} = useInitializeChat();

  const {
    publicationDatetime,
    body,
    createdAt,
    user,
    hasBeenSegmented,
    reactions,
    price,
    currencyCode,
    currencySymbol,
    parentId,
    bodyHtml,
    isExternal,
  } = post as FullPost;
  const authorName = getCompleteName(user);
  const isOwner = userId === user.id;
  const bodyLimit = collapsedByDefault
    ? COLLAPSED_POST_BODY_LIMIT
    : isComment
    ? COMMENT_BODY_LIMIT
    : POST_BODY_LIMIT;
  const croppedBody = useMemo(() => {
    if (!body) {
      return '';
    }
    if (
      !bodySizeLimit ||
      textShown ||
      showCollapsedMedia ||
      body.length < bodyLimit
    ) {
      return body;
    }
    const shortenedBody = body.slice(0, bodyLimit);
    const lastIndex = shortenedBody.lastIndexOf(' ');
    return shortenedBody.substring(0, lastIndex);
  }, [body, bodySizeLimit, showCollapsedMedia, textShown, bodyLimit]);
  const truncatedHtml = useMemo(
    () => truncateHtml(bodyHtml, bodyLimit, 4),
    [bodyHtml, bodyLimit],
  );
  const postGroupTitle = (post as PostType).group?.title;
  const isGroupPostInFeed = !!postGroupTitle;
  const showMenuOptions =
    onOptionsPress ||
    (!hideMenuOptions &&
      !isGroupPostInFeed &&
      (isOwner ||
        (isMarketplace && userCanDeleteMarketplacePosts) ||
        (isComment ? canManageComments : canManagePosts)));
  const normalBodyLimit = isComment ? COMMENT_BODY_LIMIT : POST_BODY_LIMIT;
  const commentableType = useMemo(
    () =>
      parentId
        ? CommentableType.COMMENT_THREAD
        : groupId
        ? CommentableType.GROUP_POST
        : articleId
        ? CommentableType.ARTICLE
        : isMarketplace
        ? CommentableType.MARKETPLACE
        : CommentableType.POST,
    [articleId, groupId, isMarketplace, parentId],
  );

  const navigateToEditScreen = useCallback(async () => {
    const completePost =
      isComment || !!groupId
        ? post
        : await (isMarketplace
            ? getMarketplacePost(post.id)
            : getPost(post.id));
    await wait(WAITING_TIME);
    if (completePost) {
      const postToEdit = completePost.attachments?.some(
        a => typeof (a as Attachment).position !== 'number',
      )
        ? {
            ...completePost,
            attachments: completePost.attachments.map((item, position) => ({
              ...item,
              position,
            })),
          }
        : completePost;
      if (isComment) {
        dispatch(setCommentToEdit(postToEdit as Comment));
      } else if (groupId) {
        navigation.navigate(Screens.PUBLISH_GROUP_POST, {
          post: postToEdit as PostType,
          groupId,
        });
      } else {
        navigation.navigate(
          isMarketplace
            ? Screens.PUBLISH_MARKETPLACE_POST
            : Screens.PUBLISH_POST,
          {post: postToEdit as PostType},
        );
      }
    }
  }, [dispatch, groupId, isComment, isMarketplace, navigation, post]);

  const handleReaction = useCallback(
    (reaction: string, shouldUpdateLastComment?: boolean) => {
      const reactionData = {
        commentableType,
        postId: (articleId || postId)!,
        commentId: post.id,
        reaction,
        shouldUpdateLastComment,
        articleId,
        groupId,
        parentId,
        isMarketplace,
      };
      const reactionSmallData = {postId: post.id, reaction};
      const isReactedByUser = getIsReactionLoggedUser(post.reactions, reaction);

      if (!isComment && groupId) {
        const commonGroupReactionData = {...reactionSmallData, groupId};
        isReactedByUser
          ? removeGroupPostReaction(commonGroupReactionData)
          : addGroupPostReaction(commonGroupReactionData);
      } else if (!isComment && isMarketplace) {
        useMarketplaceStore.getState().reactToPost(reactionSmallData);
      } else {
        dispatch(
          !isReactedByUser
            ? isComment
              ? addCommentReaction(reactionData)
              : reactToPost(reactionSmallData)
            : isComment
            ? removeCommentReaction(reactionData)
            : unReactToPost(reactionSmallData),
        );
      }
    },
    [
      articleId,
      commentableType,
      dispatch,
      groupId,
      isComment,
      isMarketplace,
      parentId,
      post.id,
      post.reactions,
      postId,
    ],
  );

  const toggleNumberOfLines = useCallback(
    () =>
      collapsedByDefault
        ? setShowCollapsedMedia(prevState => !prevState)
        : setTextShown(prevState => !prevState),
    [collapsedByDefault],
  );

  const handleTagPress = useCallback(
    (targetId: number) => {
      navigation.dispatch(
        StackActions.push(Screens.PROFILE, {userId: targetId}),
      );
    },
    [navigation],
  );

  const handleChatAction = () => {
    initializeChat({
      user,
      initialMessage: t('marketplace.default_message'),
    });
  };

  const onProfileImagePress = useCallback(() => {
    !isExternal &&
      navigation.dispatch(
        StackActions.push(Screens.PROFILE, {userId: user.id}),
      );
  }, [navigation, user.id, isExternal]);

  const onGroupTitlePress = useCallback(
    (gId: number) => () => {
      navigation.dispatch(
        StackActions.push(Screens.GROUP_DETAIL, {groupId: gId}),
      );
    },
    [navigation],
  );

  return (
    <>
      <View
        style={[
          styles.postContainer,
          {backgroundColor: theme.white},
          style,
          hasBeenSegmented && {
            ...styles.withBorder,
            borderColor: theme.primaryBorder,
          },
        ]}>
        <Pressable
          style={styles.profileImageContainer}
          onPress={onProfileImagePress}>
          {user &&
            (!isComment ? (
              <View style={styles.headerContainer}>
                <Avatar
                  name={user}
                  url={withImage ? user.profilePicture : null}
                  size="md"
                  borderVariant={avatarBorderVariant}
                />
                <View style={isStreamPost && styles.headerTextContainer}>
                  <View
                    style={[
                      styles.headerText,
                      isGroupPostInFeed &&
                        !isStreamPost &&
                        styles.groupPostHeaderText,
                    ]}>
                    <Typography
                      numberOfLines={isStreamPost ? 2 : 1}
                      weight="semiBold"
                      adjustsFontSizeToFit
                      style={!isGroupPostInFeed && customNameStyle}>
                      {shortenText(
                        authorName,
                        isExternal
                          ? MAX_EXTERNAL_POST_TITLE_LENGTH
                          : isStreamPost
                          ? MAX_LIVESTREAM_POST_TITLE_LENGTH
                          : MAX_POST_TITLE_LENGTH,
                      )}
                      {isStreaming && (
                        <Typography weight="semiBold">
                          {isGroupPostInFeed
                            ? ` ${t('livestream.is_streaming')} `
                            : ` ${t('livestream.is_streaming_live')} `}
                        </Typography>
                      )}
                      {isStreamEnded && (
                        <Typography weight="semiBold">
                          {` ${t('livestream.transmitted_live')} `}
                        </Typography>
                      )}
                      {isStreamPost && isGroupPostInFeed && (
                        <Typography
                          weight="semiBold"
                          onPress={onGroupTitlePress(
                            (post as PostType).group!.id!,
                          )}
                          numberOfLines={1}
                          adjustsFontSizeToFit>
                          {shortenText(
                            `${`${t('livestream.in')} `}${postGroupTitle}`,
                            MAX_POST_TITLE_LENGTH / 2,
                          )}
                        </Typography>
                      )}
                    </Typography>
                    {isExternal && (
                      <Pill
                        variant="neutral"
                        size="sm"
                        text={t('group.external')}
                      />
                    )}
                    {isGroupPostInFeed && !isStreamPost && (
                      <>
                        <IconChevronRight
                          size={iconSizes.x4}
                          color={theme.neutralTextLighter}
                        />
                        <Pressable
                          onPress={onGroupTitlePress(
                            (post as PostType).group!.id!,
                          )}>
                          <Typography
                            weight="semiBold"
                            numberOfLines={1}
                            adjustsFontSizeToFit>
                            {shortenText(postGroupTitle, MAX_POST_TITLE_LENGTH)}
                          </Typography>
                        </Pressable>
                        {(post as PostType).group!.isMultiCompany && (
                          <IconArrowsRightLeft
                            color={theme.neutralText}
                            size={iconSizes.x4}
                          />
                        )}
                      </>
                    )}
                  </View>
                  <View style={styles.timeAgoContainer}>
                    <Typography
                      variant="xxs"
                      color={theme.neutralTextLighter}
                      numberOfLines={1}
                      adjustsFontSizeToFit>
                      {getExactTimeAgo(publicationDatetime || createdAt)}
                    </Typography>
                    {(post as PostType).isKeyUpdate && <KeyUpdateLabel />}
                  </View>
                </View>
              </View>
            ) : (
              <Text variant="subtitle1">{getCompleteName(user)}</Text>
            ))}
        </Pressable>
        {isPinned && !isMarketplace && (
          <View style={[styles.iconContainer, showMenuOptions && styles.right]}>
            <IconPinned size={iconSizes.x6} color={theme.errorGraphic} />
          </View>
        )}
        {!isArchived && showMenuOptions && (
          <PostOptions
            isComment={isComment}
            isOwner={isOwner}
            isPinned={isPinned}
            post={post as PostType}
            canEdit={canEdit}
            canManagePosts={canManagePosts}
            navigateToEditScreen={navigateToEditScreen}
            groupId={groupId}
            goBackOnDelete={goBackOnDelete}
            isMarketplace={isMarketplace}
            articleId={articleId}
            parentId={parentId}
            postId={postId}
            onOptionsPress={onOptionsPress}
          />
        )}
        {isMarketplace && typeof price === 'number' && (
          <View style={styles.priceContainer}>
            <Typography variant="m" weight="semiBold" color={theme.primary}>{`${
              currencyCode ? `${currencyCode} ${currencySymbol}` : '$'
            }${formatNumber(String(price), false)}`}</Typography>
            {allowCreateChats && canChat && !isOwner && (
              <Button
                text={t('post.contact')}
                variant="secondary"
                isLoading={isInitializingChat}
                size="sm"
                onPress={handleChatAction}
              />
            )}
          </View>
        )}
        <PostBody
          isArchived={isArchived}
          showComments={showComments}
          showReactions={showReactions}
          onPress={onPress}
          isComment={isComment}
          isOwner={isOwner}
          canInteract={canInteract}
          post={post}
          croppedBody={croppedBody}
          truncatedHtml={truncatedHtml}
          bodySizeLimit={bodySizeLimit}
          normalBodyLimit={normalBodyLimit}
          collapsedByDefault={collapsedByDefault}
          showCollapsedMedia={showCollapsedMedia}
          textShown={textShown}
          postId={postId}
          reactions={reactions}
          handleReaction={onReactionPress || handleReaction}
          toggleNumberOfLines={toggleNumberOfLines}
          displayLastComment={displayLastComment}
          isPinned={isPinned}
          canManagePosts={canManagePosts}
          navigateToEditScreen={navigateToEditScreen}
          goBackOnDelete={goBackOnDelete}
          groupId={groupId}
          isMarketplace={isMarketplace}
          articleId={articleId}
          parentId={parentId}
          onTagPress={handleTagPress}
          onPressComment={onPressComment}
          onReactionPickerPress={onReactionPress}
          onCommentReactionPress={onCommentReactionPress}
        />
      </View>
    </>
  );
}

export default memo(Post);
