import { useState, useEffect, useRef } from 'react';
import {
  subscribeToParticle,
  subscribeToParticleChildren,
  subscribeToLatestChild,
  getParticle,
  getParticleChildren,
} from '@/lib/firestore-particles';
import type { Particle } from '@/api/types';
import {
  type ParticlePath,
  toFirestoreDocPath,
  toFirestoreChildrenPath,
} from '@/lib/particle-path';
import { useQuery } from '@tanstack/react-query';
import { QueryFieldFilterConstraint } from 'firebase/firestore';

interface UseLiveParticleResult {
  particle: Particle | null;
  isLoading: boolean;
  error: Error | null;
}

export function useLiveParticle(path: ParticlePath): UseLiveParticleResult {
  const [particle, setParticle] = useState<Particle | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    const docPath = toFirestoreDocPath(path);
    const unsubscribe = subscribeToParticle(
      docPath,
      (data) => {
        setParticle(data);
        setIsLoading(false);
      },
      (err) => {
        setError(err);
        setIsLoading(false);
      },
    );

    return () => {
      unsubscribe();
      setIsLoading(true);
      setError(null);
      setParticle(null);
    };
  }, [path]);

  return { particle, isLoading, error };
}

interface UseLiveParticleChildrenResult {
  children: Particle[];
  isLoading: boolean;
  error: Error | null;
}

interface UseLiveParticleChildrenParams {
  orderByField?: string;
  orderDirection?: 'asc' | 'desc';
  visibilityScopes?: string[];
  onAdded?: (child: Particle) => void;
  onRemoved?: (child: Particle, updatedChildren: Particle[]) => void;
  whereFilter?: QueryFieldFilterConstraint;
  /** Optional cap on results. Changes trigger a re-subscription. */
  limit?: number;
}

export function useLiveParticleChildren(
  path: ParticlePath | undefined,
  {
    orderByField = 'created_at',
    orderDirection = 'desc',
    visibilityScopes,
    onAdded,
    onRemoved,
    whereFilter,
    limit,
  }: UseLiveParticleChildrenParams = {},
): UseLiveParticleChildrenResult {
  const [children, setChildren] = useState<Particle[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  // Keep the latest add/remove callbacks in refs so changing them doesn't force
  // the subscription to re-attach — they're notifications, not query params.
  const onAddedRef = useRef(onAdded);
  const onRemovedRef = useRef(onRemoved);
  useEffect(() => {
    onAddedRef.current = onAdded;
    onRemovedRef.current = onRemoved;
  }, [onAdded, onRemoved]);

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

    const collectionPath = toFirestoreChildrenPath(path);

    const unsubscribe = subscribeToParticleChildren(collectionPath, {
      onData: (data) => {
        setChildren(data);
        setIsLoading(false);
      },
      onError: (err) => {
        console.warn(err);
        setError(err);
        setIsLoading(false);
      },
      visibilityScopes,
      orderByField,
      orderDirection,
      onAdded: (child: Particle) => onAddedRef.current?.(child),
      onRemoved: (child: Particle, updatedChildren: Particle[]) =>
        onRemovedRef.current?.(child, updatedChildren),
      whereFilter,
      limit,
    });

    return () => {
      unsubscribe();
      setChildren([]);
      setError(null);
      setIsLoading(true);
    };
  }, [
    path,
    whereFilter,
    limit,
    orderByField,
    orderDirection,
    visibilityScopes,
  ]);

  // No path: nothing to load, so report an empty non-loading state.
  if (!path) {
    return { children: [], isLoading: false, error: null };
  }

  return { children, isLoading, error };
}

interface UseLiveLatestChildResult {
  latestChild: Particle | null;
  isLoading: boolean;
}

export function useLiveLatestChild(
  path: ParticlePath,
): UseLiveLatestChildResult {
  const [latestChild, setLatestChild] = useState<Particle | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = subscribeToLatestChild(
      toFirestoreChildrenPath(path),
      (data) => {
        setLatestChild(data);
        setIsLoading(false);
      },
      () => {
        setIsLoading(false);
      },
    );

    return () => {
      unsubscribe();
      setIsLoading(true);
      setLatestChild(null);
    };
  }, [path]);

  return { latestChild, isLoading };
}

export function useParticle(path?: ParticlePath) {
  return useQuery({
    queryKey: ['particle', path],
    queryFn: async () => {
      if (!path) return null;
      const docPath = toFirestoreDocPath(path);
      const particle = await getParticle(docPath);
      return particle;
    },
    enabled: !!path,
  });
}

export function useParticleChildren(path?: ParticlePath) {
  return useQuery({
    queryKey: ['particle-children', path],
    queryFn: async () => {
      if (!path) return [];
      const collectionPath = toFirestoreChildrenPath(path);
      return getParticleChildren(collectionPath);
    },
    enabled: !!path,
    staleTime: 1000 * 60 * 5, // 5 min — attachments don't change
  });
}
