import { FC } from 'react';

import { InfiniteData, useMutation, useQueryClient } from 'react-query';
import { useNavigate } from 'react-router-dom';

import { AxiosResponse } from 'axios';
import { useModal } from '@material-hu/hooks/useModal';
import {
  IconArchive,
  IconBell,
  IconDoorExit,
  IconDotsVertical,
  IconShield,
} from '@material-hu/icons/tabler';
import IconButton from '@material-hu/mui/IconButton/IconButton';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import HuMenuList from '@material-hu/components/composed-components/MenuList';
import HuBadge from '@material-hu/components/design-system/Badge';
import Button from '@material-hu/components/design-system/Buttons/Button';
import HuCardContainer from '@material-hu/components/design-system/CardContainer';
import useHuSnackbar from '@material-hu/components/design-system/Snackbar';

import { logEvent } from 'src/config/logging';

import useGeneralError from 'src/hooks/useGeneralError';
import useRequiredParams from 'src/hooks/useRequiredParams';
import {
  joinGroup,
  cancelJoinRequest,
  archiveGroup,
  leaveGroup,
} from 'src/services/groups';
import { EventName } from 'src/types/amplitude';
import { Group, GroupRequestStatus } from 'src/types/groups';

import { Pagination } from 'src/types/services';
import { insertIf } from 'src/utils/arrays';
import { getJoinButtonText } from 'src/utils/groups';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';

import { getPrivacyIcon } from '../constants';
import { useGroupMember } from '../GroupMemberContext';
import { useGroupHasPendingPostRequests } from '../hooks/useGroupHasPendingPostRequests';
import {
  invalidateGroup,
  invalidateAllGroupLists,
  groupsKeys,
} from '../queries';
import { groupsRoutes } from '../routes';
import { GROUP_DETAIL_PAGE_BANNER_DIMENSIONS, getNextGroupId } from '../utils';

import ArchiveGroupModal from './ArchiveGroupModal';
import { GroupCompaniesList } from './GroupCompaniesList';
import GroupsMemberSelect from './GroupMemberSelect';
import GroupMembersList from './GroupMembersList';
import GroupPostSearch from './GroupPostSearch';
import LeaveGroupModal from './LeaveGroupModal';
import useGroupNotificationsSettingsDrawer from './useGroupNotificationsSettingsDrawer';

type GroupHeaderProps = Pick<
  Group,
  | 'title'
  | 'bannerUrl'
  | 'description'
  | 'membersCount'
  | 'privacyPolicy'
  | 'groupRequest'
  | 'hasPendingRequests'
  | 'isArchived'
  | 'isMultiCompany'
>;

