import { FC, Fragment, useEffect, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { useInfiniteQuery } from 'react-query';
import { useNavigate, useSearchParams } from 'react-router-dom';

import { useDebounce } from '@material-hu/hooks/useDebounce';
import { IconUsersGroup } from '@material-hu/icons/tabler';
import Divider from '@material-hu/mui/Divider';
import Stack from '@material-hu/mui/Stack';

import Button from '@material-hu/components/design-system/Buttons/Button';
import HuChip from '@material-hu/components/design-system/Chip';
import HuSearch from '@material-hu/components/design-system/Inputs/Search';
import HuTitle from '@material-hu/components/design-system/Title';

import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useSocket } from 'src/contexts/SocketContext';
import useCustomServerTranslation from 'src/hooks/useCustomServerTranslation';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import usePermissions from 'src/hooks/usePermissions';
import { exploreGroups, getGroups } from 'src/services/groups';
import { formatTitle } from 'src/utils/helmetUtils';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { UserPermissions } from 'src/utils/permissions';

import InfiniteList from 'src/components/list/InfiniteList';
import { NoMoreResultsFooter } from 'src/components/NoMoreResultsFooter';
import { NoResultsLabel } from 'src/components/NoResultsLabel';

import GroupItem from './components/GroupItem';
import PinnedGroupsList from './components/PinnedGroupsList';
import { groupsKeys, invalidateExploreGroups } from './queries';
import { groupsRoutes } from './routes';

enum GroupsList {
  MY_GROUPS = 'MY_GROUPS',
  PINNED_GROUPS = 'PINNED_GROUPS',
  EXPLORE_GROUPS = 'EXPLORE_GROUPS',
}

const { MY_GROUPS, PINNED_GROUPS, EXPLORE_GROUPS } = GroupsList;

