import { type FC, useEffect } from 'react';
import { useMutation } from 'react-query';
import { useNavigate } from 'react-router';

import { IconArrowLeft, IconLink } from '@material-hu/icons/tabler';
import Box from '@material-hu/mui/Box';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import HTMLBody from '@material-hu/components/composed-components/HTMLBody';
import Button from '@material-hu/components/design-system/Buttons/Button';
import Pills from '@material-hu/components/design-system/Pills';
import useSnackbar from '@material-hu/components/design-system/Snackbar';

import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useAuth } from 'src/contexts/JWTContext';
import { useSocket } from 'src/contexts/SocketContext';
import useCopyUrl from 'src/hooks/useCopyUrl';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import usePermissions from 'src/hooks/usePermissions';
import useTimeInScreen from 'src/hooks/useTimeInScreen';
import ArticleChildren from 'src/pages/dashboard/libraries/components/ArticleChildren';
import ArticleComments from 'src/pages/dashboard/news/components/ArticleComments';
import {
  addArticleReaction,
  getArticleReactionUsers,
  removeArticleReaction,
} from 'src/services/news';
import { type EventName } from 'src/types/amplitude';
import { type Attachment } from 'src/types/attachments';
import { DEFAULT_EMOJI } from 'src/types/feed';
import { type ArticleChild, LibraryStatus } from 'src/types/libraries';
import { type ArticleReactionSocket, type ArticleTopics } from 'src/types/news';
import { type Reaction } from 'src/types/reaction';
import { splitByTypes } from 'src/utils/attachments';
import { getEventNameArticle } from 'src/utils/feed';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';
import { UserPermissions } from 'src/utils/permissions';
import { canAddReaction } from 'src/utils/reactions';

import { AttachmentsList } from 'src/components/attachment';
import { ReactionsList } from 'src/components/dashboard/reactions';
import TimeDistance from 'src/components/time/TimeDistance';

import {
  addReactionsInArticleDetail,
  removeReactionsInArticleDetail,
} from '../queries';
import { newsRoutes } from '../routes';

const {
  CREATE_COMMENT_IN_ARTICLES,
  CAN_REACT_ARTICLES,
  CAN_REACT_CONTENT,
  CREATE_COMMENT,
} = UserPermissions;

export type ArticleDetailProps = {
  id?: number;
  title: string;
  body?: string;
  publicationDateTime?: string;
  coverPicture: string;
  commentCount?: number;
  showTime?: boolean;
  eventNameAmplitude?: EventName;
  eventPropertiesAmplitude?: any;
  attachments?: Attachment[];
  isArticle?: boolean;
  children?: ArticleChild[];
  copyType: any;
  reactions?: Reaction[];
  copyRoute: string;
  topics?: ArticleTopics[];
  onDownload?: (file: Attachment) => void;
};

