/* eslint-disable react/no-unstable-nested-components */
import React, {useMemo, useState} from 'react';
import {useTranslation} from 'react-i18next';
import {useMutation} from 'react-query';
import {useNavigation} from '@react-navigation/native';
import {
  IconChartBar,
  IconClockEdit,
  IconCopy,
  IconEdit,
  IconMessage,
  IconMessageX,
  IconPinned,
  IconPinnedOff,
  IconShare3,
  IconSpeakerphone,
  IconTrash,
} from '@tabler/icons-react-native';
import {Dialog, List, ListRow} from '@components/_HuGo';
import {Typography} from '@components/_core';
import {UserPermissions} from '@interfaces/user';
import {SetState} from '@interfaces/generic';
import {Post, OptionListItem} from '@modules/post/interfaces';
import {
  pinGroupPost,
  unpinGroupPost,
  deleteGroupPost,
  changeGroupPostCommentsEnabled,
} from '@modules/group/services';
import {
  changeCommentsEnabled,
  deletePost,
  pinPost,
  unpinPost,
} from '@modules/post/services';
import {editEventPost} from '@modules/events/services';
import {
  pinPostInStore,
  removeFeedPost,
  unpinPostInStore,
} from '@modules/post/utils';
import {useEventPostsStore} from '@modules/events/store/useEventPostsStore';
import {useGroupFeedStore} from '@modules/group/store/useGroupFeedStore';
import {useFeedStore} from '@modules/post/store/useFeedStore';
import RemoveKeyUpdateDialog from '@modules/keyUpdates/screens/KeyUpdateDetails/component/RemoveKeyUpdateDialog';
import {usePermission} from '@redux/selectors';
import {showSnackbar} from '@redux/dispatchers';
import {Screens} from '@shared/constants';
import {useTheme} from '@shared/theme';
import {copyToClipboard, wait} from '@shared/utils';
import {HUMAND_URL} from '@shared/keys';
import {useCommunityFeature} from '@stores/communityFeatures';

import {PostState} from '../../interfaces';
import {parsePostAttachments} from '../../utils';
import {styles} from './styles';

interface Props {
  isOwner?: boolean;
  isPinned?: boolean;
  post: Post;
  canManagePosts?: boolean;
  navigateToEditScreen: () => void;
  groupId?: number;
  goBackOnDelete?: boolean;
  canEdit?: boolean;
  isVisible: boolean;
  setIsVisible: SetState<boolean>;
  isGroupPostInFeed?: boolean;
  showKeyUpdateOptions?: boolean;
  showCopyLinkOptions?: boolean;
  eventId?: number;
}

const keyExtractor = (item: OptionListItem) => item.text;

const MAX_PINNED_POSTS_LENGTH = 10;

