import { FC } from 'react';
import { useMutation } from 'react-query';
import { useNavigate } from 'react-router-dom';

import {
  IconArchive,
  IconArrowsRightLeft,
  IconPinned,
  IconPinnedOff,
} from '@material-hu/icons/tabler';
import Stack from '@material-hu/mui/Stack/Stack';

import Button from '@material-hu/components/design-system/Buttons/Button';
import HuListItem from '@material-hu/components/design-system/List/components/ListItem';
import useSnackbar from '@material-hu/components/design-system/Snackbar';

import { logEvent } from 'src/config/logging';
import useGeneralError from 'src/hooks/useGeneralError';
import {
  cancelJoinRequest,
  joinGroup,
  pinGroup,
  unpinGroup,
} from 'src/services/groups';
import { EventName } from 'src/types/amplitude';
import {
  Group,
  GroupPrivacyPolicies,
  GroupRequestStatus,
} from 'src/types/groups';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';
import { optimisticUpdate } from 'src/utils/queries';

import {
  groupsKeys,
  groupsMutationKeys,
  invalidateAllGroupLists,
  invalidateGroupList,
  removePinnedGroup,
  removeUnpinnedGroup,
} from '../queries';
import { groupsRoutes } from '../routes';

type GroupItemProps = {
  // We should use the useGroupMember hook instead of a prop once the pinned groups implement members (now an empty array)
  userIsMember: boolean;
  group: Group;
};

