import type React from 'react';
import { type FC, useEffect, useState } from 'react';
import { useInfiniteQuery, useMutation } from 'react-query';
import { Link } from 'react-router-dom';

import { useDebounce } from '@material-hu/hooks/useDebounce';
import { useModal } from '@material-hu/hooks/useModal';
import { IconCheck, IconInfoCircle, IconX } from '@material-hu/icons/tabler';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import Avatar from '@material-hu/components/design-system/Avatar';
import Button from '@material-hu/components/design-system/Buttons/Button';
import Dialog from '@material-hu/components/design-system/Dialog';
import Search from '@material-hu/components/design-system/Inputs/Search';
import useSnackbar from '@material-hu/components/design-system/Snackbar';
import Title from '@material-hu/components/design-system/Title';

import { logEvent } from 'src/config/logging';
import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useAuth } from 'src/contexts/JWTContext';
import { useSocket } from 'src/contexts/SocketContext';
import useRequiredParams from 'src/hooks/useRequiredParams';
import { profileRoutes } from 'src/pages/dashboard/profile/routes';
import {
  getGroupRequests,
  updateAllGroupRequests,
  updateGroupRequest,
} from 'src/services/groups';
import { EventName } from 'src/types/amplitude';
import { type GroupRequest, GroupRequestStatus } from 'src/types/groups';
import { formatDistanceToNow } from 'src/utils/date';
import { userIsOnManageGroupPage } from 'src/utils/groups';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';
import { getFullName } from 'src/utils/userUtils';

import { InfiniteList } from 'src/components/list';
import ProfilePicture from 'src/components/user/ProfilePicture';

import { groupsKeys, invalidateGroupRequests } from '../../queries';

