import { RefObject } from 'react';
import { InfiniteData } from 'react-query';

import { AxiosResponse } from 'axios';

import { queryClient } from 'src/config/react-query';
import { marketplaceKeys } from 'src/pages/dashboard/marketplace/queries';
import { Comment } from 'src/types/comments';
import { GroupCommentList, GroupPost } from 'src/types/groups';
import { MarketplacePost } from 'src/types/marketplace';
import { Post } from 'src/types/posts';
import { DataUpdate, Updater } from 'src/types/queries';
import { findPostIndexOnPages } from 'src/utils/feed';
import { functionalUpdate } from 'src/utils/queries';

import {
  pushLastCommentData,
  pushLastCommentDataDetail,
} from 'src/components/comments/queries';

export const getCommentType = (path: string) => {
  if (path.includes('feed')) {
    return 'post';
  }

  if (path.includes('news')) {
    return 'article';
  }

  return null;
};

export const getCommentsList = (
  data: InfiniteData<AxiosResponse<Comment[] | GroupCommentList>> | undefined,
) => {
  return (
    data?.pages.flatMap(page =>
      'items' in page.data ? page.data.items : page.data,
    ) || []
  );
};

export const unshiftCommentUpdater = <PostType extends Post | GroupPost>(
  oldPost: PostType | undefined,
  comment: Comment,
) => {
  if (!oldPost) return oldPost;

  const lastComments = oldPost.lastComments || [];

  if (!includesComment(lastComments, comment)) {
    // Return new object reference for React Query to detect the change
    return {
      ...oldPost,
      commentCount: increaseCommentCount(oldPost.commentCount),
      lastComments: [comment, ...lastComments],
    };
  }

  return oldPost;
};

export const lastCommentUpdater = <PostType extends Post | GroupPost>(
  oldPost: DataUpdate<PostType>,
  commentId: number,
  updater: Updater<Comment>,
) => {
  if (!oldPost?.lastComments) return oldPost;

  const commentIndex = oldPost.lastComments.findIndex(
    comment => comment.id === commentId,
  );

  if (commentIndex !== -1) {
    oldPost.lastComments[commentIndex] = functionalUpdate(
      updater,
      oldPost.lastComments[commentIndex],
    );
  }

  return oldPost;
};

export const unshiftChildUpdater = (
  oldComment: DataUpdate<Comment>,
  childComment: Comment,
): DataUpdate<Comment> => {
  if (!oldComment) return oldComment;

  if (!oldComment.children) {
    oldComment.children = [];
  }

  if (!includesComment(oldComment.children, childComment)) {
    oldComment.childrenNumber = increaseCommentCount(oldComment.childrenNumber);
    oldComment.children.unshift(childComment);
  }

  return oldComment;
};

export const getCurrentCommentsCount = (
  data: InfiniteData<AxiosResponse<Comment[] | GroupCommentList>> | undefined,
) => {
  let counter = 0;

  data?.pages.forEach(
    page =>
      (counter +=
        'items' in page.data ? page.data.items.length : page.data.length),
  );

  return counter;
};

export const onAddComment = (
  id: number,
  data: Comment,
  isPostDetail = false,
) => {
  if (isPostDetail) {
    pushLastCommentDataDetail(id, data);
  } else {
    pushLastCommentData(id, data);
  }
};

export const isCurrentComment = (postId: number, commentId: number) => {
  const data = queryClient.getQueryData<
    InfiniteData<AxiosResponse<MarketplacePost[]>>
  >(marketplaceKeys.list());
  if (!data) return false;

  const [pageIndex, postIndex] = findPostIndexOnPages(postId, data.pages);

  if (pageIndex !== -1 && postIndex !== -1) {
    const indexAux = data.pages[pageIndex].data[
      postIndex
    ].lastComments?.findIndex(elem => elem.id === commentId);
    if (indexAux !== -1) {
      return true;
    }
  }

  return false;
};

export const isCurrentCommentPostDetail = (
  postId: number,
  commentId: number,
) => {
  const data = queryClient.getQueryData<AxiosResponse<MarketplacePost>>(
    marketplaceKeys.detail(postId),
  );
  if (!data) return false;

  const indexAux = data.data.lastComments.findIndex(
    elem => elem.id === commentId,
  );

  return indexAux !== -1 && indexAux !== undefined;
};

export const decreaseCommentCount = (commentCount: number | undefined) => {
  if (!commentCount || commentCount <= 0) return 0;
  return commentCount - 1;
};

export const increaseCommentCount = (commentCount: number | undefined) => {
  if (!commentCount || commentCount <= 0) return 1;
  return commentCount + 1;
};

export const includesComment = (
  commentList: Comment[],
  commentSearch: Comment,
) => {
  if (!commentList || !commentSearch) return false;

  return commentList.some(comment => comment.id === commentSearch.id);
};

export const getCommentToScrollRef = (
  commentId: number,
  parentId: string | null,
  commentToScrollRef: RefObject<any>,
) => {
  if (!parentId || Number(parentId) !== commentId) return null;
  return commentToScrollRef;
};