export function PostOptions({
  eventId,
  isOwner,
  isPinned,
  post,
  canEdit = true,
  canManagePosts,
  navigateToEditScreen,
  groupId,
  goBackOnDelete,
  isVisible,
  setIsVisible,
  isGroupPostInFeed,
  showKeyUpdateOptions = true,
  showCopyLinkOptions = true,
}: Props) {
  const [isDeleteVisible, setIsDeleteVisible] = useState(false);
  const [isRemoveKeyUpdateVisible, setIsRemoveKeyUpdateVisible] =
    useState(false);
  const navigation = useNavigation();
  const {t} = useTranslation();
  const {theme, iconSizes} = useTheme();
  const {
    getPinnedPostsLength,
    pinPost: pinGroupPostInStore,
    unpinPost: unpinGroupPostInStore,
  } = useGroupFeedStore();
  const groupPinnedPostsLength = getPinnedPostsLength(groupId);
  const pinnedPostsLength = useFeedStore(state => state.pinnedIds.length);
  const canViewStats = useCommunityFeature('VIEW_POST_STATS');
  const canCreateKeyUpdates = usePermission(UserPermissions.CREATE_KEY_UPDATES);
  const canViewKeyUpdates = usePermission(UserPermissions.VIEW_KEY_UPDATES);
  const updateEventPost = useEventPostsStore(state => state.updatePost);
  const onChangeGroupPostCommentsEnabled = useMutation(
    changeGroupPostCommentsEnabled,
  );
  const cantPinPost =
    (groupId ? groupPinnedPostsLength : pinnedPostsLength) >=
    MAX_PINNED_POSTS_LENGTH;
  const deleteGroupPostMutation = useMutation(deleteGroupPost, {
    onSuccess: () => {
      showSnackbar({
        title: t('group.post_deleted'),
      });
    },
  });
  const deactivateEventPostMutation = useMutation(editEventPost, {
    onSuccess: (_, variables) => {
      updateEventPost(variables.eventId, variables.postId, currentPost => ({
        ...currentPost,
        commentsEnabled: variables.commentsEnabled,
      }));
    },
  });

  const openDeletePostDialog = () => {
    // wait for the prev dialog to be closed
    setTimeout(() => {
      setIsDeleteVisible(true);
    }, 600);
  };

  const openRemoveKeyUpdateDialog = () => {
    // wait for the prev dialog to be closed
    setTimeout(() => {
      setIsRemoveKeyUpdateVisible(true);
    }, 600);
  };

  const items: OptionListItem[] = useMemo(
    () =>
      [
        {
          logoComponent: () => (
            <IconCopy size={iconSizes.x6} color={theme.text.neutral.default} />
          ),
          text: t('deeplinks.copy_link'),
          onPress: () => {
            copyToClipboard(
              {
                text: groupId
                  ? `${HUMAND_URL}groups/${groupId}/post/${post.id}`
                  : `${HUMAND_URL}feed/${post.id}`,
              },
              {
                variant: 'success',
                title: t('deeplinks.copied'),
              },
            );
          },
          hide: !showCopyLinkOptions,
        },
        {
          logoComponent: () => (
            <IconShare3
              size={iconSizes.x6}
              color={theme.text.neutral.default}
            />
          ),
          text: t('post.share_post'),
          onPress: () => {
            navigation.navigate(Screens.SHARE_POST, {
              postId: post.id,
              groupId,
            });
          },
          hide: !showCopyLinkOptions,
        },
        {
          logoComponent: () =>
            post?.commentsEnabled ? (
              <IconMessageX
                size={iconSizes.x6}
                color={theme.text.neutral.default}
              />
            ) : (
              <IconMessage
                size={iconSizes.x6}
                color={theme.text.neutral.default}
              />
            ),
          text: t(
            post?.commentsEnabled
              ? 'post.disable_comments'
              : 'post.activate_comments',
          ),
          onPress: () => {
            if (groupId) {
              onChangeGroupPostCommentsEnabled.mutate({
                groupId,
                postId: post.id,
                commentsEnabled: !post?.commentsEnabled,
              });
            } else if (eventId) {
              const {multimedia, files} = parsePostAttachments(
                post.attachments,
              );
              deactivateEventPostMutation.mutate({
                eventId,
                postId: post.id,
                body: post.body || '',
                multimedia,
                files,
                commentsEnabled: !post?.commentsEnabled,
              });
            } else {
              changeCommentsEnabled({
                id: post.id,
                commentsEnabled: !post?.commentsEnabled,
              });
            }
            showSnackbar({
              title: t(
                post?.commentsEnabled
                  ? 'post.deactivated_post_comments'
                  : 'post.activated_post_comments',
              ),
              variant: 'success',
            });
          },
          hide: !isOwner || isGroupPostInFeed,
        },
        {
          logoComponent: () => (
            <IconSpeakerphone
              size={iconSizes.x6}
              color={theme.text.neutral.default}
            />
          ),
          text: t(
            post.isKeyUpdate
              ? 'post.unmark_as_key_update'
              : 'key_updates.set_as_key_update',
          ),
          onPress: () => {
            if (!post) return;
            if (post.isKeyUpdate) {
              openRemoveKeyUpdateDialog();
            } else {
              navigation.navigate(Screens.PUBLISH_KEY_UPDATE, post);
            }
          },
          hide:
            !canCreateKeyUpdates ||
            post?.hasBeenSegmented ||
            !canViewKeyUpdates ||
            !showKeyUpdateOptions,
        },
        {
          logoComponent: () =>
            isPinned ? (
              <IconPinnedOff
                size={iconSizes.x6}
                color={theme.text.neutral.default}
              />
            ) : (
              <IconPinned
                size={iconSizes.x6}
                color={theme.text.neutral.default}
              />
            ),
          text: t(isPinned ? 'post.unpin' : 'post.pin'),
          onPress: async () => {
            if (groupId) {
              const commonParams = {groupId, postId: post.id};
              if (isPinned) {
                unpinGroupPostInStore(groupId, post.id);
                await unpinGroupPost(commonParams).catch(() => {
                  pinGroupPostInStore(groupId, post.id);
                });
              } else {
                pinGroupPostInStore(groupId, post.id);
                await pinGroupPost(commonParams).catch(() => {
                  unpinGroupPostInStore(groupId, post.id);
                });
              }
            } else {
              // Optimistically pinning/unpinning post
              if (isPinned) {
                unpinPostInStore(post.id);
                await unpinPost(post.id).catch(() => pinPostInStore(post));
              } else {
                pinPostInStore(post);
                await pinPost(post.id).catch(() => unpinPostInStore(post.id));
              }
            }

            showSnackbar({
              title: t(isPinned ? 'post.unpinned_post' : 'post.pinned_post'),
              variant: 'success',
            });
          },
          hide:
            !canManagePosts || (!isPinned && cantPinPost) || isGroupPostInFeed,
        },
        {
          logoComponent: () => (
            <IconChartBar
              size={iconSizes.x6}
              color={theme.text.neutral.default}
            />
          ),
          text: t('post.analysis'),
          onPress: () => {
            navigation.navigate(Screens.INSIGHTS, {id: post.id, groupId});
          },
          hide:
            !canViewStats || isGroupPostInFeed || (!canManagePosts && !isOwner),
        },
        {
          logoComponent: () => (
            <IconClockEdit
              size={iconSizes.x6}
              color={theme.text.neutral.default}
            />
          ),
          text: t('screens.EditEndTime'),
          onPress: () => {
            navigation.navigate(Screens.EDIT_END_TIME, {
              endsAt: post.poll?.pollConfiguration.endsAt ?? null,
              postId: post.id,
              pollId: post.poll!.id,
              groupId,
            });
          },
          hide: !isOwner || !canEdit || !post.poll || isGroupPostInFeed,
        },
        {
          logoComponent: () => (
            <IconEdit size={iconSizes.x6} color={theme.text.neutral.default} />
          ),
          text: t('post.edit'),
          onPress: navigateToEditScreen,
          hide:
            !isOwner ||
            !canEdit ||
            !!post.poll?.totalAnswerCount ||
            isGroupPostInFeed,
        },
        {
          logoComponent: () => (
            <IconTrash size={iconSizes.x6} color={theme.text.neutral.default} />
          ),
          text: t('post.delete'),
          onPress: openDeletePostDialog,
          hide: (!canManagePosts && !isOwner) || isGroupPostInFeed,
        },
      ].filter(item => !item.hide),
    [
      t,
      post,
      isGroupPostInFeed,
      isOwner,
      canManagePosts,
      canCreateKeyUpdates,
      canViewKeyUpdates,
      isPinned,
      cantPinPost,
      canViewStats,
      canEdit,
      navigateToEditScreen,
      theme.text.neutral.default,
      iconSizes.x6,
      groupId,
      onChangeGroupPostCommentsEnabled,
      navigation,
      unpinGroupPostInStore,
      pinGroupPostInStore,
      showCopyLinkOptions,
      showKeyUpdateOptions,
      eventId,
      deactivateEventPostMutation,
    ],
  );

  const closeDeletePostDialog = () => {
    setIsDeleteVisible(false);
  };

  const closeRemoveKeyUpdateDialog = () => {
    setIsRemoveKeyUpdateVisible(false);
  };

  const handleDelete = async () => {
    if (post) {
      if (goBackOnDelete) {
        navigation.goBack();
        // This 'wait' is to unmount completely PostDetail component before deleting the post and avoid a bug.
        // If not unmounted, then a PostDetail useEffect will be called, which calls GET /post/:id endpoint.
        // As the id is the id of a deleted post, then backend will return an error code and an error message will be shown.
        await wait(100);
      }
      if (groupId) {
        deleteGroupPostMutation.mutate({
          groupId: groupId,
          postId: post.id!,
          isScheduled: (post as Post).state === PostState.Scheduled,
        });
      } else {
        deletePost({
          id: post.id!,
          isScheduled: (post as Post).state === PostState.Scheduled,
        });
        if (post.id) removeFeedPost(post.id);
        showSnackbar({
          title: t('post.post_deleted_success'),
          variant: 'success',
        });
      }
    }
    setIsDeleteVisible(false);
  };

  const onHide = () => {
    setIsVisible(false);
  };

  const onItemPress = (item: OptionListItem) => () => {
    setIsVisible(false);
    item.onPress();
  };

  const renderItem = ({item}: {item: OptionListItem}) => {
    return (
      <ListRow onPress={onItemPress(item)}>
        <ListRow.Avatar iconColor={item.color} Icon={item.logoComponent} />
        <Typography
          align="left"
          weight="semiBold"
          color={item.color}
          numberOfLines={1}>
          {item.text}
        </Typography>
      </ListRow>
    );
  };

  return (
    <>
      <Dialog
        title={t('post.more_options')}
        onClose={onHide}
        isVisible={isVisible}>
        <List
          scrollEnabled={false}
          data={items}
          keyExtractor={keyExtractor}
          renderItem={renderItem}
          style={styles.list}
        />
      </Dialog>
      <Dialog
        title={t('general.confirmation')}
        onClose={closeDeletePostDialog}
        isVisible={isDeleteVisible}
        footer={{
          primaryButton: {
            text: t('post.delete'),
            onPress: handleDelete,
          },
          secondaryButton: {
            text: t('general.cancel'),
            onPress: closeDeletePostDialog,
          },
        }}>
        <Typography>{t('post.confirm_delete_post')}</Typography>
      </Dialog>
      <RemoveKeyUpdateDialog
        onClose={closeRemoveKeyUpdateDialog}
        post={isRemoveKeyUpdateVisible ? post : null}
        unreads={false}
      />
    </>
  );
}