const Groups: FC = () => {
  const { t } = useLokaliseTranslation(['group']);
  const HuGoThemeProvider = useHuGoTheme();
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const [groupsQuery, setGroupsQuery] = useState<string>('');
  const [selectedList, setSelectedList] = useState<GroupsList>(
    searchParams.get('tab') === 'pinned' ? PINNED_GROUPS : MY_GROUPS,
  );

  useEffect(() => {
    setSelectedList(
      searchParams.get('tab') === 'pinned' ? PINNED_GROUPS : MY_GROUPS,
    );
  }, [searchParams]);
  const { hasAll: canCreateGroup } = usePermissions([
    UserPermissions.CREATE_GROUPS,
  ]);

  const title = useCustomServerTranslation({
    module: 'GROUPS',
    defaultTranslationKey: 'groups',
    namespace: 'group',
  });

  const socket = useSocket();

  const handleChange = (value: string) => setGroupsQuery(value);

  const debouncedQuery = useDebounce(groupsQuery);

  const params = {
    q: debouncedQuery || null,
    limit: 20,
    orderBy: 'TITLE',
    order: 'ASC',
  };

  const myGroups = useInfiniteQuery(
    groupsKeys.myGroups(debouncedQuery),
    ({ pageParam = 1 }) => getGroups({ ...params, page: pageParam }),
    {
      getNextPageParam: (_, pages) => {
        const { page, totalPages } = pages[pages.length - 1]?.data || {};
        return page < totalPages ? pages.length + 1 : undefined;
      },
    },
  );

  const pinnedGroups = useInfiniteQuery(
    groupsKeys.pinnedGroups(debouncedQuery),
    ({ pageParam = 1 }) =>
      getGroups({ ...params, page: pageParam, pinned: true }),
    {
      getNextPageParam: (_, pages) => {
        const { page, totalPages } = pages[pages.length - 1]?.data || {};
        return page < totalPages ? pages.length + 1 : undefined;
      },
    },
  );

  const exploredGroups = useInfiniteQuery(
    groupsKeys.exploreGroups(debouncedQuery),
    ({ pageParam = '' }) => exploreGroups({ ...params, cursor: pageParam }),
    {
      getNextPageParam: lastPage => lastPage?.data?.cursor,
    },
  );

  useEffect(() => {
    const refetchExploreGroups = () => invalidateExploreGroups();

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

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

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

    return () => {
      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_REQUEST_CANCELED,
        refetchExploreGroups,
      );

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

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

  const selectedData = {
    [MY_GROUPS]: myGroups,
    [PINNED_GROUPS]: pinnedGroups,
    [EXPLORE_GROUPS]: exploredGroups,
  }[selectedList];

  const {
    data: groupsData,
    isLoading: isLoadingGroups,
    hasNextPage: groupsHasNextPage,
    fetchNextPage: fetchNexGroupsPage,
    isFetchingNextPage: groupsFetchingNextPage,
  } = selectedData || {};

  const userIsMember = selectedList !== EXPLORE_GROUPS;
  const navigateToCreateGroup = () => {
    navigate(groupsRoutes.create());
  };

  const isEmpty = groupsData && groupsData.pages[0].data?.items?.length === 0;

  const pinnedGroupItems =
    selectedList === PINNED_GROUPS
      ? (groupsData?.pages?.flatMap(page => page.data?.items ?? []) ?? [])
      : [];

  const showNoMoreResultsFooter =
    !isEmpty &&
    !groupsHasNextPage &&
    !isLoadingGroups &&
    groupsData &&
    groupsData.pages.length > 1;

  return (
    <HuGoThemeProvider>
      <Helmet>
        <title>{formatTitle(title)}</title>
      </Helmet>
      <Stack
        sx={{
          backgroundColor: theme => theme.palette.new.background.layout.default,
          alignItems: 'center',
          pt: 3,
          pb: 8,
          minHeight: '100%',
        }}
      >
        <Stack sx={{ width: '80%', gap: 3 }}>
          <Stack
            sx={{
              flexDirection: 'row',
              justifyContent: 'space-between',
              alignItems: 'center',
            }}
          >
            <>
              <HuTitle
                variant="XL"
                title={title}
                description={t('group:module_description')}
              />
            </>
            {canCreateGroup && (
              <Button
                variant="contained"
                onClick={navigateToCreateGroup}
                startIcon={<IconUsersGroup />}
              >
                {t('group:create_group')}
              </Button>
            )}
          </Stack>
          <Stack
            sx={{
              pt: 2,
              gap: 2,
              borderRadius: 2,
              border: theme =>
                `1px solid ${theme.palette.new.border.neutral.default}`,
              backgroundColor: theme =>
                theme.palette.new.background.layout.tertiary,
            }}
          >
            <Stack sx={{ flexDirection: 'row', gap: 1, px: 2 }}>
              <HuChip
                label={t('group:my_groups')}
                isSelected={selectedList === MY_GROUPS}
                onClick={() => setSelectedList(MY_GROUPS)}
              />
              <HuChip
                label={t('group:pinned')}
                isSelected={selectedList === PINNED_GROUPS}
                onClick={() => setSelectedList(PINNED_GROUPS)}
              />
              <HuChip
                label={t('group:explore_groups')}
                isSelected={selectedList === EXPLORE_GROUPS}
                onClick={() => setSelectedList(EXPLORE_GROUPS)}
              />
            </Stack>
            <Divider />
            <Stack sx={{ px: 2 }}>
              <HuSearch
                value={groupsQuery}
                onChange={handleChange}
              />
            </Stack>
            <Stack>
              <Divider sx={{ mb: 0 }} />
              {selectedList === PINNED_GROUPS &&
              !isLoadingGroups &&
              !isEmpty ? (
                <PinnedGroupsList groups={pinnedGroupItems} />
              ) : (
                <InfiniteList
                  isSuccess={!debouncedQuery || !!groupsData}
                  isEmpty={isEmpty}
                  isLoading={isLoadingGroups}
                  fetchNextPage={fetchNexGroupsPage}
                  hasNextPage={groupsHasNextPage}
                  isFetchingNextPage={groupsFetchingNextPage}
                  sx={{ p: isLoadingGroups || isEmpty ? 6 : 0 }}
                  noResultsLabel={
                    <NoResultsLabel
                      slotProps={{
                        title: {
                          title: t('group:no_groups_to_display'),
                        },
                      }}
                    />
                  }
                >
                  {groupsData?.pages?.map((page, pageIndex) =>
                    page.data?.items?.map((group, groupIndex) => (
                      <Fragment key={group.id}>
                        {!(pageIndex === 0 && groupIndex === 0) && <Divider />}
                        <GroupItem
                          group={group}
                          userIsMember={userIsMember}
                        />
                      </Fragment>
                    )),
                  )}
                </InfiniteList>
              )}
            </Stack>
          </Stack>
        </Stack>
        {showNoMoreResultsFooter && (
          <Stack sx={{ width: '80%', mt: 1 }}>
            <NoMoreResultsFooter />
          </Stack>
        )}
      </Stack>
    </HuGoThemeProvider>
  );
};

export default Groups;
