import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
import { Trans, useTranslation } from 'react-i18next';
import { Comment, useAccount, useFeed, useSubplebbit, useAccountComments } from '@plebbit/plebbit-react-hooks';
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import useCatalogFeedRows from '../../hooks/use-catalog-feed-rows';
import { useDirectories } from '../../hooks/use-directories';
import { useFilteredDirectoryAddresses } from '../../hooks/use-filtered-directory-addresses';
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
import { useFeedStateString } from '../../hooks/use-state-string';
import useTimeFilter, { timeFilterNameToSeconds } from '../../hooks/use-time-filter';
import useWindowWidth from '../../hooks/use-window-width';
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
import useFeedResetStore from '../../stores/use-feed-reset-store';
import useSortingStore from '../../stores/use-sorting-store';
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
import { getSubplebbitAddress, isDirectoryBoard } from '../../lib/utils/route-utils';
import CatalogRow from '../../components/catalog-row';
import LoadingEllipsis from '../../components/loading-ellipsis';
import ErrorDisplay from '../../components/error-display/error-display';
import styles from './catalog.module.css';
import { commentMatchesPattern } from '../../lib/utils/pattern-utils';

const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};

interface CatalogFooterProps {
  subplebbitAddresses: string[];
  hasMore: boolean;
  feedLength: number;
  combinedFeedLength: number;
  subplebbitAddressesWithNewerPosts: string[];
  onNewerPostsClick: () => void;
  isInAllView: boolean;
  isInSubscriptionsView: boolean;
  showMorePostsSuggestion: boolean;
  weeklyFeedLength: number;
  monthlyFeedLength: number;
  yearlyFeedLength: number;
  boardPath: string | undefined;
  currentTimeFilterName: string | undefined;
}

// Defined outside Catalog to preserve component identity across renders (Virtuoso optimization)
// The useFeedStateString hook is called here instead of in Catalog to isolate re-renders
// caused by backend IPFS state changes to just this footer component
const CatalogFooter = ({
  subplebbitAddresses,
  hasMore,
  feedLength,
  combinedFeedLength,
  subplebbitAddressesWithNewerPosts,
  onNewerPostsClick,
  isInAllView,
  isInSubscriptionsView,
  showMorePostsSuggestion,
  weeklyFeedLength,
  monthlyFeedLength,
  yearlyFeedLength,
  boardPath,
  currentTimeFilterName,
}: CatalogFooterProps) => {
  const { t } = useTranslation();

  const loadingStateString =
    useFeedStateString(subplebbitAddresses) ||
    (feedLength === 0 && !(weeklyFeedLength > feedLength || monthlyFeedLength > feedLength || yearlyFeedLength > monthlyFeedLength))
      ? t('loading_feed')
      : t('looking_for_more_posts');

  let footerContent;
  if (feedLength === 0) {
    if (combinedFeedLength === 0) {
      footerContent = t('no_threads');
    }
  }
  if (hasMore || (subplebbitAddresses && subplebbitAddresses.length === 0)) {
    footerContent = (
      <>
        {subplebbitAddressesWithNewerPosts.length > 0 ? (
          <div className={styles.stateString}>
            <Trans
              i18nKey='newer_threads_available'
              components={{
                1: <span className={styles.newerPostsButton} onClick={onNewerPostsClick} />,
              }}
            />
          </div>
        ) : (
          (isInAllView || isInSubscriptionsView) &&
          showMorePostsSuggestion &&
          (monthlyFeedLength > feedLength || yearlyFeedLength > monthlyFeedLength) &&
          (weeklyFeedLength > feedLength ? (
            <div className={styles.stateString}>
              <Trans
                i18nKey='more_threads_last_week'
                values={{ currentTimeFilterName, count: feedLength }}
                components={{
                  1: <Link to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subs/catalog' : `/${boardPath}/catalog`) + '/1w'} />,
                }}
              />
            </div>
          ) : monthlyFeedLength > feedLength ? (
            <div className={styles.stateString}>
              <Trans
                i18nKey='more_threads_last_month'
                values={{ currentTimeFilterName, count: feedLength }}
                components={{
                  1: <Link to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subs/catalog' : `/${boardPath}/catalog`) + '/1m'} />,
                }}
              />
            </div>
          ) : (
            <div className={styles.stateString}>
              <Trans
                i18nKey='more_threads_last_year'
                values={{ currentTimeFilterName, count: feedLength }}
                components={{
                  1: <Link to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subs/catalog' : `/${boardPath}/catalog`) + '/1y'} />,
                }}
              />
            </div>
          ))
        )}
        <div className={styles.stateString}>
          <LoadingEllipsis string={loadingStateString} />
        </div>
      </>
    );
  }
  return <div className={styles.footer}>{footerContent}</div>;
};

