import { FC, useRef, useState } from 'react';
import { useInfiniteQuery, useIsMutating } from 'react-query';
import { useNavigate } from 'react-router-dom';

import { useDebounce } from '@material-hu/hooks/useDebounce';
import Stack from '@material-hu/mui/Stack';

import InputSearch from '@material-hu/components/design-system/Inputs/Search';

import { SUB_MENU_WIDTH } from 'src/constants/sidebar';
import useFeatureFlag from 'src/hooks/useFeatureFlag';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import usePermissions from 'src/hooks/usePermissions';
import {
  groupsKeys,
  groupsMutationKeys,
} from 'src/pages/dashboard/groups/queries';
import { groupsRoutes } from 'src/pages/dashboard/groups/routes';
import { getGroups } from 'src/services/groups';
import { FeatureFlags } from 'src/types/featureFlags';
import { Group } from 'src/types/groups';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { UserPermissions } from 'src/utils/permissions';

import { NavGroupItem } from 'src/components/dashboard/sidebar';
import InfiniteList from 'src/components/list/InfiniteList';

import SidebarGroupsEmptyState from './SidebarGroupsEmptyState';
import SidebarGroupsHeader from './SidebarGroupsHeader';
import SidebarGroupsSubMenuSkeleton from './SidebarGroupsSubMenuSkeleton';

export type SidebarGroupsSubMenuProps = {
  onGroupClick: () => void;
};

const { VIEW_GROUPS } = UserPermissions;

