import clsx from 'clsx';
import { useRouter } from 'next/router';
import { useState } from 'react';
import {
  ArrowDownCircleIcon,
  ArrowUpCircleIcon,
} from '@heroicons/react/20/solid';
import { Vote } from '@prisma/client';

import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';

import { trpc } from '~/utils/trpc';

type ResumeCommentVoteButtonsProps = {
  commentId: string;
  userId: string | undefined;
};

export default function ResumeCommentVoteButtons({
  commentId,
  userId,
}: ResumeCommentVoteButtonsProps) {
  const [upvoteAnimation, setUpvoteAnimation] = useState(false);
  const [downvoteAnimation, setDownvoteAnimation] = useState(false);
  const { event: gaEvent } = useGoogleAnalytics();

  const trpcContext = trpc.useContext();
  const router = useRouter();

  // COMMENT VOTES
  const commentVotesQuery = trpc.useQuery([
    'resumes.comments.votes.list',
    { commentId },
  ]);
  const commentVotesUpsertMutation = trpc.useMutation(
    'resumes.comments.votes.user.upsert',
    {
      onSuccess: () => {
        // Comment updated, invalidate query to trigger refetch
        trpcContext.invalidateQueries(['resumes.comments.votes.list']);
        gaEvent({
          action: 'resumes.comment_vote',
          category: 'engagement',
          label: 'Upvote/Downvote comment',
        });
      },
    },
  );
  const commentVotesDeleteMutation = trpc.useMutation(
    'resumes.comments.votes.user.delete',
    {
      onSuccess: () => {
        // Comment updated, invalidate query to trigger refetch
        trpcContext.invalidateQueries(['resumes.comments.votes.list']);
        gaEvent({
          action: 'resumes.comment_unvote',
          category: 'engagement',
          label: 'Unvote comment',
        });
      },
    },
  );

  const onVote = async (value: Vote, setAnimation: (_: boolean) => void) => {
    if (!userId) {
      router.push('/api/auth/signin');
      return;
    }

    setAnimation(true);

    if (commentVotesQuery.data?.userVote?.value === value) {
      return commentVotesDeleteMutation.mutate(
        {
          commentId,
        },
        {
          onSettled: async () => setAnimation(false),
        },
      );
    }
    return commentVotesUpsertMutation.mutate(
      {
        commentId,
        value,
      },
      {
        onSettled: async () => setAnimation(false),
      },
    );
  };

  return (
    <>
      <button
        disabled={
          commentVotesQuery.isLoading ||
          commentVotesUpsertMutation.isLoading ||
          commentVotesDeleteMutation.isLoading
        }
        type="button"
        onClick={() => onVote(Vote.UPVOTE, setUpvoteAnimation)}>
        <ArrowUpCircleIcon
          className={clsx(
            'h-4 w-4',
            commentVotesQuery.data?.userVote?.value === Vote.UPVOTE ||
              upvoteAnimation
              ? 'fill-primary-500'
              : 'fill-slate-400',
            userId &&
              !downvoteAnimation &&
              !upvoteAnimation &&
              'hover:fill-primary-500',
            upvoteAnimation && 'animate-[bounce_0.5s_infinite] cursor-default',
          )}
        />
      </button>

      <div className="flex min-w-[1rem] justify-center text-xs font-semibold text-gray-700">
        {commentVotesQuery.data?.numVotes ?? 0}
      </div>

      <button
        disabled={
          commentVotesQuery.isLoading ||
          commentVotesUpsertMutation.isLoading ||
          commentVotesDeleteMutation.isLoading
        }
        type="button"
        onClick={() => onVote(Vote.DOWNVOTE, setDownvoteAnimation)}>
        <ArrowDownCircleIcon
          className={clsx(
            'h-4 w-4',
            commentVotesQuery.data?.userVote?.value === Vote.DOWNVOTE ||
              downvoteAnimation
              ? 'fill-danger-500'
              : 'fill-slate-400',
            userId &&
              !downvoteAnimation &&
              !upvoteAnimation &&
              'hover:fill-danger-500',
            downvoteAnimation &&
              'animate-[bounce_0.5s_infinite] cursor-default',
          )}
        />
      </button>
    </>
  );
}