// Separate component for the loading state when there's no feed
// This also calls useFeedStateString internally to isolate re-renders
interface CatalogLoadingProps {
  subplebbitAddresses: string[];
  hasMore: boolean;
  feedLength: number;
  weeklyFeedLength: number;
  monthlyFeedLength: number;
  yearlyFeedLength: number;
  state: string | undefined;
  subscriptionsLength: number;
  combinedFeedLength: number;
  error: Error | undefined;
}

const CatalogLoading = ({
  subplebbitAddresses,
  hasMore,
  feedLength,
  weeklyFeedLength,
  monthlyFeedLength,
  yearlyFeedLength,
  state,
  subscriptionsLength,
  combinedFeedLength,
  error,
}: CatalogLoadingProps) => {
  const { t } = useTranslation();

  const rawFeedStateString = useFeedStateString(subplebbitAddresses);
  const loadingStateString =
    rawFeedStateString || (feedLength === 0 && !(weeklyFeedLength > feedLength || monthlyFeedLength > feedLength || yearlyFeedLength > monthlyFeedLength))
      ? t('loading_feed')
      : t('looking_for_more_posts');

  return (
    <div className={styles.stateString}>
      {state === 'failed' ? (
        <span className='red'>{state}</span>
      ) : subscriptionsLength === 0 ? (
        <span className='red'>{t('not_subscribed_to_any_board')}</span>
      ) : !hasMore && combinedFeedLength === 0 ? (
        t('no_threads')
      ) : (
        hasMore && <LoadingEllipsis string={loadingStateString} />
      )}
      <ErrorDisplay error={error} />
    </div>
  );
};

const createContentFilter = (
  filterItems: { text: string; enabled: boolean; count: number; filteredCids: Set<string>; hide: boolean; top: boolean; color?: string }[],
  subplebbitAddress: string,
  onFilterMatch?: (filterIndex: number, cid: string, subplebbitAddress: string) => void,
) => {
  // Create a unique key based on the enabled filter items
  const enabledFilters = filterItems.filter((item) => item.enabled && item.text.trim() !== '');
  const filterKey =
    enabledFilters.length > 0
      ? `content-filter-${enabledFilters.map((item) => `${item.text}-${item.hide ? 'hide' : ''}-${item.top ? 'top' : ''}`).join('-')}`
      : 'no-content-filter';

  return {
    filter: (comment: Comment) => {
      if (!comment?.cid) return true;

      if (enabledFilters.length === 0) return true;

      // Check if any enabled filter matches the content
      for (let i = 0; i < enabledFilters.length; i++) {
        const item = enabledFilters[i];
        const pattern = item.text;

        if (commentMatchesPattern(comment, pattern)) {
          // Find the original filter index to increment count
          const filterIndex = filterItems.findIndex((f) => f.text === item.text && f.enabled);
          if (filterIndex !== -1) {
            if (onFilterMatch) {
              onFilterMatch(filterIndex, comment.cid, subplebbitAddress);
            } else {
              // Fallback to the store method if no callback provided
              useCatalogFiltersStore.getState().incrementFilterCount(filterIndex, comment.cid, subplebbitAddress);
            }

            // If the filter has a color, track it in the matchedFilters map
            if (item.color) {
              useCatalogFiltersStore.getState().setMatchedFilter(comment.cid, item.color);
            }
          }

          // If this filter is set to hide, filter out the comment
          if (item.hide) {
            return false;
          }

          // If this filter is set to top, we'll handle it separately in the component
          // (we don't filter it out here)
        }
      }

      return true;
    },
    key: filterKey,
  };
};

const createImageFilter = (showTextOnlyThreads: boolean) => {
  return {
    filter: (comment: Comment) => {
      if (showTextOnlyThreads) return true;

      const { link, linkHeight, linkWidth, thumbnailUrl } = comment || {};
      const hasThumbnail = getHasThumbnail(getCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight), link);

      return hasThumbnail;
    },
    key: showTextOnlyThreads ? 'no-image-filter' : 'threads-with-images-only',
  };
};

