import { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useInfiniteQuery, useMutation } from 'react-query';
import { useSearchParams } from 'react-router-dom';

import useSnackbar from '@material-hu/components/design-system/Snackbar';
import { useCommentHandlers } from 'src/hooks/useCommentHandlers';
import usePermissions from 'src/hooks/usePermissions';
import { Comment as CommentType, PostCommentPayload } from 'src/types/comments';
import { TaggedUser } from 'src/types/user';
import { getCommentsList } from 'src/utils/comments';

import { getCommentConfig } from 'src/components/comments/commentConfigs';

import { CommentMutation, ReplyMutation } from 'src/components/comments/types';

export type CommentContext =
  | 'feed'
  | 'groups'
  | 'acknowledgements'
  | 'marketplace'
  | 'articles'
  | 'events';

export type CommentsSystemState = {
  isFocused: boolean;
  hasLoadMore: boolean;
  isReplyFocused: boolean;
  reply: {
    id?: number | null;
    user?: CommentType['user'];
  } | null;
};

export type CommentsSystemProps = {
  context: CommentContext;
  postId: number;
  lastComments: CommentType[];
  groupId?: string;
  eventId?: number;
  isDetail?: boolean;
  shouldAutoLoad?: boolean;
  commentsEnabled?: boolean;
};

export const useCommentsSystem = ({
  context,
  postId,
  groupId,
  eventId,
  shouldAutoLoad = false,
  commentsEnabled = true,
}: CommentsSystemProps) => {
  const { enqueueSnackbar } = useSnackbar();
  const [searchParams, setSearchParams] = useSearchParams();
  const { t } = useTranslation(['post']);

  // State management
  const [state, setState] = useState<CommentsSystemState>({
    isFocused: false,
    hasLoadMore: false,
    isReplyFocused: false,
    reply: null,
  });

  const [shouldEnable, setShouldEnable] = useState(shouldAutoLoad); // This allows cache invalidation refetching but not initial auto-load

  // Get context-specific configuration with proper groupId/eventId handling
  const config = getCommentConfig(context, groupId, eventId);

  // Permissions
  const { hasAny: canReact } = usePermissions(config.permissions.react);
  const { hasAny: canManageComments } = usePermissions(
    config.permissions.manage,
  );

  // Query key and parameters
  const queryKey = config.getQueryKey(postId);

  // Main comments query
  const { data, isLoading, fetchNextPage, isFetchingNextPage } =
    useInfiniteQuery(
      queryKey,
      ({ pageParam }) => config.queryFn(postId, pageParam),
      {
        getNextPageParam: config.getNextPageParam,
        enabled: shouldEnable && commentsEnabled,
        onError: () => {
          enqueueSnackbar({
            title: t('post:error_loading_comments'),
            variant: 'error',
          });
        },
        select: config.select,
      },
    );

  // Post comment mutation
  const postCommentMutation: CommentMutation = useMutation(
    (body: [PostCommentPayload, TaggedUser[]]) =>
      config.postComment(postId, body[0]),
    {
      onSuccess: (response, variables) => {
        // Enable query so invalidation triggers a refetch
        setShouldEnable(true);
        config.onPostSuccess?.(postId, response?.data);

        // Log events if configured
        if (config.logEvents?.postComment) {
          config.logEvents.postComment({
            postId,
            commentId: response.data?.id,
            isChildComment: !!response.data?.parentId,
            groupId,
            eventId,
          });
        }

        // Log mentions if configured
        if (config.logEvents?.postMention && variables[1]?.length) {
          variables[1].forEach((elem: TaggedUser) => {
            config.logEvents?.postMention?.({
              postId,
              commentId: response.data?.id,
              userId: elem.type.user.id,
              isChildComment: !!response.data?.parentId,
              groupId,
              eventId,
            });
          });
        }
      },
    },
  );

  // Reply comment mutation
  const replyCommentMutation: ReplyMutation = useMutation(
    (body: PostCommentPayload) => config.postComment(postId, body),
    {
      onSuccess: response => {
        // Enable query so invalidation triggers a refetch
        setShouldEnable(true);
        if (response?.data?.parentId) {
          config.onReplySuccess?.(
            postId,
            response?.data?.parentId,
            response?.data,
          );
        }
        setState(prev => ({ ...prev, reply: { id: postId } }));
      },
    },
  );

  // Get comments list
  const comments = useMemo(() => {
    return data ? getCommentsList(data) : [];
  }, [data]);

  const setIsFocused = useCallback((value: boolean) => {
    setState(prev => ({ ...prev, isFocused: value }));
  }, []);

  // Custom fetchNextPage that enables the query on first call
  const handleFetchNextPage = useCallback(async () => {
    if (isFetchingNextPage) return;
    if (!shouldEnable) {
      setShouldEnable(true);
    }
    return fetchNextPage();
  }, [shouldEnable, fetchNextPage, isFetchingNextPage]);

  // Get comment handlers
  const handlers = useCommentHandlers({
    postId,
    config,
    setState,
    searchParams,
    setSearchParams,
    replyCommentMutation,
  });

  return {
    // Data
    comments,
    data,
    isLoading,
    isFetchingNextPage,

    // State
    state,
    setIsFocused,

    // Mutations
    postCommentMutation,
    replyCommentMutation,

    // Actions
    fetchNextPage: handleFetchNextPage,

    // Handlers
    handlers,

    // Permissions
    canReact,
    canManageComments,

    // Context info
    config,
  };
};