const InvitationManagement: FC = () => {
  const { id: groupId } = useRequiredParams(['id']);
  const { t } = useTranslation(['group']);
  const [query, setQuery] = useState('');
  const debouncedQuery = useDebounce(query, 300);

  const { enqueueSnackbar } = useSnackbar();

  const socket = useSocket();
  const { user } = useAuth();

  const {
    data,
    isLoading,
    refetch,
    isSuccess,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery(
    groupsKeys.requests(groupId, { q: debouncedQuery || undefined }),
    ({ pageParam = 0 }) =>
      getGroupRequests(groupId, {
        q: debouncedQuery || undefined,
        page: pageParam,
        limit: 10,
      }),
    {
      getNextPageParam: lastPage => {
        const { page, totalPages } = lastPage.data || {};
        return page < totalPages ? page + 1 : undefined;
      },
    },
  );

  useEffect(() => {
    const refetchGroupRequests = ({
      groupId: eventGroupId,
    }: {
      groupId: string;
    }) => {
      const isOnUpdatedGroup = userIsOnManageGroupPage(eventGroupId);
      if (isOnUpdatedGroup) {
        invalidateGroupRequests(eventGroupId);
      }
    };

    socket.listenEvent(
      EVENTS_SOCKETS.ALL_GROUP_REQUESTS_STATUS_UPDATED,
      refetchGroupRequests,
    );

    socket.listenEvent(
      EVENTS_SOCKETS.GROUP_REQUEST_STATUS_UPDATED,
      refetchGroupRequests,
    );

    socket.listenEvent(
      EVENTS_SOCKETS.GROUP_REQUEST_CANCELED,
      refetchGroupRequests,
    );

    socket.listenEvent(
      EVENTS_SOCKETS.GROUP_REQUEST_CREATED,
      refetchGroupRequests,
    );

    return () => {
      socket.closeEvent(
        EVENTS_SOCKETS.ALL_GROUP_REQUESTS_STATUS_UPDATED,
        refetchGroupRequests,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_REQUEST_STATUS_UPDATED,
        refetchGroupRequests,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_REQUEST_CANCELED,
        refetchGroupRequests,
      );

      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_REQUEST_CREATED,
        refetchGroupRequests,
      );
    };
  }, [socket]);

  const { mutate: updateUserRequest } = useMutation(
    ({
      request,
      status,
    }: {
      request: GroupRequest;
      status: GroupRequestStatus;
    }) => updateGroupRequest(groupId, request.id, status),
    {
      onSuccess: (_, { status, request }) => {
        refetch();
        const eventToLog =
          status === GroupRequestStatus.ACCEPTED
            ? EventName.GROUPS_REQUEST_ACCEPTED
            : EventName.GROUPS_REQUEST_DECLINED;
        const bodyToLog =
          status === GroupRequestStatus.ACCEPTED
            ? { acceptedUserId: request.userId }
            : { declinedUserId: request.userId };
        logEvent(eventToLog, { groupId, ...bodyToLog });
        enqueueSnackbar({
          title: t('group:request_updated_success', {
            context: status.toLowerCase(),
          }),
          variant: 'success',
        });
      },
    },
  );

  const { mutate: updateAllUsersRequests } = useMutation(
    (status: GroupRequestStatus) => updateAllGroupRequests(groupId, status),
    {
      onSuccess: (_, status) => {
        refetch();
        const eventToLog =
          status === GroupRequestStatus.ACCEPTED
            ? EventName.GROUPS_REQUEST_ACCEPTED_ALL
            : EventName.GROUPS_REQUEST_DECLINED_ALL;
        logEvent(eventToLog, { groupId });
        enqueueSnackbar({
          title: t('group:all_request_updated_success', {
            context: status.toLowerCase(),
          }),
          variant: 'success',
        });
      },
    },
  );

  const requests = data?.pages.flatMap(page => page.data.items) || [];
  const isEmpty = isSuccess && !requests.length;

  const AcceptMemberModal: React.FC<{ request: GroupRequest }> = ({
    request,
  }) => (
    <Dialog
      title={t('group:accept_request_title')}
      textBody={t('group:accept_request_body')}
      primaryButtonProps={{
        children: t('group:approve'),
        onClick: () => {
          updateUserRequest({
            request,
            status: GroupRequestStatus.ACCEPTED,
          });
          closeAcceptMemberModal();
        },
      }}
      secondaryButtonProps={{
        children: t('general:cancel'),
        onClick: closeAcceptMemberModal,
      }}
      onClose={closeAcceptMemberModal}
    />
  );

  const {
    modal: acceptMemberModal,
    showModal: showAcceptMemberModal,
    closeModal: closeAcceptMemberModal,
  } = useModal(AcceptMemberModal, {
    fullWidth: true,
  });

  const RejectMemberModal: React.FC<{ request: GroupRequest }> = ({
    request,
  }) => (
    <Dialog
      title={t('group:reject_request_title')}
      textBody={t('group:reject_request_body')}
      primaryButtonProps={{
        children: t('group:reject'),
        onClick: () => {
          updateUserRequest({
            request,
            status: GroupRequestStatus.REJECTED,
          });
          closeRejectMemberModal();
        },
      }}
      secondaryButtonProps={{
        children: t('general:cancel'),
        onClick: closeRejectMemberModal,
      }}
      onClose={closeRejectMemberModal}
    />
  );

  const {
    modal: rejectMemberModal,
    showModal: showRejectMemberModal,
    closeModal: closeRejectMemberModal,
  } = useModal(RejectMemberModal, {
    fullWidth: true,
  });

  const {
    modal: acceptAllMembersModal,
    showModal: showAcceptAllMembersModal,
    closeModal: closeAcceptAllMembersModal,
  } = useModal(
    () => (
      <Dialog
        title={t('group:accept_all_request_title')}
        textBody={t('group:accept_all_request_body')}
        primaryButtonProps={{
          children: t('group:approve'),
          onClick: () => {
            updateAllUsersRequests(GroupRequestStatus.ACCEPTED);
            closeAcceptAllMembersModal();
          },
        }}
        secondaryButtonProps={{
          children: t('general:cancel'),
          onClick: closeAcceptAllMembersModal,
        }}
        onClose={closeAcceptAllMembersModal}
      />
    ),
    { fullWidth: true },
  );

  const {
    modal: rejectAllMembersModal,
    showModal: showRejectAllMembersModal,
    closeModal: closeRejectAllMembersModal,
  } = useModal(
    () => (
      <Dialog
        title={t('group:reject_all_request_title')}
        textBody={t('group:reject_all_request_body')}
        primaryButtonProps={{
          children: t('group:reject'),
          onClick: () => {
            updateAllUsersRequests(GroupRequestStatus.REJECTED);
            closeRejectAllMembersModal();
          },
        }}
        secondaryButtonProps={{
          children: t('general:cancel'),
          onClick: closeRejectAllMembersModal,
        }}
        onClose={closeRejectAllMembersModal}
      />
    ),
    { fullWidth: true },
  );

  return (
    <Stack
      sx={{
        minHeight: '600px',
        width: '100%',
      }}
    >
      {acceptMemberModal}
      {acceptAllMembersModal}
      {rejectMemberModal}
      {rejectAllMembersModal}
      <Title
        variant="L"
        title={t('group:invitation_management')}
        description={t('group:invitation_management_info')}
      />
      <Search
        value={query}
        onChange={setQuery}
        sx={{ my: 3 }}
      />
      {!isEmpty && !isLoading && (
        <Stack
          sx={{
            justifyContent: 'space-between',
            flexDirection: 'row',
            mb: 1,
            alignItems: 'center',
          }}
        >
          <Typography
            variant="globalM"
            fontWeight="fontWeightSemiBold"
          >
            {t('general:action_label')}
          </Typography>
          <Stack
            direction="row"
            gap={2}
          >
            <Button onClick={showRejectAllMembersModal}>
              {t('group:reject_all_requests')}
            </Button>
            <Button onClick={showAcceptAllMembersModal}>
              {t('group:approve_all_requests')}
            </Button>
          </Stack>
        </Stack>
      )}
      <InfiniteList
        isSuccess={isSuccess}
        isEmpty={isEmpty}
        isLoading={isLoading}
        fetchNextPage={fetchNextPage}
        hasNextPage={hasNextPage}
        isFetchingNextPage={isFetchingNextPage}
        noResultsLabel={
          <Stack
            sx={theme => ({
              alignItems: 'center',
              borderRadius: theme.shape.borderRadiusL,
              p: 5,
              border: `1px solid ${theme.palette.new.border.neutral.default}`,
              backgroundColor: theme.palette.new.background.layout.tertiary,
              mt: 2,
            })}
          >
            <Avatar
              Icon={IconInfoCircle}
              sx={{
                backgroundColor: theme =>
                  theme.palette.new.background.elements.brand,
                mb: 2,
              }}
            />
            <Typography
              variant="globalM"
              fontWeight="fontWeightSemiBold"
            >
              {t(`group:empty_requests_title`)}
            </Typography>
            <Typography variant="globalXS">
              {t(`group:empty_requests_message`)}
            </Typography>
          </Stack>
        }
      >
        {requests.map(request => (
          <Stack
            key={request.id}
            direction="row"
            gap={1}
            alignItems="center"
            sx={theme => ({
              backgroundColor: theme.palette.new.background.layout.tertiary,
              borderRadius: theme.shape.borderRadiusL,
              p: 2,
              mb: 2,
              border: `1px solid ${theme.palette.new.border.neutral.default}`,
            })}
          >
            <Link
              to={profileRoutes.profile(request.userId)}
              target="_blank"
              rel="noopener noreferrer"
              style={{ textDecoration: 'none' }}
            >
              <Stack
                direction="row"
                gap={1}
                alignItems="center"
              >
                <ProfilePicture user={request.user} />
                <Stack>
                  <Typography
                    variant="globalS"
                    fontWeight="fontWeightSemiBold"
                  >
                    {getFullName(request.user)}
                  </Typography>
                  <Typography
                    variant="globalXS"
                    sx={{
                      color: theme => theme.palette.new.text.neutral.lighter,
                    }}
                  >
                    {formatDistanceToNow(new Date(request.createdAt), user)}
                  </Typography>
                </Stack>
              </Stack>
            </Link>
            <Stack
              direction="row"
              gap={1}
              justifyContent="flex-end"
              flex={1}
            >
              <Button
                sx={{ maxWidth: '200px', width: '100%' }}
                variant="outlined"
                startIcon={<IconX />}
                onClick={() =>
                  showRejectMemberModal({
                    request,
                  })
                }
              >
                {t('group:reject')}
              </Button>
              <Button
                sx={{ maxWidth: '200px', width: '100%' }}
                variant="contained"
                startIcon={<IconCheck />}
                onClick={() =>
                  showAcceptMemberModal({
                    request,
                  })
                }
              >
                {t('group:approve')}
              </Button>
            </Stack>
          </Stack>
        ))}
      </InfiniteList>
    </Stack>
  );
};

export default InvitationManagement;