const GroupHeader: FC<GroupHeaderProps> = props => {
  const {
    title,
    bannerUrl,
    description,
    membersCount,
    privacyPolicy,
    groupRequest,
    hasPendingRequests,
    isArchived,
    isMultiCompany,
  } = props;

  const {
    userIsMember,
    isGroupAdmin,
    userCanSeePosts,
    isClosedGroup,
    userCanLeave,
  } = useGroupMember();
  const { id } = useRequiredParams(['id']);
  const { t } = useTranslation(['group']);
  const { enqueueSnackbar } = useHuSnackbar();
  const navigate = useNavigate();
  const showGeneralError = useGeneralError();
  const queryClient = useQueryClient();
  const {
    modal: archiveModal,
    showModal: showArchiveModal,
    closeModal: closeArchiveModal,
  } = useModal(
    () => (
      <ArchiveGroupModal
        onClose={closeArchiveModal}
        onConfirm={handleArchiveGroup}
        isArchived={isArchived || false}
        isLoading={isArchiving}
      />
    ),
    { maxWidth: 'sm', fullWidth: true },
  );

  const {
    drawer: notificationsSettingsDrawer,
    showDrawer: showNotificationsSettingsDrawer,
  } = useGroupNotificationsSettingsDrawer();

  const { data: hasPendingPostRequests } = useGroupHasPendingPostRequests(id);

  const {
    modal: leaveGroupModal,
    showModal: showLeaveGroupModal,
    closeModal: closeLeaveGroupModal,
  } = useModal(
    () => (
      <LeaveGroupModal
        onClose={closeLeaveGroupModal}
        onConfirm={handleLeaveGroup}
        privacyPolicy={privacyPolicy}
        isLoading={isLeavingGroup}
      />
    ),
    { maxWidth: 'sm', fullWidth: true },
  );

  const { mutate: joinGroupMutation, isLoading: isJoining } = useMutation(
    () => joinGroup(id),
    {
      onSuccess: () => {
        invalidateGroup(Number(id));
        enqueueSnackbar({
          title: t(isClosedGroup ? 'join_group_pending' : 'join_group_success'),
          variant: 'success',
        });
      },
      onError: err => {
        showGeneralError(err, t('error_join_group'));
      },
    },
  );

  const {
    mutate: cancelJoinRequestMutation,
    isLoading: isCancellingJoinRequest,
  } = useMutation(
    () => {
      if (!groupRequest) {
        throw new Error('Group request not found');
      }
      return cancelJoinRequest(id, groupRequest.id);
    },
    {
      onSuccess: () => {
        logEvent(EventName.GROUPS_REQUESTED, { groupId: id });
        invalidateGroup(Number(id));
        enqueueSnackbar({
          title: t('group:cancel_join_request'),
          variant: 'success',
        });
      },
      onError: err => {
        showGeneralError(err, t('group:error_cancel_request'));
      },
    },
  );

  const { mutate: archiveGroupMutation, isLoading: isArchiving } = useMutation(
    (_isArchived: boolean) => archiveGroup(id, _isArchived),
    {
      onSuccess: () => {
        invalidateGroup(Number(id));
        closeArchiveModal();
        enqueueSnackbar({
          title: t(
            isArchived
              ? 'group:group_unarchived_success'
              : 'group:group_archived_success',
          ),
          variant: 'success',
        });
      },
      onError: err => {
        showGeneralError(err, t('group:error_archive_group'));
      },
    },
  );

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

  const handleArchiveGroup = () => {
    archiveGroupMutation(!isArchived);
  };

  const handleOpenArchiveModal = () => {
    showArchiveModal();
  };

  const handleOpenLeaveGroupModal = () => {
    showLeaveGroupModal();
  };

  const { mutate: leaveGroupMutation, isLoading: isLeavingGroup } = useMutation(
    () => leaveGroup(id),
    {
      onSuccess: () => {
        invalidateGroup(Number(id));
        invalidateAllGroupLists();
        closeLeaveGroupModal();

        enqueueSnackbar({
          title: t('leave_group_success'),
          variant: 'success',
        });

        const allGroups: Group[] = [];

        const pinnedData = queryClient.getQueryData(
          groupsKeys.allPinnedList(),
        ) as InfiniteData<AxiosResponse<Pagination<Group[]>>>;
        if (pinnedData?.pages) {
          pinnedData.pages.forEach(page => {
            if (page?.data?.items) {
              allGroups.push(...page.data.items);
            }
          });
        }

        // Get unpinned groups (infinite query structure)
        const unpinnedData = queryClient.getQueryData(
          groupsKeys.allUnpinnedList(),
        ) as InfiniteData<AxiosResponse<Pagination<Group[]>>>;
        if (unpinnedData?.pages) {
          unpinnedData.pages.forEach(page => {
            if (page?.data?.items) {
              allGroups.push(...page.data.items);
            }
          });
        }

        const nextGroupId = getNextGroupId(Number(id), allGroups);
        if (nextGroupId) {
          navigate(groupsRoutes.detail(nextGroupId));
        } else {
          navigate(groupsRoutes.groups());
        }
      },
      onError: err => {
        showGeneralError(err, t('error_leave_group'));
      },
    },
  );

  const handleLeaveGroup = () => {
    leaveGroupMutation();
  };

  const canLeaveGroup = userIsMember && !isArchived && userCanLeave;

  const showBadge =
    isGroupAdmin &&
    !isArchived &&
    (hasPendingRequests || hasPendingPostRequests);

  const menuOptions = [
    ...insertIf(isGroupAdmin && !isArchived, {
      onClick: () => navigate(groupsRoutes.configuration(Number(id))),
      Icon: () => (
        <HuBadge
          variant="dot"
          color="primary"
          anchorOrigin={{ vertical: 'top', horizontal: 'left' }}
          invisible={!showBadge}
        >
          <Stack
            sx={{ color: theme => theme.palette.new.text.neutral.default }}
          >
            <IconShield />
          </Stack>
        </HuBadge>
      ),
      title: t('administrator_tools'),
    }),
    {
      onClick: () => showNotificationsSettingsDrawer(),
      Icon: () => <IconBell />,
      title: t('notifications_tools'),
    },
    ...insertIf(isGroupAdmin, {
      onClick: handleOpenArchiveModal,
      Icon: () => <IconArchive />,
      title: t(isArchived ? 'unarchive_group' : 'archive_group'),
    }),
    ...insertIf(canLeaveGroup, {
      onClick: handleOpenLeaveGroupModal,
      Icon: () => <IconDoorExit />,
      title: t('leave_group'),
    }),
  ];

  return (
    <>
      {notificationsSettingsDrawer}
      <HuCardContainer
        sx={{
          '& .MuiCardContent-root': { p: 0, m: 0 },
          m: 0,
          gap: 1,
          pb: 0,
          width: '100%',
        }}
      >
        <img
          style={{
            width: GROUP_DETAIL_PAGE_BANNER_DIMENSIONS.WIDTH,
            height: GROUP_DETAIL_PAGE_BANNER_DIMENSIONS.HEIGHT,
            objectFit: 'cover',
          }}
          src={bannerUrl}
        />
        <Stack sx={{ p: 2, gap: 1 }}>
          <Stack
            sx={{
              flexDirection: 'row',
              justifyContent: 'space-between',
            }}
          >
            <Typography
              variant="globalL"
              fontWeight="semiBold"
            >
              {title}
            </Typography>
            <Stack
              sx={{
                flexDirection: 'row',
                justifyContent: 'end',
                gap: 1,
                flex: 1,
              }}
            >
              {userCanSeePosts && <GroupPostSearch />}
              <HuBadge
                invisible={!showBadge}
                variant="dot"
                color="primary"
                sx={{
                  '.MuiBadge-dot': {
                    width: '14px',
                    height: '14px',
                    borderRadius: '14px',
                    right: '4px',
                    top: '4px',
                  },
                }}
              >
                <HuMenuList
                  options={menuOptions}
                  position="left"
                  customButton={
                    <IconButton
                      variant="secondary"
                      sx={{ py: '5px', px: '7px' }}
                    >
                      <IconDotsVertical />
                    </IconButton>
                  }
                />
              </HuBadge>
            </Stack>
          </Stack>
          <Typography variant="globalS">{description}</Typography>
          <Stack sx={{ flexDirection: 'row', justifyContent: 'space-between' }}>
            <Stack
              sx={{
                flexDirection: 'row',
                alignItems: 'center',
                gap: 0.5,
              }}
            >
              {isMultiCompany && <GroupCompaniesList />}
              {getPrivacyIcon(privacyPolicy)}
              <Typography
                variant="globalS"
                fontWeight="semiBold"
              >
                {t(`group:groups_group_title_${privacyPolicy.toLowerCase()}`)}
              </Typography>
              <Typography
                variant="globalS"
                fontWeight="semiBold"
              >
                •
              </Typography>
              <GroupMembersList
                groupTitle={title}
                membersCount={membersCount}
              />
            </Stack>
            <Stack sx={{ flexDirection: 'row', gap: 1, alignItems: 'center' }}>
              {userIsMember && !isArchived && (
                <GroupsMemberSelect privacyPolicy={privacyPolicy} />
              )}
              {!userIsMember &&
                // It will never be not-a-member and ACCEPTED. The check is only for TS type safety
                groupRequest?.status !== GroupRequestStatus.ACCEPTED && (
                  <Button
                    variant="contained"
                    onClick={() => joinGroupMutation()}
                    loading={isJoining}
                    disabled={rejectedRequest || pendingRequest}
                  >
                    {t(getJoinButtonText(groupRequest?.status))}
                  </Button>
                )}
            </Stack>
          </Stack>
          {pendingRequest && (
            <Stack
              sx={{
                p: 2,
                borderRadius: 2,
                backgroundColor: theme =>
                  theme.palette.new.background.layout.default,
                gap: 2,
              }}
            >
              <Stack>
                <Typography
                  variant="globalS"
                  fontWeight="semiBold"
                >
                  {t('pending_request')}
                </Typography>
                <Typography variant="globalXS">
                  {t('pending_request_info')}
                </Typography>
              </Stack>
              <Button
                variant="secondary"
                onClick={() => cancelJoinRequestMutation()}
                loading={isCancellingJoinRequest}
                disabled={rejectedRequest}
              >
                {t('group:cancel_request')}
              </Button>
            </Stack>
          )}
        </Stack>
        {archiveModal}
        {leaveGroupModal}
      </HuCardContainer>
    </>
  );
};

export default GroupHeader;
