import { FC, useMemo, useRef } from 'react';
import { useMutation } from 'react-query';

import { useDrawerV2 } from '@material-hu/hooks/useDrawerV2';
import Box from '@material-hu/mui/Box';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import { useAuth } from 'src/contexts/JWTContext';
import useGeneralError from 'src/hooks/useGeneralError';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import {
  addArticleReaction,
  getArticleReactionUsers,
  removeArticleReaction,
} from 'src/services/news';
import { DEFAULT_EMOJI } from 'src/types/feed';
import { Reaction as ReactionType } from 'src/types/reaction';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';
import { canAddReaction } from 'src/utils/reactions';

import {
  REACTION_BUTTON_HEIGHT,
  REACTION_BUTTON_WIDTH,
  ReactionAdd,
} from 'src/components/dashboard/reactions';
import { invalidateReactionUserList } from 'src/components/dashboard/reactions/queries';
import Reaction from 'src/components/dashboard/reactions/Reaction';
import ReactionTooltip from 'src/components/dashboard/reactions/ReactionTooltip';
import getReactionUsersListDrawer from 'src/components/dashboard/reactions/UsersListDrawer/getReactionUsersListDrawer';

import {
  addArticleListDataReaction,
  removeArticleListDataReaction,
} from '../queries';

const REACTIONS_DISPLAY_LIMIT = 3;

export type NewsCardReactionsProps = {
  articleId: number;
  reactions: ReactionType[];
  filter: number | null;
  searchQuery: string;
};

const NewsCardReactions: FC<NewsCardReactionsProps> = ({
  articleId,
  reactions,
  filter,
  searchQuery,
}) => {
  const HuGoThemeProvider = useHuGoTheme();
  const { user: loggedUser } = useAuth();
  const { t } = useTranslation('web_only');
  const showGeneralError = useGeneralError();
  const containerRef = useRef<HTMLDivElement>(null);

  const activeReactions = useMemo(
    () => reactions.filter(reaction => reaction.count > 0),
    [reactions],
  );

  const visibleReactions = useMemo(() => {
    if (activeReactions.length > 0) {
      return activeReactions.slice(0, REACTIONS_DISPLAY_LIMIT);
    }
    return [
      {
        emoji: DEFAULT_EMOJI.emoji,
        unified: DEFAULT_EMOJI.unified,
        count: 0,
      },
    ];
  }, [activeReactions]);

  const overflowCount = Math.max(
    activeReactions.length - REACTIONS_DISPLAY_LIMIT,
    0,
  );

  const getReactionUsers = (
    emoji: string,
    params?: { timestamp?: string; cursor?: string },
  ) => getArticleReactionUsers(articleId, emoji, params?.timestamp);

  const { drawer, showDrawer } = useDrawerV2(args =>
    getReactionUsersListDrawer({
      ...args,
      id: articleId,
      filterReactions: activeReactions,
      getReactionUsers,
      container: containerRef.current,
    }),
  );

  const addInCache = (emoji: string, unified: string) => {
    addArticleListDataReaction(
      filter,
      searchQuery,
      articleId,
      emoji,
      unified,
      true,
    );
  };

  const removeInCache = (emoji: string) => {
    removeArticleListDataReaction(filter, searchQuery, articleId, emoji, true);
  };

  const addMutation = useMutation({
    mutationFn: ({ emoji, unified }: { emoji: string; unified: string }) =>
      addArticleReaction(articleId, emoji, unified),
    onMutate: ({ emoji, unified }) => {
      if (!loggedUser) return;
      addInCache(emoji, unified);
    },
    onSuccess: (_, { emoji }) => {
      invalidateReactionUserList(articleId, emoji);
    },
    onError: (_, { emoji }) => {
      if (loggedUser) removeInCache(emoji);
    },
  });

  const removeMutation = useMutation({
    mutationFn: (emoji: string) => removeArticleReaction(articleId, emoji),
    onMutate: emoji => {
      const unified = reactions.find(r => r.emoji === emoji)?.unified;
      if (loggedUser) removeInCache(emoji);
      return { unified };
    },
    onSuccess: (_, emoji) => {
      invalidateReactionUserList(articleId, emoji);
    },
    onError: (_, emoji, context) => {
      if (loggedUser && context?.unified) {
        addInCache(emoji, context.unified);
      }
    },
  });

  const handleAdd = async (emoji: string, unified: string) => {
    if (!canAddReaction(reactions, emoji)) return;
    try {
      await addMutation.mutateAsync({ emoji, unified });
    } catch (err) {
      showGeneralError(err, t('reactions.add_reaction_error'));
    }
  };

  const handleRemove = async (emoji: string) => {
    try {
      await removeMutation.mutateAsync(emoji);
    } catch (err) {
      showGeneralError(err, t('reactions.remove_reaction_error'));
    }
  };

  return (
    <HuGoThemeProvider>
      <Box
        ref={containerRef}
        onClick={e => {
          e.stopPropagation();
          e.preventDefault();
        }}
      >
        {drawer}
        <Stack
          alignItems="center"
          gap={1}
          sx={{ flexDirection: 'row', flexWrap: 'nowrap' }}
        >
          {visibleReactions.map(reaction => (
            <ReactionTooltip
              key={reaction.emoji}
              id={articleId}
              reaction={reaction}
              getReactionUsers={getReactionUsers}
              popperProps={{ container: containerRef.current }}
            >
              <Reaction
                reaction={reaction}
                onAdd={handleAdd}
                onRemove={handleRemove}
              />
            </ReactionTooltip>
          ))}
          {overflowCount > 0 && (
            <IconButton
              onClick={showDrawer}
              size="large"
              aria-label={t('reactions.see_all')}
              sx={{
                gap: 0.5,
                py: 0.75,
                px: 1,
                height: REACTION_BUTTON_HEIGHT,
                minWidth: REACTION_BUTTON_WIDTH,
                backgroundColor: theme =>
                  theme.palette.new.background.elements.grey,
              }}
            >
              <Typography
                variant="globalXS"
                fontWeight="fontWeightSemiBold"
                component="span"
              >
                +{overflowCount}
              </Typography>
            </IconButton>
          )}
          <ReactionAdd
            onAdd={handleAdd}
            variant="button"
            buttonSize={{
              width: REACTION_BUTTON_WIDTH,
              height: REACTION_BUTTON_HEIGHT,
            }}
            tooltipProps={{
              slotProps: {
                popper: {
                  container: containerRef.current,
                },
              },
            }}
          />
        </Stack>
      </Box>
    </HuGoThemeProvider>
  );
};

export default NewsCardReactions;