const createCombinedFilter = (
  showTextOnlyThreads: boolean,
  filterItems: { text: string; enabled: boolean; count: number; filteredCids: Set<string>; hide: boolean; top: boolean; color?: string }[],
  searchText: string,
  subplebbitAddress: string,
  onFilterMatch?: (filterIndex: number, cid: string, subplebbitAddress: string) => void,
) => {
  const imageFilter = createImageFilter(showTextOnlyThreads);
  const contentFilter = createContentFilter(filterItems, subplebbitAddress, onFilterMatch);

  const searchFilter = {
    filter: (comment: Comment) => {
      if (!searchText.trim()) return true;
      return commentMatchesPattern(comment, searchText);
    },
    key: searchText ? `search-filter-${searchText}` : 'no-search-filter',
  };

  return {
    filter: (comment: Comment) => {
      if (!imageFilter.filter(comment)) return false;
      if (!contentFilter.filter(comment)) return false;
      if (!searchFilter.filter(comment)) return false;

      return true;
    },
    key: `${imageFilter.key}-${contentFilter.key}-${searchFilter.key}`,
  };
};

export interface CatalogProps {
  feedCacheKey?: string;
  viewType?: 'all' | 'subs' | 'mod' | 'board';
  boardIdentifier?: string;
  timeFilterNameFromCache?: string;
  isVisible?: boolean;
}

