import { useMutation, useQueryClient } from "@tanstack/react-query";
import { createParticle, createStreamParticle } from "@/lib/firestore-particles";
import { CONTAINER_TYPES, type NetworkUsage, type ParticleType, type ParticlePropertiesMap } from "@/api/types";
import { parseParticlePath, particlePath, ParticlePath, toFirestoreChildrenPath } from "@/lib/particle-path";
import { QuotaExceededError } from "@/lib/errors";
import {
  isUsageExhausted,
  networkUsageQueryKey,
  useBumpNetworkUsage,
  useInvalidateNetworkUsage,
} from "./use-network-usage";

interface CreateParticleParams<T extends ParticleType = ParticleType> {
  // Path to which the new particle will be added as a child
  path: ParticlePath;
  type: T;
  properties: ParticlePropertiesMap[T];
  createdByHumanId: string;
}

export function useCreateParticle() {
  const qc = useQueryClient();
  const bumpUsage = useBumpNetworkUsage();
  const invalidateUsage = useInvalidateNetworkUsage();

  return useMutation({
    // Compose UI renders a custom quota-exceeded toast + cancels the overlay.
    // Opt out of the global mutation error toast to avoid a double-toast.
    meta: { suppressToast: true },
    mutationFn: async (params: CreateParticleParams) => {
      const { networkId } = parseParticlePath(params.path);

      // Containers aren't counted server-side, so we block them here
      if (!CONTAINER_TYPES.has(params.type)) {
        const cached = qc.getQueryData<NetworkUsage>(networkUsageQueryKey(networkId));
        if (isUsageExhausted(cached)) {
          throw new QuotaExceededError(networkId);
        }
      }

      const collectionPath = toFirestoreChildrenPath(params.path);
      const result = await createParticle(
        collectionPath,
        params.type,
        params.properties,
        params.createdByHumanId,
      );

      if (!CONTAINER_TYPES.has(params.type)) {
        bumpUsage(networkId);
        void invalidateUsage(networkId);
      }

      return result;
    },
  });
}

type CreateStreamParticleParams = {
  networkId: string;
  properties: ParticlePropertiesMap["stream"];
  createdByHumanId: string;
  visibleTo?: string[];
};

export function useCreateStreamParticle() {
  return useMutation({
    mutationFn: async (params: CreateStreamParticleParams) => {
      const path = particlePath(params.networkId, []);
      const networkCollectionPath = toFirestoreChildrenPath(path);
      return await createStreamParticle(
        networkCollectionPath,
        params.properties,
        params.createdByHumanId,
        params.visibleTo,
      );
    }
  });
}