const ArticleDetail: FC<ArticleDetailProps> = props => {
  const {
    id,
    title,
    body,
    publicationDateTime,
    coverPicture,
    commentCount,
    eventNameAmplitude,
    eventPropertiesAmplitude,
    attachments,
    children,
    copyRoute,
    reactions,
    showTime = true,
    isArticle = true,
    topics,
    onDownload = () => null,
  } = props;

  const { hasAny: canViewComments } = usePermissions([
    CREATE_COMMENT_IN_ARTICLES,
    CREATE_COMMENT,
  ]);
  const { hasAny: canReactContent } = usePermissions([
    CAN_REACT_ARTICLES,
    CAN_REACT_CONTENT,
  ]);

  const HuGoThemeProvider = useHuGoTheme();
  const { user: loggedUser } = useAuth();
  const socket = useSocket();
  const { t } = useTranslation(['news', 'general']);
  const navigate = useNavigate();
  const { copyUrlToClipboard } = useCopyUrl();
  const { enqueueSnackbar } = useSnackbar();
  useTimeInScreen(
    getEventNameArticle(eventNameAmplitude),
    eventPropertiesAmplitude,
  );

  const addArticleReactionInCache = (reaction: ArticleReactionSocket) => {
    const { emoji, unified, userId, articleId } = reaction;

    addReactionsInArticleDetail(
      articleId,
      emoji,
      unified,
      userId === loggedUser?.id,
    );
  };

  const removeArticleReactionInCache = (
    reaction: Omit<ArticleReactionSocket, 'unified'>,
  ) => {
    const { emoji, userId, articleId } = reaction;

    removeReactionsInArticleDetail(articleId, emoji, userId === loggedUser?.id);
  };

  useEffect(() => {
    socket.listenEvent(
      EVENTS_SOCKETS.NEW_ARTICLE_REACTION,
      addArticleReactionInCache,
    );

    socket.listenEvent(
      EVENTS_SOCKETS.REMOVE_ARTICLE_REACTION,
      removeArticleReactionInCache,
    );

    return () => {
      socket.closeEvent(
        EVENTS_SOCKETS.NEW_ARTICLE_REACTION,
        addArticleReactionInCache,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.REMOVE_ARTICLE_REACTION,
        removeArticleReactionInCache,
      );
    };
  }, [socket, removeArticleReactionInCache, addArticleReactionInCache]);

  const addMutation = useMutation(
    ({ emoji, unified }: { emoji: string; unified: string }) => {
      if (!loggedUser) throw new Error('Logged user not found');
      if (!id) throw new Error('Article ID not found');
      return addArticleReaction(id, emoji, unified);
    },
    {
      onMutate: ({ emoji, unified }) => {
        if (id && loggedUser) {
          addArticleReactionInCache({
            emoji,
            unified,
            userId: loggedUser.id,
            articleId: id,
          });
        }
      },
      onError: (_, { emoji }) => {
        if (id && loggedUser) {
          removeArticleReactionInCache({
            emoji,
            userId: loggedUser.id,
            articleId: id,
          });
        }
      },
    },
  );

  const removeMutation = useMutation(
    (emoji: string) => {
      if (!loggedUser) throw new Error('Logged user not found');
      if (!id) throw new Error('Article ID not found');
      return removeArticleReaction(id, emoji);
    },
    {
      onMutate: emoji => {
        if (id && loggedUser) {
          removeArticleReactionInCache({
            emoji,
            userId: loggedUser.id,
            articleId: id,
          });
        }
        return { unified: reactions?.find(r => r.emoji === emoji)?.unified };
      },
      onError: (_, emoji, context) => {
        if (id && loggedUser && context?.unified) {
          addArticleReactionInCache({
            emoji,
            unified: context.unified,
            userId: loggedUser.id,
            articleId: id,
          });
        }
      },
    },
  );

  const getReactionUsers = (
    emoji: string,
    params?: { timestamp?: string; cursor?: string },
  ) => {
    if (!id) throw new Error('Article ID not found');
    return getArticleReactionUsers(id, emoji, params?.timestamp);
  };

  const handleAddReaction = (emoji: string, unified: string) => {
    if (!reactions || !canAddReaction(reactions, emoji)) return;

    addMutation.mutate({ emoji, unified });
  };

  const handleRemoveReaction = (emoji: string) => removeMutation.mutate(emoji);

  const showComments =
    canViewComments && commentCount !== null && commentCount !== undefined;

  const handleCopyUrl = () => {
    copyUrlToClipboard(copyRoute);
    enqueueSnackbar({
      title: t('general:url_copied'),
      variant: 'success',
    });
  };

  return (
    <HuGoThemeProvider>
      {isArticle && (
        <Box
          sx={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'space-between',
            mb: 2,
          }}
        >
          <Button
            variant="secondary"
            onClick={() => navigate(newsRoutes.news())}
            startIcon={<IconArrowLeft />}
          >
            {t('GO_BACK')}
          </Button>
          <Button
            variant="secondary"
            onClick={handleCopyUrl}
            sx={{ minWidth: 'unset', p: 1 }}
          >
            <IconLink />
          </Button>
        </Box>
      )}
      <Box
        sx={theme => ({
          width: '100%',
          backgroundColor: theme.palette.new.background.layout.tertiary,
          borderRadius: theme.shape.borderRadiusL,
          pb: 2,
          border: `1px solid ${theme.palette.new.border.neutral.default}`,
        })}
      >
        <Stack
          maxWidth="md"
          sx={{ pb: 1 }}
        >
          {coverPicture && (
            <Box
              sx={{
                display: 'flex',
                justifyContent: 'center',
                aspectRatio: isArticle ? '11 / 3.5' : '11 / 3',
                '& img': {
                  borderTopLeftRadius: '16px',
                  borderTopRightRadius: '16px',
                  display: 'block',
                  objectFit: 'cover',
                  width: '100%',
                  height: '100%',
                },
              }}
            >
              <img
                src={coverPicture}
                alt=""
              />
            </Box>
          )}
          <Box sx={{ paddingX: 2, mt: 2 }}>
            <Box>
              <Typography
                component="h3"
                variant="globalM"
                fontWeight="fontWeightSemiBold"
                style={{
                  overflow: 'hidden',
                  textOverflow: 'ellipsis',
                }}
              >
                {title}
              </Typography>
            </Box>
            {showTime && isArticle && publicationDateTime && (
              <Stack sx={{ alignItems: 'flex-start' }}>
                <TimeDistance
                  date={new Date(publicationDateTime)}
                  showIcon={false}
                  typographySx={{
                    fontSize: '14px',
                    fontWeight: 'fontWeightRegular',
                  }}
                />
              </Stack>
            )}
            {!!topics?.length && (
              <Stack
                sx={{
                  flexDirection: 'row',
                  flexWrap: 'wrap',
                  gap: 1,
                  my: 1,
                }}
              >
                {topics.map(topic => (
                  <Pills
                    key={topic.id}
                    label={topic.name}
                    type="neutral"
                    size="small"
                    hasIcon={false}
                    onClick={() =>
                      navigate(newsRoutes.news(), {
                        state: { activeFilter: topic.id },
                      })
                    }
                  />
                ))}
              </Stack>
            )}
            {children && (
              <ArticleChildren
                sx={{ py: 2 }}
                articleChildren={children.filter(
                  child => child.status === LibraryStatus.ENABLED,
                )}
              />
            )}
            {body && (
              <Box sx={{ width: '100%', overflow: 'hidden' }}>
                <HTMLBody body={body} />
              </Box>
            )}
            {!!attachments?.length && (
              <Stack
                sx={{ mt: 2 }}
                id="attachments-container"
              >
                <AttachmentsList
                  {...splitByTypes(attachments)}
                  mediaListType="carousel"
                  enableOpenFile
                  onDownload={onDownload}
                  isPost
                  parentContainerId="attachments-container"
                />
              </Stack>
            )}
          </Box>
        </Stack>
        {isArticle &&
          canReactContent &&
          reactions &&
          typeof id === 'number' && (
            <Box
              sx={{
                paddingX: 2,
                paddingBottom: !showComments ? '16px' : '0px',
              }}
            >
              <ReactionsList
                id={id}
                reactions={reactions}
                defaultEmoji={DEFAULT_EMOJI}
                onAdd={handleAddReaction}
                onRemove={handleRemoveReaction}
                getReactionUsers={getReactionUsers}
                withUserList
                stackProps={{ sx: { mt: 0 } }}
              />
            </Box>
          )}
        {showComments && typeof id === 'number' && (
          <ArticleComments
            id={id}
            commentCount={commentCount}
          />
        )}
      </Box>
    </HuGoThemeProvider>
  );
};

export default ArticleDetail;