const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, timeFilterNameFromCache, isVisible = true }: CatalogProps) => {
  const { t } = useTranslation();
  const location = useLocation();
  const params = useParams();

  const isInAllView = viewType ? viewType === 'all' : false;
  const isInSubscriptionsView = viewType ? viewType === 'subs' : false;

  const directories = useDirectories();
  const resolvedAddressFromUrl = useResolvedSubplebbitAddress();
  const subplebbitAddress = useMemo(() => {
    if (boardIdentifierProp) {
      return getSubplebbitAddress(boardIdentifierProp, directories);
    }
    return resolvedAddressFromUrl;
  }, [boardIdentifierProp, directories, resolvedAddressFromUrl]);

  const boardPath = useBoardPath(subplebbitAddress);
  const { showTextOnlyThreads, filterItems, searchText, clearMatchedFilters } = useCatalogFiltersStore();

  const account = useAccount();
  const subscriptions = account?.subscriptions;
  const filteredDirectoryAddresses = useFilteredDirectoryAddresses();

  const subplebbitAddresses = useMemo(() => {
    if (isInAllView) {
      return filteredDirectoryAddresses;
    }
    if (isInSubscriptionsView) {
      return (subscriptions || []).filter(Boolean); // Filter out any undefined/null values
    }
    // Only include subplebbitAddress if it's defined
    return subplebbitAddress ? [subplebbitAddress] : [];
  }, [isInAllView, isInSubscriptionsView, subplebbitAddress, filteredDirectoryAddresses, subscriptions]);

  const { imageSize } = useCatalogStyleStore();
  const columnWidth = imageSize === 'Large' ? 270 : 180;

  const columnCount = Math.floor(useWindowWidth() / columnWidth);
  const postsPerPage = columnCount <= 2 ? 10 : columnCount === 3 ? 15 : columnCount === 4 ? 20 : 25;

  const { timeFilterSeconds: timeFilterSecondsFromHook, timeFilterName: timeFilterNameFromHook } = useTimeFilter();
  const { sortType } = useSortingStore();
  const timeFilterName = timeFilterNameFromCache || timeFilterNameFromHook;
  const timeFilterSeconds = timeFilterNameFromCache ? timeFilterNameToSeconds(timeFilterNameFromCache) : timeFilterSecondsFromHook;

  // Create a stable callback for filter matching
  const handleFilterMatch = useCallback((filterIndex: number, cid: string, subplebbitAddress: string) => {
    useCatalogFiltersStore.getState().incrementFilterCount(filterIndex, cid, subplebbitAddress);
  }, []);

  // Set the current subplebbit address
  useEffect(() => {
    useCatalogFiltersStore.getState().setCurrentSubplebbitAddress(subplebbitAddress || null);
    return () => {
      useCatalogFiltersStore.getState().setCurrentSubplebbitAddress(null);
    };
  }, [subplebbitAddress]);

  const feedOptions = useMemo(() => {
    const options: any = {
      subplebbitAddresses,
      sortType,
      postsPerPage: isInAllView || isInSubscriptionsView ? 10 : postsPerPage,
      filter: createCombinedFilter(showTextOnlyThreads, filterItems, searchText, subplebbitAddress || 'all', handleFilterMatch),
    };

    if (isInAllView || isInSubscriptionsView) {
      options.newerThan = timeFilterSeconds;
    }

    return options;
  }, [
    subplebbitAddresses,
    sortType,
    isInAllView,
    isInSubscriptionsView,
    postsPerPage,
    timeFilterSeconds,
    showTextOnlyThreads,
    filterItems,
    searchText,
    subplebbitAddress,
    handleFilterMatch,
  ]);

  const { feed, hasMore, loadMore, reset, subplebbitAddressesWithNewerPosts } = useFeed(feedOptions);
  const { accountComments } = useAccountComments();

  const resetTriggeredRef = useRef(false);

  // show account comments instantly in the feed once published (cid defined), instead of waiting for the feed to update
  const filteredComments = useMemo(
    () =>
      accountComments.filter((comment) => {
        const { cid, deleted, link, linkHeight, linkWidth, postCid, removed, state, thumbnailUrl, timestamp } = comment || {};

        // Basic filtering conditions
        const basicConditions =
          !deleted &&
          !removed &&
          timestamp > Date.now() / 1000 - 60 * 60 &&
          state === 'succeeded' &&
          cid &&
          (showTextOnlyThreads ? getHasThumbnail(getCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight), comment?.link) : true) &&
          cid === postCid &&
          comment?.subplebbitAddress === subplebbitAddress &&
          !feed.some((post) => post.cid === cid);

        // If search is active, also check search conditions
        if (basicConditions && searchText.trim()) {
          const titleLower = comment?.title?.toLowerCase() || '';
          const contentLower = comment?.content?.toLowerCase() || '';
          const searchPattern = searchText.toLowerCase();

          return titleLower.includes(searchPattern) || contentLower.includes(searchPattern);
        }

        return basicConditions;
      }),
    [accountComments, subplebbitAddress, feed, showTextOnlyThreads, searchText],
  );

  // show newest account comment at the top of the feed but after pinned posts
  const combinedFeed = useMemo(() => {
    const newFeed = [...feed];
    const lastPinnedIndex = newFeed.map((post) => post.pinned).lastIndexOf(true);
    if (filteredComments.length > 0) {
      newFeed.splice(lastPinnedIndex + 1, 0, ...filteredComments);
    }
    return newFeed;
  }, [feed, filteredComments]);

  useEffect(() => {
    if (filteredComments.length > 0 && !resetTriggeredRef.current) {
      reset();
      resetTriggeredRef.current = true;
    }
  }, [filteredComments, reset]);

  const handleNewerPostsButtonClick = () => {
    window.scrollTo({ top: 0, left: 0 });
    setTimeout(() => {
      reset();
    }, 300);
  };

  // suggest the user to change time filter if there aren't enough posts
  const { feed: weeklyFeed } = useFeed({
    subplebbitAddresses,
    sortType,
    newerThan: 60 * 60 * 24 * 7,
    filter: createCombinedFilter(showTextOnlyThreads, filterItems, searchText, subplebbitAddress || 'all', handleFilterMatch),
  });

  const { feed: monthlyFeed } = useFeed({
    subplebbitAddresses,
    sortType,
    newerThan: 60 * 60 * 24 * 30,
    filter: createCombinedFilter(showTextOnlyThreads, filterItems, searchText, subplebbitAddress || 'all', handleFilterMatch),
  });

  const { feed: yearlyFeed } = useFeed({
    subplebbitAddresses,
    sortType,
    newerThan: 60 * 60 * 24 * 365,
    filter: createCombinedFilter(showTextOnlyThreads, filterItems, searchText, subplebbitAddress || 'all', handleFilterMatch),
  });

  const [showMorePostsSuggestion, setShowMorePostsSuggestion] = useState(false);
  useEffect(() => {
    const timer = setTimeout(() => {
      setShowMorePostsSuggestion(true);
    }, 5000);

    return () => clearTimeout(timer);
  }, []);

  const setResetFunction = useFeedResetStore((state) => state.setResetFunction);
  useEffect(() => {
    if (isVisible) {
      setResetFunction(reset);
    }
  }, [reset, setResetFunction, isVisible]);

  const subplebbit = useSubplebbit({ subplebbitAddress });
  const { error, shortAddress, state, title } = subplebbit || {};
  const feedLength = feed.length;
  const weeklyFeedLength = weeklyFeed.length;
  const monthlyFeedLength = monthlyFeed.length;
  const yearlyFeedLength = yearlyFeed.length;

  const currentTimeFilterName = timeFilterName || params?.timeFilterName;

  // Memoize footer component to preserve identity across renders (Virtuoso optimization)
  // Note: useFeedStateString is called inside CatalogFooter to isolate re-renders from backend state changes
  const footerComponents = useMemo(
    () => ({
      Footer: () => (
        <CatalogFooter
          subplebbitAddresses={subplebbitAddresses}
          hasMore={hasMore}
          feedLength={feedLength}
          combinedFeedLength={combinedFeed.length}
          subplebbitAddressesWithNewerPosts={subplebbitAddressesWithNewerPosts}
          onNewerPostsClick={handleNewerPostsButtonClick}
          isInAllView={isInAllView}
          isInSubscriptionsView={isInSubscriptionsView}
          showMorePostsSuggestion={showMorePostsSuggestion}
          weeklyFeedLength={weeklyFeedLength}
          monthlyFeedLength={monthlyFeedLength}
          yearlyFeedLength={yearlyFeedLength}
          boardPath={boardPath}
          currentTimeFilterName={currentTimeFilterName}
        />
      ),
    }),
    [
      subplebbitAddresses,
      hasMore,
      feedLength,
      combinedFeed.length,
      subplebbitAddressesWithNewerPosts,
      handleNewerPostsButtonClick,
      isInAllView,
      isInSubscriptionsView,
      showMorePostsSuggestion,
      weeklyFeedLength,
      monthlyFeedLength,
      yearlyFeedLength,
      boardPath,
      currentTimeFilterName,
    ],
  );

  const isFeedLoaded = feed.length > 0 || state === 'failed';

  // Process the feed to move "top" posts to the top
  const processedFeed = useMemo(() => {
    if (!combinedFeed || combinedFeed.length === 0) return combinedFeed;

    const enabledTopFilters = filterItems.filter((item) => item.enabled && item.text.trim() !== '' && item.top);
    if (enabledTopFilters.length === 0) return combinedFeed;

    // Separate posts that match "top" filters
    const topPosts: Comment[] = [];
    const regularPosts: Comment[] = [];

    combinedFeed.forEach((comment) => {
      if (!comment) return;

      let isTop = false;
      for (const filter of enabledTopFilters) {
        if (commentMatchesPattern(comment, filter.text)) {
          isTop = true;
          break;
        }
      }

      if (isTop) {
        topPosts.push(comment);
      } else {
        regularPosts.push(comment);
      }
    });

    // Return top posts followed by regular posts
    return [...topPosts, ...regularPosts];
  }, [combinedFeed, filterItems]);

  const rows = useCatalogFeedRows(columnCount, processedFeed, isFeedLoaded, subplebbit);

  const virtuosoRef = useRef<VirtuosoHandle | null>(null);
  const virtuosoStateKey = feedCacheKey ? `${feedCacheKey}-${sortType}-${timeFilterSeconds}` : `${location.pathname}-${sortType}-${timeFilterSeconds}-catalog`;
  const navigationType = useNavigationType();

  const hasBeenVisibleRef = useRef(false);
  useEffect(() => {
    if (isVisible && !hasBeenVisibleRef.current) {
      hasBeenVisibleRef.current = true;
      if (navigationType !== 'POP') {
        window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
      }
    }
  }, [isVisible, navigationType]);

  useEffect(() => {
    if (!isVisible) return;

    const currentKey = virtuosoStateKey;
    const setLastVirtuosoState = () =>
      virtuosoRef.current?.getState((snapshot: StateSnapshot) => {
        if (snapshot?.ranges?.length) {
          lastVirtuosoStates[currentKey] = snapshot;
        }
      });
    window.addEventListener('scroll', setLastVirtuosoState);
    return () => window.removeEventListener('scroll', setLastVirtuosoState);
  }, [virtuosoStateKey, isVisible]);

  const lastVirtuosoState = navigationType === 'POP' ? lastVirtuosoStates?.[virtuosoStateKey] : undefined;

  useEffect(() => {
    if (!isVisible) return;
    const boardIdentifier = params.boardIdentifier || boardIdentifierProp;
    const isDirectory = boardIdentifier ? isDirectoryBoard(boardIdentifier, directories) : false;

    let documentTitle: string;
    if (isInAllView) {
      documentTitle = t('all');
    } else if (isInSubscriptionsView) {
      documentTitle = t('subscriptions');
    } else if (isDirectory) {
      documentTitle = `/${boardIdentifier}/`;
    } else {
      documentTitle = title ? title : shortAddress || subplebbitAddress || '';
    }
    document.title = documentTitle + ` - ${t('catalog')} - 5chan`;
  }, [title, shortAddress, subplebbitAddress, isInAllView, isInSubscriptionsView, t, isVisible, params.boardIdentifier, boardIdentifierProp, directories]);

  // Clear matched filters when component mounts or when subplebbit changes
  useEffect(() => {
    clearMatchedFilters();
    return () => {
      clearMatchedFilters();
    };
  }, [clearMatchedFilters, subplebbitAddress]);

  // Memoize filter color application to avoid redundant iterations
  useMemo(() => {
    if (combinedFeed.length > 0 && filterItems.length > 0) {
      // Clear existing matched filters
      clearMatchedFilters();

      // Apply colors to posts that match filters
      combinedFeed.forEach((comment) => {
        if (!comment?.cid) return;

        // Check each filter
        for (const item of filterItems) {
          if (item.enabled && item.text.trim() !== '' && item.color) {
            if (commentMatchesPattern(comment, item.text)) {
              useCatalogFiltersStore.getState().setMatchedFilter(comment.cid, item.color);
              break; // Use the first matching filter's color
            }
          }
        }
      });
    }
  }, [combinedFeed, filterItems, clearMatchedFilters]);

  return (
    <div className={styles.content}>
      <hr />
      <div className={styles.catalog}>
        {processedFeed?.length !== 0 ? (
          <>
            {/* Use Virtuoso for infinite scroll only when there's more content to paginate */}
            {hasMore ? (
              <Virtuoso
                increaseViewportBy={{ bottom: 1200, top: 1200 }}
                totalCount={rows?.length || 0}
                data={rows}
                itemContent={(index, row) => <CatalogRow index={index} row={row} />}
                useWindowScroll={true}
                components={footerComponents}
                endReached={loadMore}
                ref={virtuosoRef}
                restoreStateFrom={lastVirtuosoState}
                initialScrollTop={lastVirtuosoState?.scrollTop}
              />
            ) : (
              <>
                {rows.map((row, index) => (
                  <CatalogRow key={index} index={index} row={row} />
                ))}
                <CatalogFooter
                  subplebbitAddresses={subplebbitAddresses}
                  hasMore={hasMore}
                  feedLength={feedLength}
                  combinedFeedLength={combinedFeed.length}
                  subplebbitAddressesWithNewerPosts={subplebbitAddressesWithNewerPosts}
                  onNewerPostsClick={handleNewerPostsButtonClick}
                  isInAllView={isInAllView}
                  isInSubscriptionsView={isInSubscriptionsView}
                  showMorePostsSuggestion={showMorePostsSuggestion}
                  weeklyFeedLength={weeklyFeedLength}
                  monthlyFeedLength={monthlyFeedLength}
                  yearlyFeedLength={yearlyFeedLength}
                  boardPath={boardPath}
                  currentTimeFilterName={currentTimeFilterName}
                />
              </>
            )}
          </>
        ) : (
          <div className={styles.footer}>
            <CatalogLoading
              subplebbitAddresses={subplebbitAddresses}
              hasMore={hasMore}
              feedLength={feedLength}
              weeklyFeedLength={weeklyFeedLength}
              monthlyFeedLength={monthlyFeedLength}
              yearlyFeedLength={yearlyFeedLength}
              state={state}
              subscriptionsLength={isInSubscriptionsView ? subscriptions?.length || 0 : 1}
              combinedFeedLength={combinedFeed.length}
              error={error}
            />
          </div>
        )}
      </div>
    </div>
  );
};

export default Catalog;
