import { useCallback } from 'react';

import { useMutation } from 'react-query';

import { logEvent } from 'src/config/logging';
import useGeneralError from 'src/hooks/useGeneralError';
import {
  addEventPostReaction,
  removeEventPostReaction,
  getEventPostReactionUsers,
} from 'src/services/events';
import {
  addGroupPostReaction,
  removeGroupPostReaction,
  getGroupPostReactionUsers,
} from 'src/services/groups';
import {
  addMarketplacePostReaction,
  removeMarketplacePostReaction,
  getMarketplacePostReactionUsers,
} from 'src/services/marketplace';
import {
  addPostReaction,
  removePostReaction,
  getPostReactionUsers,
} from 'src/services/posts';
import { EventName } from 'src/types/amplitude';
import { Reaction } from 'src/types/reaction';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';
import { canAddReaction } from 'src/utils/reactions';

import { invalidateReactionUserList } from 'src/components/dashboard/reactions/queries';
import { GenericGetReactionUsersFunction } from 'src/components/dashboard/reactions/UsersListDrawer/ReactionUsersList';

export type PostReactionsContext = 'feed' | 'groups' | 'marketplace' | 'events';

export type UsePostReactionsProps = {
  context: PostReactionsContext;
  postId: number;
  groupId?: number | string;
  eventId?: number;
  reactions: Reaction[];
  /** Called in onMutate for instant UI feedback. Rolled back on error. */
  onAddReactionOptimistic?: (
    postId: number,
    emoji: string,
    unified: string,
  ) => void;
  onRemoveReactionOptimistic?: (postId: number, emoji: string) => void;
  /** Called in onSuccess after the API responds. Use for refetching etc. */
  onAddReactionSuccess?: (
    postId: number,
    emoji: string,
    unified: string,
  ) => void;
  onRemoveReactionSuccess?: (postId: number, emoji: string) => void;
};

export type UsePostReactionsReturn = {
  handleAddReaction: (emoji: string, unified: string) => Promise<void>;
  handleRemoveReaction: (emoji: string) => Promise<void>;
  getReactionUsers: GenericGetReactionUsersFunction;
};

export const usePostReactions = ({
  context,
  postId,
  groupId,
  eventId,
  reactions,
  onAddReactionOptimistic,
  onRemoveReactionOptimistic,
  onAddReactionSuccess = () => null,
  onRemoveReactionSuccess = () => null,
}: UsePostReactionsProps): UsePostReactionsReturn => {
  const { t } = useTranslation(['web_only']);
  const showGeneralError = useGeneralError();

  const useGroupService =
    context === 'groups' || (context === 'feed' && groupId);
  const useFeedService = context === 'feed' && !groupId;
  const useEventsService = context === 'events';

  // Get event name for logging
  const getEventName = () => {
    if (useFeedService) return EventName.POST_REACTION;
    if (useGroupService) return EventName.GROUPS_POST_REACTIONED;
    if (useEventsService) return EventName.EVENT_POST_REACTION;
    return EventName.POST_MARKETPLACE_REACTION;
  };

  // Add reaction mutation
  const addReaction = useMutation(
    ({ emoji, unified }: { emoji: string; unified: string }) => {
      if (useFeedService) return addPostReaction(postId, emoji, unified);
      if (useGroupService)
        return addGroupPostReaction(postId, groupId!, emoji, unified);
      if (useEventsService)
        return addEventPostReaction(eventId!, postId, emoji, unified);
      return addMarketplacePostReaction(postId, emoji, unified);
    },
    {
      onMutate: ({ emoji, unified }) => {
        onAddReactionOptimistic?.(postId, emoji, unified);
      },
      onSuccess: (_, { emoji, unified }) => {
        onAddReactionSuccess(postId, emoji, unified);
        invalidateReactionUserList(postId, emoji);

        logEvent(getEventName(), {
          postId,
          reaction: emoji,
          ...(useGroupService ? { groupId: Number(groupId) } : {}),
          ...(useEventsService ? { eventId } : {}),
        });
      },
      onError: (err, { emoji }) => {
        onRemoveReactionOptimistic?.(postId, emoji);
        showGeneralError(err, t('web_only:reactions.add_reaction_error'));
      },
    },
  );

  // Remove reaction mutation
  const removeReaction = useMutation(
    (emoji: string) => {
      if (useFeedService) return removePostReaction(postId, emoji);
      if (useGroupService)
        return removeGroupPostReaction(postId, groupId!, emoji);
      if (useEventsService)
        return removeEventPostReaction(eventId!, postId, emoji);
      return removeMarketplacePostReaction(postId, emoji);
    },
    {
      onMutate: emoji => {
        const unified = reactions.find(r => r.emoji === emoji)?.unified;
        onRemoveReactionOptimistic?.(postId, emoji);
        return { unified };
      },
      onSuccess: (_, emoji) => {
        onRemoveReactionSuccess(postId, emoji);
        invalidateReactionUserList(postId, emoji);
      },
      onError: (err, emoji, context) => {
        if (context?.unified) {
          onAddReactionOptimistic?.(postId, emoji, context.unified);
        }
        showGeneralError(err, t('web_only:reactions.remove_reaction_error'));
      },
    },
  );

  // Handle add reaction with validation
  const handleAddReaction = useCallback(
    async (emoji: string, unified: string) => {
      if (!canAddReaction(reactions, emoji)) return;
      await addReaction.mutateAsync({ emoji, unified });
    },
    [reactions, addReaction],
  );

  // Handle remove reaction
  const handleRemoveReaction = useCallback(
    async (emoji: string) => {
      await removeReaction.mutateAsync(emoji);
    },
    [removeReaction],
  );

  // Get reaction users function - context-aware
  const getReactionUsers = useCallback(
    (emoji: string, params?: { timestamp?: string; cursor?: string }) => {
      if (useGroupService)
        return getGroupPostReactionUsers(
          postId,
          groupId!,
          emoji,
          params?.cursor ?? '',
        );
      if (useFeedService)
        return getPostReactionUsers(postId, emoji, params?.timestamp);
      if (useEventsService)
        return getEventPostReactionUsers(
          eventId!,
          postId,
          emoji,
          params?.cursor ?? '',
        );
      return getMarketplacePostReactionUsers(postId, emoji, params?.timestamp);
    },
    [
      useFeedService,
      useGroupService,
      useEventsService,
      postId,
      groupId,
      eventId,
    ],
  );

  return {
    handleAddReaction,
    handleRemoveReaction,
    getReactionUsers,
  };
};

export default usePostReactions;
