import { useCallback } from 'react';

import {
  type Comment as CommentType,
  type PostCommentPayload,
} from 'src/types/comments';
import { type User } from 'src/types/user';
import { addReaction, removeReaction } from 'src/utils/reactions';
import { addAnimation } from 'src/utils/styles';

import { type CommentConfig } from 'src/components/comments/commentConfigs';

import {
  type CommentHandlers,
  type ReplyMutation,
} from '../components/comments/types';

import { type CommentsSystemState } from './useCommentsSystem';

export type CommentHandlersProps = {
  postId: number;
  config: CommentConfig;
  setState: React.Dispatch<React.SetStateAction<CommentsSystemState>>;
  searchParams: URLSearchParams;
  setSearchParams: (params: URLSearchParams) => void;
  replyCommentMutation: ReplyMutation;
};

export const useCommentHandlers = ({
  postId,
  config,
  setState,
  searchParams,
  setSearchParams,
  replyCommentMutation,
}: CommentHandlersProps): CommentHandlers => {
  // Basic state handlers
  const handleBlur = useCallback(() => {
    // Used to un-render the comment add component. Left for backwards compatibility.
  }, []);

  const handleClickComment = useCallback(() => {
    setState(prev => ({
      ...prev,
      isFocused: true,
    }));
  }, [setState]);

  // Comment action handlers
  const handleDeleteSuccess = useCallback(
    (commentId: number, parentId: number | null) => {
      if (parentId !== null) {
        config.onDeleteChildSuccess?.(postId, parentId, commentId);
      } else {
        config.onDeleteSuccess?.(postId, commentId);
      }
    },
    [config, postId],
  );

  const handleEditSuccess = useCallback(
    (comment: CommentType) => {
      if (comment.parentId !== null) {
        config.onUpdateChildSuccess?.(postId, comment.parentId, comment);
      } else {
        config.onUpdateSuccess?.(postId, comment);
      }
    },
    [config, postId],
  );

  const handleAddReactionSuccess = useCallback(
    (
      commentId: number,
      parentId: number | null,
      emoji: string,
      unified: string,
    ) => {
      if (parentId !== null) {
        config.onUpdateReactionChildSuccess?.(
          postId,
          parentId,
          commentId,
          reactions => addReaction(reactions, emoji, unified),
        );
      } else {
        config.onUpdateReactionSuccess?.(postId, commentId, reactions =>
          addReaction(reactions, emoji, unified),
        );
      }
    },
    [config, postId],
  );

  const handleRemoveReactionSuccess = useCallback(
    (commentId: number, parentId: number | null, emoji: string) => {
      if (parentId !== null) {
        config.onUpdateReactionChildSuccess?.(
          postId,
          parentId,
          commentId,
          reactions => removeReaction(reactions, emoji),
        );
      } else {
        config.onUpdateReactionSuccess?.(postId, commentId, reactions =>
          removeReaction(reactions, emoji),
        );
      }
    },
    [config, postId],
  );

  // Reply handlers
  const handleReply = useCallback(
    (replyId: number | null) => {
      setState(prev => ({
        ...prev,
        isReplyFocused: true,
        reply: { id: replyId },
      }));
    },
    [setState],
  );

  const handleReplyChild = useCallback(
    (_replyId: number, parentId: number | null, replyUser: User) => {
      setState(prev => ({
        ...prev,
        isReplyFocused: true,
        reply: { id: parentId, user: replyUser },
      }));
    },
    [setState],
  );

  const handleReplyBlur = useCallback(() => {
    setState(prev => ({ ...prev, isReplyFocused: false }));
  }, [setState]);

  const handleDeleteUserReply = useCallback(() => {
    setState(prev => ({
      ...prev,
      reply: prev.reply ? { id: prev.reply.id } : null,
    }));
  }, [setState]);

  // Scroll to comment handler
  const handleScrollToComment = useCallback(
    (
      commentToScrollToRef: React.RefObject<HTMLElement>,
      comments: CommentType[],
    ) => {
      if (commentToScrollToRef?.current && comments?.length) {
        commentToScrollToRef.current.scrollIntoView({
          behavior: 'smooth',
          block: 'center',
        });
        addAnimation(commentToScrollToRef.current, 'flash-animation');
        searchParams.delete('parentId');
        setSearchParams(searchParams);
      } else {
        // Load more comments if needed (TODO: Implement)
      }
    },
    [searchParams, setSearchParams],
  );

  // Show load more comments logic
  const showLoadMoreComments = useCallback(
    (data: any, lastComments: CommentType[], commentCount: number) => {
      const currentCommentsCount = data ? getCurrentCommentsCount(data) : 0;
      return (currentCommentsCount || lastComments?.length) < commentCount;
    },
    [],
  );

  // Get child comments query configuration
  const getChildCommentsQueryConfig = useCallback(
    (comment: CommentType) => {
      return config.getChildCommentsQueryConfig(comment, postId);
    },
    [config, postId],
  );

  // Handle reply comment submission
  const handleReplyComment = useCallback(
    async (formData: PostCommentPayload) => {
      await replyCommentMutation.mutateAsync(formData);
    },
    [replyCommentMutation],
  );

  return {
    // Basic handlers
    handleBlur,
    handleClickComment,

    // Comment actions
    handleDeleteSuccess,
    handleEditSuccess,
    handleAddReactionSuccess,
    handleRemoveReactionSuccess,

    // Reply handlers
    handleReply,
    handleReplyChild,
    handleReplyBlur,
    handleDeleteUserReply,
    handleReplyComment,

    // Load more
    showLoadMoreComments,

    // Scroll
    handleScrollToComment,

    // Child comments
    getChildCommentsQueryConfig,
  };
};

// Helper function to get current comments count
const getCurrentCommentsCount = (data: any) => {
  let counter = 0;
  data?.pages.forEach((page: any) => {
    counter += 'items' in page.data ? page.data.items.length : page.data.length;
  });
  return counter;
};
