import { useEffect } from 'react';
import { useInfiniteQuery } from 'react-query';

import Stack from '@material-hu/mui/Stack';

import StateCard from '@material-hu/components/design-system/StateCard';

import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useRequiredAuth } from 'src/contexts/JWTContext';
import { useSocket } from 'src/contexts/SocketContext';
import useGeneralError from 'src/hooks/useGeneralError';
import AcknowledgementCard from 'src/pages/dashboard/acknowledgements/components/AcknowledgementCard';
import {
  type Acknowledgement,
  type AcknowledgementReactionSocket,
  type Category,
} from 'src/pages/dashboard/acknowledgements/types';
import {
  addUserAcknowledgement,
  addUserAcknowledgementListDataReaction,
  profileKeys,
  removeUserAcknowledgement,
  removeUserAcknowledgementListDataReaction,
  setUserAcknowledgementListData,
  updateCategoryData,
} from 'src/pages/dashboard/profile/queries';
import { getUserAcknowledgementList } from 'src/services/users';
import { type UserProfile } from 'src/types/user';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { canViewAcknowledgements } from 'src/utils/profile';

import InfiniteList from 'src/components/list/InfiniteList';

type AcknowledgementsTabProps = {
  user: UserProfile;
};

export const AcknowledgementsTab = ({
  user: { id },
}: AcknowledgementsTabProps) => {
  const { t } = useLokaliseTranslation('profile');
  const socket = useSocket();
  const { user: currentUser, permissions } = useRequiredAuth();
  const showGeneralError = useGeneralError();

  const currentUserId = currentUser.id;
  const isSameUser = currentUserId === id;

  const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage } =
    useInfiniteQuery(
      profileKeys.acknowledgements.list(id),
      ({ pageParam = '' }) => getUserAcknowledgementList(id, pageParam),
      {
        getNextPageParam: lastPage =>
          lastPage.data?.length > 0
            ? lastPage.data[lastPage.data.length - 1].createdAt
            : undefined,
        onError: err =>
          showGeneralError(err, t('error_loading_acknowledgments')),
        enabled: canViewAcknowledgements(permissions),
      },
    );

  useEffect(() => {
    const addAcknowledgementReaction = (
      reaction: AcknowledgementReactionSocket,
    ) => {
      const { emoji, unified, acknowledgmentId, userId: reactorId } = reaction;

      addUserAcknowledgementListDataReaction(
        id,
        acknowledgmentId,
        emoji,
        unified,
        reactorId === currentUserId,
      );
    };

    const removeAcknowledgementReaction = (
      reaction: AcknowledgementReactionSocket,
    ) => {
      const { emoji, acknowledgmentId, userId: reactorId } = reaction;

      removeUserAcknowledgementListDataReaction(
        id,
        acknowledgmentId,
        emoji,
        reactorId === currentUserId,
      );
    };

    const onCategoryUpdated = (category: Category) => {
      updateCategoryData(id, category);
    };

    const onAcknowledgementCreated = (acknowledgement: Acknowledgement) => {
      addUserAcknowledgement(acknowledgement.acknowledged.id, acknowledgement);
    };

    const onAcknowledgementUpdated = (acknowledgement: Acknowledgement) => {
      setUserAcknowledgementListData(
        acknowledgement.acknowledged.id,
        acknowledgement.id,
        acknowledgement,
      );
    };

    const onAcknowledgementDeleted = (acknowledgement: Acknowledgement) => {
      removeUserAcknowledgement(acknowledgement);
    };

    socket.listenEvent(
      EVENTS_SOCKETS.NEW_ACKNOWLEDGMENT_REACTION,
      addAcknowledgementReaction,
    );
    socket.listenEvent(
      EVENTS_SOCKETS.REMOVE_ACKNOWLEDGMENT_REACTION,
      removeAcknowledgementReaction,
    );
    socket.listenEvent(
      EVENTS_SOCKETS.ACKNOWLEDGEMENT_CATEGORY_UPDATED,
      onCategoryUpdated,
    );
    socket.listenEvent(
      EVENTS_SOCKETS.ACKNOWLEDGEMENT_CREATED,
      onAcknowledgementCreated,
    );
    socket.listenEvent(
      EVENTS_SOCKETS.ACKNOWLEDGEMENT_UPDATED,
      onAcknowledgementUpdated,
    );
    socket.listenEvent(
      EVENTS_SOCKETS.ACKNOWLEDGEMENT_DELETED,
      onAcknowledgementDeleted,
    );

    return () => {
      socket.closeEvent(
        EVENTS_SOCKETS.NEW_ACKNOWLEDGMENT_REACTION,
        addAcknowledgementReaction,
      );
      socket.closeEvent(
        EVENTS_SOCKETS.REMOVE_ACKNOWLEDGMENT_REACTION,
        removeAcknowledgementReaction,
      );
      socket.closeEvent(
        EVENTS_SOCKETS.ACKNOWLEDGEMENT_CATEGORY_UPDATED,
        onCategoryUpdated,
      );
      socket.closeEvent(
        EVENTS_SOCKETS.ACKNOWLEDGEMENT_CREATED,
        onAcknowledgementCreated,
      );
      socket.closeEvent(
        EVENTS_SOCKETS.ACKNOWLEDGEMENT_UPDATED,
        onAcknowledgementUpdated,
      );
      socket.closeEvent(
        EVENTS_SOCKETS.ACKNOWLEDGEMENT_DELETED,
        onAcknowledgementDeleted,
      );
    };
  }, [socket, id, currentUserId]);

  const acknowledgements = data?.pages?.flatMap(page => page.data) || [];

  if (data && !acknowledgements.length) {
    return (
      <StateCard
        title={t('empty_state.title.acknowledgments')}
        description={t(
          'empty_state.description.' +
            (isSameUser ? 'acknowledgments' : 'other_user_acknowledgments'),
        )}
      />
    );
  }

  return (
    <InfiniteList
      isSuccess={!!data}
      isLoading={isLoading}
      fetchNextPage={fetchNextPage}
      hasNextPage={hasNextPage}
      isFetchingNextPage={isFetchingNextPage}
    >
      {acknowledgements.map(acknowledgement => (
        <Stack
          key={acknowledgement.id}
          sx={{
            alignItems: 'center',
            mb: 3,
            '.MuiPaper-root': { maxWidth: 500 },
          }}
        >
          <AcknowledgementCard acknowledgement={acknowledgement} />
        </Stack>
      ))}
    </InfiniteList>
  );
};

export default AcknowledgementsTab;
