import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";

import { api } from "../client";
import type { components } from "../schema";
import { HttpError, InUseError } from "../errors";
import { keys } from "../query-keys";

type NewFieldDefinitionRequest = components["schemas"]["NewFieldDefinitionRequest"];
type LabelInput = components["schemas"]["LabelInput"];

export function useFieldDefinitions() {
  return useQuery({
    queryKey: keys.fieldDefinitions(),
    queryFn: async () => {
      const { data, error } = await api.GET("/api/admin/field-definitions");

      if (error || !data) throw new Error("failed to load field definitions");

      return data;
    },
    staleTime: 5 * 60 * 1000,
  });
}

export function useCreateFieldDefinition() {
  const qc = useQueryClient();

  return useMutation({
    mutationFn: async (body: NewFieldDefinitionRequest) => {
      const { data, response } = await api.POST("/api/admin/field-definitions", { body });

      if (response.status !== 201 || !data) throw new HttpError(response.status);

      return data;
    },
    onSuccess: () => qc.invalidateQueries({ queryKey: keys.fieldDefinitions() }),
    meta: { successMessage: "toast.created", suppressErrorToast: true },
  });
}

export function useUpdateFieldDefinition() {
  const qc = useQueryClient();

  return useMutation({
    mutationFn: async ({
      key,
      required,
      group,
      labels,
    }: {
      key: string;
      required: boolean;
      group: string | null;
      labels: LabelInput[];
    }) => {
      const { response } = await api.PATCH("/api/admin/field-definitions/{key}", {
        params: { path: { key } },
        body: { required, group, labels },
      });

      if (response.status !== 204) throw new HttpError(response.status);
    },
    onSuccess: () => qc.invalidateQueries({ queryKey: keys.fieldDefinitions() }),
    meta: { successMessage: "toast.saved", suppressErrorToast: true },
  });
}

export function useDeleteFieldDefinition() {
  const qc = useQueryClient();

  return useMutation({
    mutationFn: async (key: string) => {
      const { error, response } = await api.DELETE("/api/admin/field-definitions/{key}", {
        params: { path: { key } },
      });

      if (response.status === 409) throw new InUseError((error as { count?: number })?.count ?? 0);
      if (response.status !== 204) throw new HttpError(response.status);
    },
    onSuccess: () => qc.invalidateQueries({ queryKey: keys.fieldDefinitions() }),
    meta: { successMessage: "toast.deleted", suppressErrorToast: true },
  });
}
