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 CLOSED_INITIAL_PAGE_SIZE = 50;
const CLOSED_PAGE_INCREMENT = 50;

// 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. Open streams are loaded in full (bounded
   * by active work — full realtime coverage is needed for autoplay/huddles).
   * Closed streams are paginated via `loadMore`.
   */
  status: 'open' | 'closed';
}

interface UseStreamParticlesResult {
  streams: StreamParticle[];
  isLoading: boolean;
  error: Error | null;
  networkId: string;
  /** True when more closed streams may exist beyond the current window. */
  canLoadMore: boolean;
  /** Extend the pagination window. No-op on the open tab. */
  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 [closedLimit, setClosedLimit] = useState(CLOSED_INITIAL_PAGE_SIZE);
  const [prevStatus, setPrevStatus] = useState(status);

  // Switching back to the closed tab starts a fresh window, avoiding an
  // ever-growing subscription across a long session.
  if (status !== prevStatus) {
    setPrevStatus(status);
    if (status === 'closed') {
      setClosedLimit(CLOSED_INITIAL_PAGE_SIZE);
    }
  }

  const whereFilter: QueryFieldFilterConstraint =
    status === 'open' ? OPEN_STATUS_FILTER : CLOSED_STATUS_FILTER;
  const limit = status === 'closed' ? closedLimit : undefined;

  const { children, isLoading, error } = 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 = status === 'closed' && streams.length >= closedLimit;

  const loadMore = useCallback(() => {
    if (status !== 'closed') return;
    setClosedLimit((prev) => prev + CLOSED_PAGE_INCREMENT);
  }, [status]);

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