const GroupItem: FC<GroupItemProps> = ({ group, userIsMember }) => {
  const { t } = useTranslation(['group']);

  const {
    id: groupId,
    icon,
    title,
    privacyPolicy,
    membersCount,
    groupRequest,
    isArchived,
    pinned,
    isMultiCompany,
  } = group;

  const isClosedGroup = privacyPolicy === GroupPrivacyPolicies.CLOSE;

  const { enqueueSnackbar } = useSnackbar();
  const showGeneralError = useGeneralError();
  const navigate = useNavigate();

  const { mutate: joinGroupMutation, isLoading: joinGroupIsLoading } =
    useMutation(() => joinGroup(groupId), {
      mutationKey: groupsMutationKeys.join(),
      onSuccess: () => {
        invalidateAllGroupLists();
        enqueueSnackbar({
          title: t(isClosedGroup ? 'join_group_pending' : 'join_group_success'),
          variant: 'success',
        });
      },
      onError: err => {
        showGeneralError(err, t('error_join_group'));
      },
    });

  const {
    mutate: cancelJoinRequestMutation,
    isLoading: cancelJoinRequestIsLoading,
  } = useMutation(() => cancelJoinRequest(groupId, groupRequest!.id), {
    mutationKey: groupsMutationKeys.join(),
    onSuccess: () => {
      logEvent(EventName.GROUPS_REQUESTED, { groupId });
      invalidateAllGroupLists();
      enqueueSnackbar({
        title: t('group:cancel_join_request'),
        variant: 'success',
      });
    },
    onError: err => {
      showGeneralError(err, t('group:error_cancel_request'));
    },
  });

  const { mutate: pin, isLoading: pinGroupIsLoading } = useMutation(pinGroup, {
    mutationKey: groupsMutationKeys.pin(),
    onSettled: () => {
      invalidateGroupList();
    },
    onMutate: () => {
      optimisticUpdate(
        groupId,
        groupsKeys.allUnpinnedList(),
        removeUnpinnedGroup,
      );
    },
  });

  const { mutate: unpin, isLoading: unpinGroupIsLoading } = useMutation(
    unpinGroup,
    {
      mutationKey: groupsMutationKeys.unpin(),
      onSettled: () => {
        invalidateGroupList();
      },
      onMutate: () => {
        optimisticUpdate(
          groupId,
          groupsKeys.allPinnedList(),
          removePinnedGroup,
        );
      },
    },
  );

  const pendingRequest = groupRequest?.status === GroupRequestStatus.PENDING;
  const rejectedRequest = groupRequest?.status === GroupRequestStatus.REJECTED;

  const goToGroup = () => navigate(groupsRoutes.detail(groupId));

  const handleJoin = (e: React.MouseEvent<HTMLButtonElement>) => {
    e.stopPropagation();
    pendingRequest ? cancelJoinRequestMutation() : joinGroupMutation();
  };

  const togglePin = (e: React.MouseEvent<HTMLButtonElement>) => {
    e.stopPropagation();
    if (pinned) {
      unpin(groupId);
    } else {
      pin(groupId);
    }
  };

  const getJoinButtonText = (groupRequestStatus?: GroupRequestStatus) => {
    if (!groupRequestStatus) {
      return 'group:join_web';
    }

    switch (groupRequestStatus) {
      case GroupRequestStatus.REJECTED:
        return 'group:request_rejected';
      case GroupRequestStatus.PENDING:
        return 'group:cancel_request';
      case GroupRequestStatus.ACCEPTED:
        return '';
    }
  };

  return (
    <HuListItem
      key={groupId}
      onClick={goToGroup}
      avatar={{
        src: icon.type !== 'EMOJI' ? icon.value : undefined,
        text: icon.type === 'EMOJI' ? icon.value : undefined,
        alt: title,
        variant: 'square',
      }}
      text={{
        title: (
          <Stack
            direction="row"
            spacing={1}
            alignItems="center"
          >
            <span>{title}</span>
            {isArchived && (
              <Stack
                sx={{
                  color: th => th.palette.new.text.feedback.warning,
                }}
              >
                <IconArchive size={16} />
              </Stack>
            )}
          </Stack>
        ),
        description: (
          <Stack
            sx={{
              gap: 1,
              flexDirection: 'row',
              alignItems: 'center',
              justifyItems: 'center',
              textAlign: 'center',
            }}
          >
            {isMultiCompany ? (
              <>
                <Stack
                  sx={{
                    color: theme => theme.palette.new.text.neutral.default,
                  }}
                >
                  <IconArrowsRightLeft size={16} />
                </Stack>
                <span>{t('group:multi_company')}</span>
              </>
            ) : null}
            {t(`group:groups_group_title_${privacyPolicy.toLowerCase()}`)}
            <span>•</span>
            {t('group:member', { count: membersCount })}
          </Stack>
        ),
      }}
      sideContent={
        <>
          {!userIsMember ? (
            <Button
              sx={theme => ({
                backgroundColor: pendingRequest
                  ? theme.palette.new.background.elements.brand
                  : undefined,
              })}
              variant={pendingRequest ? 'secondary' : 'tertiary-filled'}
              loading={joinGroupIsLoading || cancelJoinRequestIsLoading}
              disabled={rejectedRequest}
              onClick={handleJoin}
            >
              {t(getJoinButtonText(groupRequest?.status))}
            </Button>
          ) : (
            !isArchived && (
              <Button
                loading={pinGroupIsLoading || unpinGroupIsLoading}
                sx={theme => ({
                  backgroundColor: pinned
                    ? theme.palette.new.background.elements.brand
                    : undefined,
                  gap: 1,
                })}
                variant={pinned ? 'secondary' : 'tertiary-filled'}
                onClick={togglePin}
              >
                {!pinGroupIsLoading && !unpinGroupIsLoading && (
                  <>
                    {pinned ? (
                      <IconPinnedOff size={16} />
                    ) : (
                      <IconPinned size={16} />
                    )}
                  </>
                )}
                {pinned ? t('group:unpin') : t('group:pin')}
              </Button>
            )
          )}
        </>
      }
      slotProps={{
        container: {
          sx: { px: 3, py: 2 },
        },
        avatar: {
          sx: {
            padding: '10px',
            mr: 0.5,
          },
        },
      }}
    />
  );
};

export default GroupItem;
