import {
  keepPreviousData,
  useMutation,
  useQuery,
  useQueryClient,
  UseQueryResult,
} from "@tanstack/react-query";
import { notifications } from "@mantine/notifications";
import { useTranslation } from "react-i18next";
import {
  ICreateShare,
  IShare,
  IShareAlias,
  ISetShareAlias,
  ISharedItem,
  ISharedPage,
  ISharedPageTree,
  IShareForPage,
  IShareInfoInput,
  IUpdateShare,
} from "@/features/share/types/share.types.ts";
import {
  createShare,
  deleteShare,
  getShareAliasForPage,
  getSharedPageTree,
  getShareForPage,
  getShareInfo,
  getSharePageInfo,
  getShares,
  removeShareAlias,
  setShareAlias,
  updateShare,
} from "@/features/share/services/share-service.ts";
import { IPagination, QueryParams } from "@/lib/types.ts";

export function useGetSharesQuery(
  params?: QueryParams,
): UseQueryResult<IPagination<ISharedItem>, Error> {
  return useQuery({
    queryKey: ["share-list", params],
    queryFn: () => getShares(params),
    placeholderData: keepPreviousData,
  });
}

export function useGetShareByIdQuery(
  shareId: string,
): UseQueryResult<IShare, Error> {
  const query = useQuery({
    queryKey: ["share-by-id", shareId],
    queryFn: () => getShareInfo(shareId),
    enabled: !!shareId,
  });

  return query;
}

export function useSharePageQuery(
  shareInput: Partial<IShareInfoInput>,
): UseQueryResult<ISharedPage, Error> {
  const query = useQuery({
    queryKey: ["shares", shareInput],
    queryFn: () => getSharePageInfo(shareInput),
    enabled: !!shareInput.pageId,
  });

  return query;
}

export function useShareForPageQuery(
  pageId: string,
): UseQueryResult<IShareForPage | null, Error> {
  const query = useQuery({
    queryKey: ["share-for-page", pageId],
    // React Query forbids `undefined` as resolved data ("Query data cannot be
    // undefined"). When no share exists for the page the endpoint resolves to
    // undefined, so normalize the absence to `null`.
    queryFn: async () => (await getShareForPage(pageId)) ?? null,
    enabled: !!pageId,
    staleTime: 60 * 1000,
    retry: false,
  });

  return query;
}

export function useCreateShareMutation() {
  const { t } = useTranslation();
  const queryClient = useQueryClient();

  return useMutation<any, Error, ICreateShare>({
    mutationFn: (data) => createShare(data),
    onSuccess: (data) => {
      queryClient.invalidateQueries({
        predicate: (item) =>
          ["share-for-page", "share-list"].includes(item.queryKey[0] as string),
      });
    },
    onError: (error) => {
      notifications.show({
        message: error?.["response"]?.data?.message || t("Failed to share page"),
        color: "red",
      });
    },
  });
}

export function useUpdateShareMutation() {
  const { t } = useTranslation();
  const queryClient = useQueryClient();

  return useMutation<any, Error, IUpdateShare>({
    mutationFn: (data) => updateShare(data),
    onSuccess: (data) => {
      queryClient.invalidateQueries({
        predicate: (item) =>
          ["share-for-page", "share-list"].includes(item.queryKey[0] as string),
      });
    },
    onError: (error, params) => {
      if (error?.["status"] === 404) {
        queryClient.removeQueries({
          predicate: (item) =>
            ["share-for-page"].includes(item.queryKey[0] as string),
        });

        notifications.show({
          message: t("Share not found"),
          color: "red",
        });
        return;
      }

      notifications.show({
        message: error?.["response"]?.data?.message || "Share not found",
        color: "red",
      });
    },
  });
}

export function useDeleteShareMutation() {
  const { t } = useTranslation();
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (shareId: string) => deleteShare(shareId),
    onSuccess: (data) => {
      queryClient.removeQueries({
        predicate: (item) =>
          ["share-for-page"].includes(item.queryKey[0] as string),
      });

      queryClient.invalidateQueries({
        predicate: (item) =>
          ["share-list"].includes(item.queryKey[0] as string),
      });

      notifications.show({ message: t("Share deleted successfully") });
    },
    onError: (error) => {
      if (error?.["status"] === 404) {
        queryClient.removeQueries({
          predicate: (item) =>
            ["share-for-page"].includes(item.queryKey[0] as string),
        });
      }

      notifications.show({
        message: error?.["response"]?.data?.message || "Failed to delete share",
        color: "red",
      });
    },
  });
}

export function useShareAliasForPageQuery(
  pageId: string,
): UseQueryResult<IShareAlias | null, Error> {
  return useQuery({
    // The endpoint resolves to null when the page has no alias; normalize the
    // absence so React Query never sees `undefined`.
    queryKey: ["share-alias-for-page", pageId],
    queryFn: async () => (await getShareAliasForPage(pageId)) ?? null,
    enabled: !!pageId,
    staleTime: 60 * 1000,
    retry: false,
  });
}

export function useSetShareAliasMutation() {
  const { t } = useTranslation();
  const queryClient = useQueryClient();

  return useMutation<IShareAlias, Error, ISetShareAlias>({
    mutationFn: (data) => setShareAlias(data),
    onSuccess: () => {
      queryClient.invalidateQueries({
        predicate: (item) =>
          ["share-alias-for-page", "share-list"].includes(
            item.queryKey[0] as string,
          ),
      });
    },
    onError: (error) => {
      // A 409 reassign-required is handled inline by the modal (it shows the
      // "move address here?" confirmation), so don't surface a generic toast.
      if (error?.["status"] === 409) return;
      notifications.show({
        message:
          error?.["response"]?.data?.message || t("Failed to set custom address"),
        color: "red",
      });
    },
  });
}

export function useRemoveShareAliasMutation() {
  const { t } = useTranslation();
  const queryClient = useQueryClient();

  return useMutation<void, Error, string>({
    mutationFn: (aliasId) => removeShareAlias(aliasId),
    onSuccess: () => {
      queryClient.invalidateQueries({
        predicate: (item) =>
          ["share-alias-for-page", "share-list"].includes(
            item.queryKey[0] as string,
          ),
      });
    },
    onError: (error) => {
      notifications.show({
        message:
          error?.["response"]?.data?.message ||
          t("Failed to remove custom address"),
        color: "red",
      });
    },
  });
}

export function useGetSharedPageTreeQuery(
  shareId: string,
): UseQueryResult<ISharedPageTree, Error> {
  return useQuery({
    queryKey: ["shared-page-tree", shareId],
    queryFn: () => getSharedPageTree(shareId),
    enabled: !!shareId,
    placeholderData: keepPreviousData,
    staleTime: 60 * 60 * 1000,
  });
}
