import { useCallback, useMemo, useState } from 'react';
import { where, type QueryFieldFilterConstraint } from 'firebase/firestore';
import { useLiveParticleChildren } from '@/hooks/use-particle';
import { useAuthStore } from '@/stores/auth-store';
import { parseParticlePath, type ParticlePath } from '@/lib/particle-path';
import type { Particle, StreamProperties } from '@/api/types';

export type StreamParticle = Particle & {
  type: 'stream';
  properties: StreamProperties;
};

const INITIAL_PAGE_SIZE = 12;
const PAGE_INCREMENT = 12;

// Stable where-constraint references so the Firestore subscription only
// re-attaches when the tab actually changes, not on every render.
const OPEN_STATUS_FILTER = where('status', '==', 'open');
const CLOSED_STATUS_FILTER = where('status', '==', 'closed');

function useVisibilityScopes(userId?: string, networkId?: string) {
  return useMemo(() => {
    const scopes: string[] = [];
    if (userId) scopes.push(`human:${userId}`);
    if (networkId) scopes.push(`network:${networkId}`);
    return scopes;
  }, [userId, networkId]);
}

interface UseStreamParticlesOptions {
  // Which streams to subscribe to
  status: 'open' | 'closed';
}

interface UseStreamParticlesResult {
  streams: StreamParticle[];
  isLoading: boolean;
  networkId: string;
  /** True when more streams may exist beyond the current window. */
  canLoadMore: boolean;
  /** Extend the pagination window. */
  loadMore: () => void;
}

export function useStreamParticles(
  path: ParticlePath,
  { status }: UseStreamParticlesOptions,
): UseStreamParticlesResult {
  const { networkId } = parseParticlePath(path);
  const user = useAuthStore((s) => s.user);
  const visibilityScopes = useVisibilityScopes(user?.id, networkId);

  const [limit, setLimit] = useState(INITIAL_PAGE_SIZE);

  const whereFilter: QueryFieldFilterConstraint =
    status === 'open' ? OPEN_STATUS_FILTER : CLOSED_STATUS_FILTER;

  const { children, isLoading } = useLiveParticleChildren(path, {
    orderByField: 'last_child_created_at',
    orderDirection: 'desc',
    visibilityScopes,
    whereFilter,
    limit,
  });

  const streams = useMemo(
    () => children.filter((c): c is StreamParticle => c.type === 'stream'),
    [children],
  );

  // Heuristic: if we got back as many items as we asked for, assume there
  // might be more. Clicking load-more when there are no more is a no-op.
  const canLoadMore = streams.length >= limit;

  const loadMore = useCallback(() => {
    setLimit((prev) => prev + PAGE_INCREMENT);
  }, []);

  return { streams, isLoading, networkId, canLoadMore, loadMore };
}