const SidebarGroupsSubMenu: FC<SidebarGroupsSubMenuProps> = props => {
  const { onGroupClick } = props;
  const HuGoThemeProvider = useHuGoTheme();

  const navigate = useNavigate();

  const [groupsQuery, setGroupsQuery] = useState<string>('');

  const { t } = useLokaliseTranslation('group');

  const { hasAll: canViewGroups } = usePermissions([VIEW_GROUPS]);
  const orderByLastInteraction = useFeatureFlag(
    FeatureFlags.GROUPS_ORDER_BY_LAST_INTERACTION,
  );

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

  const debouncedQuery = useDebounce(groupsQuery);

  const {
    data: searchGroupsData,
    isLoading: isLoadingSearchGroups,
    isFetching: isFetchingSearchGroups,
    hasNextPage: searchGroupsHasNextPage,
    fetchNextPage: fetchNextSearchGroupsPage,
    isFetchingNextPage: searchGroupsFetchingNextPage,
  } = useInfiniteQuery(
    groupsKeys.list(debouncedQuery),
    ({ pageParam = 1 }) =>
      getGroups({
        page: pageParam,
        limit: 10,
        q: debouncedQuery || null,
      }),
    {
      getNextPageParam: (lastPage, pages) => {
        const { page, totalPages } = pages[pages.length - 1]?.data || {};

        return page < totalPages ? pages.length + 1 : undefined;
      },
      enabled: canViewGroups,
    },
  );

  const {
    data: groupsData,
    isFetching: isFetchingGroups,
    hasNextPage: groupsHasNextPage,
    fetchNextPage: fetchNextGroupsPage,
    isFetchingNextPage: groupsFetchingNextPage,
  } = useInfiniteQuery(
    groupsKeys.allUnpinnedList(),
    ({ pageParam = 1 }) =>
      getGroups({
        page: pageParam,
        limit: 10,
        pinned: false,
        ...(orderByLastInteraction
          ? { orderBy: 'LAST_INTERACTION', order: 'DESC_NULLS_LAST' }
          : { orderBy: 'TITLE', order: 'ASC' }),
      }),
    {
      getNextPageParam: (lastPage, pages) => {
        const { page, totalPages } = pages[pages.length - 1]?.data || {};

        return page < totalPages ? pages.length + 1 : undefined;
      },
      enabled: canViewGroups,
    },
  );

  const {
    data: pinnedGroupsData,
    isFetching: isFetchingPinnedGroups,
    hasNextPage: pinnedGroupsHasNextPage,
    fetchNextPage: fetchNextPinnedGroupsPage,
    isFetchingNextPage: pinnedGroupsFetchingNextPage,
  } = useInfiniteQuery(
    groupsKeys.allPinnedList(),
    ({ pageParam = 1 }) =>
      getGroups({
        page: pageParam,
        limit: 10,
        pinned: true,
      }),
    {
      getNextPageParam: (_lastPage, pages) => {
        const { page, totalPages } = pages[pages.length - 1]?.data || {};

        return page < totalPages ? pages.length + 1 : undefined;
      },
      enabled: canViewGroups,
    },
  );

  const isMutating = useIsMutating(groupsMutationKeys.all());

  const pinnedGroups = (pinnedGroupsData?.pages || []).flatMap(
    page => page.data.items,
  );
  const pinnedGroupsTotalPages =
    pinnedGroupsData?.pages[pinnedGroupsData?.pages.length - 1]?.data
      ?.totalPages || 0;
  const hasPinnedGroups = pinnedGroups.length > 0;

  const groups = (groupsData?.pages || []).flatMap(page => page.data.items);
  const groupsTotalPages =
    groupsData?.pages[groupsData?.pages.length - 1]?.data?.totalPages || 0;
  const hasGroups = groups.length > 0;

  const isFetchingAny = isFetchingPinnedGroups || isFetchingGroups;
  const hadGroupsRef = useRef(false);
  const prevIsFetchingRef = useRef(false);
  if (hasGroups || hasPinnedGroups) {
    hadGroupsRef.current = true;
  } else if (!isFetchingAny && prevIsFetchingRef.current && isMutating === 0) {
    hadGroupsRef.current = false;
  }
  prevIsFetchingRef.current = isFetchingAny;
  const isTransitioning =
    hadGroupsRef.current && !hasGroups && !hasPinnedGroups;

  const searchGroups = (searchGroupsData?.pages || []).flatMap(
    page => page.data.items,
  );
  const searchGroupsTotalPages =
    searchGroupsData?.pages[searchGroupsData?.pages.length - 1]?.data
      ?.totalPages;
  const hasSearchGroups = searchGroups.length > 0;

  const debouncedQueryIsEqual = debouncedQuery === groupsQuery;

  const goToGroupsMainPage = () => {
    onGroupClick();
    navigate(groupsRoutes.groups());
  };

  const goToPinnedGroupsPage = () => {
    onGroupClick();
    navigate(groupsRoutes.groupsPinned());
  };

  const renderGroup = (group: Group) => (
    <NavGroupItem
      key={group.id}
      id={group.id}
      title={group.title}
      icon={group.icon}
      unreadCount={group.unreadCount}
      onClick={onGroupClick}
      isPinned={group.pinned}
      isArchived={group.isArchived}
      isMultiCompany={group.isMultiCompany}
    />
  );

  return (
    <HuGoThemeProvider>
      <Stack
        sx={{
          py: 2,
          maxWidth: SUB_MENU_WIDTH,
          width: '100%',
          overflowY: 'hidden',
          backgroundColor: theme =>
            theme.palette.new.background.layout.tertiary,
        }}
      >
        <InputSearch
          placeholder={t('group:search_groups')}
          value={groupsQuery}
          onChange={handleSearchGroup}
          variant="custom"
          sx={{ mx: 0, mb: 2, borderRadius: '6px', px: 2 }}
        />
        <Stack
          sx={{
            overflowY: 'auto',
            mt: 1,
            px: 2,
          }}
        >
          {!groupsQuery && (
            <>
              {!isTransitioning &&
                !isFetchingAny &&
                !hasGroups &&
                !hasPinnedGroups &&
                isMutating === 0 && (
                  <>
                    <SidebarGroupsHeader
                      title={t('groups_web')}
                      goToGroupsMainPage={goToGroupsMainPage}
                    />
                    <SidebarGroupsEmptyState title={t('you_have_no_groups')} />
                  </>
                )}
              <InfiniteList
                isLoading={
                  isTransitioning ||
                  (isFetchingAny && !hasGroups && !hasPinnedGroups) ||
                  (isMutating > 0 && !hasGroups && !hasPinnedGroups)
                }
                loadingSkeleton={
                  isTransitioning ||
                  (isFetchingAny && !hasGroups && !hasPinnedGroups) ||
                  (isMutating > 0 && !hasGroups && !hasPinnedGroups)
                }
                renderSkeleton={<SidebarGroupsSubMenuSkeleton />}
                fetchNextPage={
                  hasPinnedGroups && pinnedGroupsHasNextPage
                    ? fetchNextPinnedGroupsPage
                    : fetchNextGroupsPage
                }
                isFetchingNextPage={
                  pinnedGroupsFetchingNextPage || groupsFetchingNextPage
                }
                totalPages={pinnedGroupsTotalPages + groupsTotalPages}
                isSuccess={hasPinnedGroups || hasGroups}
                isEmpty={!(hasPinnedGroups || hasGroups)}
                hasNextPage={pinnedGroupsHasNextPage || groupsHasNextPage}
              >
                {hasPinnedGroups && (
                  <SidebarGroupsHeader
                    title={t('pinned_groups_web')}
                    goToGroupsMainPage={goToPinnedGroupsPage}
                  />
                )}
                {hasPinnedGroups && pinnedGroups.map(renderGroup)}
                {hasGroups && (
                  <SidebarGroupsHeader
                    title={t('groups_web')}
                    goToGroupsMainPage={goToGroupsMainPage}
                  />
                )}
                {hasGroups && groups.map(renderGroup)}
              </InfiniteList>
            </>
          )}
          {!!groupsQuery && (
            <>
              <InfiniteList
                isLoading={isFetchingSearchGroups || !debouncedQueryIsEqual}
                loadingSkeleton={
                  isFetchingSearchGroups || !debouncedQueryIsEqual
                }
                renderSkeleton={<SidebarGroupsSubMenuSkeleton />}
                fetchNextPage={fetchNextSearchGroupsPage}
                isFetchingNextPage={searchGroupsFetchingNextPage}
                totalPages={searchGroupsTotalPages}
                isSuccess={hasSearchGroups && debouncedQueryIsEqual}
                isEmpty={!hasSearchGroups}
                hasNextPage={searchGroupsHasNextPage}
              >
                {hasSearchGroups && searchGroups.map(renderGroup)}
              </InfiniteList>
              {!isLoadingSearchGroups &&
                debouncedQueryIsEqual &&
                !hasSearchGroups && (
                  <SidebarGroupsEmptyState title={t('no_groups_found_web')} />
                )}
            </>
          )}
        </Stack>
      </Stack>
    </HuGoThemeProvider>
  );
};

export default SidebarGroupsSubMenu;
