import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
import { useCallback, useMemo } from 'react';

export interface StreamPage<T> {
  data: T[];
  nextCursor: string | null;
  hasMore: boolean;
}

export interface UseInfiniteStreamArgs<T> {
  queryKey: readonly unknown[];
  fetchPage: (cursor: string | undefined) => Promise<StreamPage<T>>;
  enabled?: boolean;
  /** When true, the query auto-refetches every refetchMs ms. When false, polling pauses. */
  isAtTop: boolean;
  refetchMs?: number;
  staleTime?: number;
}

export interface UseInfiniteStreamResult<T> {
  items: T[];
  fetchNextPage: () => void;
  hasNextPage: boolean;
  isFetchingNextPage: boolean;
  isLoading: boolean;
  refresh: () => void;
}

/**
 * Thin wrapper over tanstack useInfiniteQuery that:
 *   - flattens pages into a single items[] array (newest first)
 *   - gates auto-refetch on isAtTop (so a user scrolled down does not lose their viewport)
 *   - exposes refresh() that invalidates the query (reset to page 1 on next render)
 */
export function useInfiniteStream<T>(args: UseInfiniteStreamArgs<T>): UseInfiniteStreamResult<T> {
  const { queryKey, fetchPage, enabled = true, isAtTop, refetchMs = 15_000, staleTime = 300 } = args;
  const queryClient = useQueryClient();

  const query = useInfiniteQuery<StreamPage<T>, Error>({
    queryKey: [...queryKey],
    initialPageParam: undefined as string | undefined,
    queryFn: ({ pageParam }) => fetchPage(pageParam as string | undefined),
    getNextPageParam: (last) => (last.hasMore && last.nextCursor ? last.nextCursor : undefined),
    enabled,
    refetchInterval: isAtTop ? refetchMs : false,
    staleTime,
    placeholderData: (prev) => prev,
  });

  const items = useMemo<T[]>(
    () => (query.data?.pages ?? []).flatMap((p) => p.data),
    [query.data],
  );

  const fetchNextPage = useCallback(() => {
    if (query.hasNextPage && !query.isFetchingNextPage) query.fetchNextPage();
  }, [query.hasNextPage, query.isFetchingNextPage, query.fetchNextPage]);

  const refresh = useCallback(() => {
    queryClient.invalidateQueries({ queryKey: [...queryKey] });
  }, [queryClient, queryKey]);

  return {
    items,
    fetchNextPage,
    hasNextPage: !!query.hasNextPage,
    isFetchingNextPage: query.isFetchingNextPage,
    isLoading: query.isLoading,
    refresh,
  };
}
