import { useQuery } from 'react-query';
import { useLocation, useNavigate, useParams } from 'react-router-dom';

import { type AxiosResponse } from 'axios';
import { IconStar, IconUsersGroup } from '@material-hu/icons/tabler';

import {
  eventsKeys,
  unshiftEventPostComment,
} from 'src/pages/dashboard/events/queries';
import {
  feedKeys,
  refetchAllPosts,
  unshiftComment,
} from 'src/pages/dashboard/feed/queries';
import { feedRoutes } from 'src/pages/dashboard/feed/routes';
import {
  groupsKeys,
  invalidateGroupDetails,
  unshiftGroupComment,
} from 'src/pages/dashboard/groups/queries';
import { groupsRoutes } from 'src/pages/dashboard/groups/routes';
import {
  createPost as createEventPost,
  deletePost as deleteEventPost,
  getEvent,
  getPost as getEventPost,
  getEventPostCommentsPaginated,
  joinEventSocketRoom,
  postEventComment,
} from 'src/services/events';
import {
  createGroupPost,
  deleteGroupPost,
  getGroupDetails,
  getGroupPostCommentsPaginated,
  getGroupPostDetails,
  joinLiveStream,
  postGroupComment,
} from 'src/services/groups';
import {
  createPost as createFeedPost,
  deletePost as deleteFeedPost,
  enableOrDisableCommentsPost,
  getPostCommentsPaginated as getFeedPostCommentsPaginated,
  getById as getFeedPostDetail,
  joinLiveStream as joinPostLiveStream,
  postComment as postFeedComment,
} from 'src/services/posts';
import { Comment } from 'src/types/comments';
import { EventPostType } from 'src/types/events';
import { GroupCommentList } from 'src/types/groups';
import { PostData } from 'src/types/posts';
import {
  DestinationActions,
  DestinationDetails,
  DestinationKeys,
  StreamDestination,
  StreamDestinationInfo,
} from 'src/types/stream';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { getListLength, getNextPage } from 'src/utils/pagination';

import { eventsRoutes } from '../../events/routes';
import { getLiveStreamDestination } from '../utils';

export const useStreamDestination = (): StreamDestinationInfo => {
  const { id } = useParams();
  const { pathname } = useLocation();
  const { t } = useLokaliseTranslation('livestream');
  const navigate = useNavigate();

  const destination = getLiveStreamDestination(pathname);

  const { data: groupDetailsData, isLoading: isLoadingGroupDetails } = useQuery(
    groupsKeys.detail(id!),
    () => getGroupDetails(id!),
    {
      enabled: destination === StreamDestination.GROUPS && !!id,
    },
  );

  const { data: eventDetailsData, isLoading: isLoadingEventDetails } = useQuery(
    eventsKeys.event(id!),
    () => getEvent(Number(id!)),
    {
      enabled: destination === StreamDestination.EVENTS && !!id,
    },
  );

  const detailsByDestination: Record<
    StreamDestination,
    DestinationDetails | undefined
  > = {
    [StreamDestination.GROUPS]: groupDetailsData?.data
      ? {
          id: groupDetailsData.data.id,
          icon: groupDetailsData.data.icon,
          avatar: !groupDetailsData.data.icon
            ? { Icon: IconUsersGroup }
            : undefined,
          title: groupDetailsData.data.title,
          description: t(
            `group:groups_group_title_${groupDetailsData.data.privacyPolicy.toLowerCase()}`,
          ),
          supportDisableComments: false,
          hideAddTitleBox: false,
          hideViewPostButton: false,
        }
      : undefined,
    [StreamDestination.EVENTS]: eventDetailsData?.data
      ? {
          id: eventDetailsData.data.id,
          avatar: {
            src: eventDetailsData.data.coverPictureUrl ?? '',
            Icon: IconStar,
          },
          title: eventDetailsData.data.name,
          description: eventDetailsData.data.group
            ? t(`GROUP`, {
                group: eventDetailsData.data.group.title,
              })
            : '',
          supportDisableComments: false,
          hideAddTitleBox: true,
          hideViewPostButton: true,
          goBackText: t('go_back_to_event'),
        }
      : undefined,
    [StreamDestination.FEED]: undefined,
  };

  const actionsByDestination: Record<StreamDestination, DestinationActions> = {
    [StreamDestination.GROUPS]: {
      commentPost: (postId, data) =>
        postGroupComment(postId, data, detailsByDestination.GROUPS!.id),
      createPost: data =>
        createGroupPost(detailsByDestination.GROUPS!.id, data as PostData),
      deletePost: postId =>
        deleteGroupPost(postId, detailsByDestination.GROUPS!.id),
      getNextPage: (lastPage: AxiosResponse<GroupCommentList | Comment[]>) =>
        'cursor' in lastPage.data && lastPage.data.cursor
          ? lastPage.data.cursor
          : undefined,
      getPostById: postId =>
        getGroupPostDetails(detailsByDestination.GROUPS!.id, postId),
      getPostComments: (postId, limit, page = '') =>
        getGroupPostCommentsPaginated(
          postId,
          page,
          detailsByDestination.GROUPS!.id,
          limit,
        ),
      goToDestination: () =>
        navigate(groupsRoutes.detail(detailsByDestination.GROUPS!.id)),
      invalidateQueries: () =>
        invalidateGroupDetails(detailsByDestination.GROUPS!.id),
      transformPostComments: (
        pages?: AxiosResponse<GroupCommentList | Comment[]>[],
      ) =>
        pages
          ?.flatMap(page =>
            Array.isArray(page.data) ? page.data : page.data.items,
          )
          .toReversed() || [],
      unshiftComment: (postId, comment) =>
        unshiftGroupComment(
          postId,
          String(detailsByDestination.GROUPS!.id),
          comment,
        ),
      viewPost: postId =>
        navigate(
          groupsRoutes.post.detail(detailsByDestination.GROUPS!.id, postId),
        ),
      joinLiveStream: postId =>
        joinLiveStream(detailsByDestination.GROUPS!.id, postId),
    },
    [StreamDestination.FEED]: {
      commentPost: (postId, data) => postFeedComment(postId, data),
      createPost: data => createFeedPost(data as PostData),
      deletePost: postId => deleteFeedPost(postId),
      toggleComments: (postId, enable) =>
        enableOrDisableCommentsPost(postId, enable),
      getNextPage: (lastPage, pages, limit) =>
        pages && limit
          ? getNextPage(getListLength(pages), limit, pages)
          : undefined,
      getPostById: postId => getFeedPostDetail(postId),
      getPostComments: (postId, limit, page = 1) =>
        getFeedPostCommentsPaginated(postId, page, limit),
      goToDestination: () => navigate(feedRoutes.feed()),
      invalidateQueries: () => refetchAllPosts(),
      transformPostComments: (
        pages?: AxiosResponse<GroupCommentList | Comment[]>[],
      ) =>
        pages
          ?.flatMap(page =>
            Array.isArray(page.data) ? page.data : page.data.items,
          )
          .toReversed() || [],
      unshiftComment: (postId, comment) => unshiftComment(postId, comment),
      viewPost: postId => navigate(feedRoutes.post.detail(postId)),
      joinLiveStream: postId => joinPostLiveStream(postId),
    },
    [StreamDestination.EVENTS]: {
      commentPost: (postId, data) =>
        postEventComment(detailsByDestination.EVENTS!.id, postId, data),
      createPost: data =>
        createEventPost(
          detailsByDestination.EVENTS!.id,
          data as Partial<EventPostType>,
        ),
      deletePost: postId =>
        deleteEventPost(detailsByDestination.EVENTS!.id, postId),
      getNextPage: (lastPage: AxiosResponse<GroupCommentList | Comment[]>) =>
        'cursor' in lastPage.data && lastPage.data.cursor
          ? lastPage.data.cursor
          : undefined,
      getPostById: postId =>
        getEventPost(detailsByDestination.EVENTS!.id, postId),
      getPostComments: (postId, limit, page = '') =>
        getEventPostCommentsPaginated(
          detailsByDestination.EVENTS!.id,
          postId,
          page,
          limit,
        ),
      goToDestination: () =>
        navigate(eventsRoutes.event(detailsByDestination.EVENTS!.id)),
      transformPostComments: (
        pages?: AxiosResponse<GroupCommentList | Comment[]>[],
      ) =>
        pages
          ?.flatMap(page =>
            Array.isArray(page.data) ? page.data : page.data.items,
          )
          .toReversed() || [],
      unshiftComment: (postId, comment) =>
        unshiftEventPostComment(
          postId,
          detailsByDestination.EVENTS!.id,
          comment,
        ),
      viewPost: () => {},
      invalidateQueries: () => {},
      joinLiveStream: () =>
        joinEventSocketRoom(detailsByDestination.EVENTS!.id),
    },
  };

  const keysByDestination: Record<StreamDestination, DestinationKeys> = {
    [StreamDestination.GROUPS]: {
      commentsDetail: postId =>
        groupsKeys.comment.liveStream(
          postId,
          String(detailsByDestination.GROUPS!.id),
        ),
      postDetail: postId =>
        groupsKeys.postDetail(
          detailsByDestination.GROUPS!.id.toString(),
          postId.toString(),
        ),
    },
    [StreamDestination.FEED]: {
      commentsDetail: postId => feedKeys.comment.liveStream(postId),
      postDetail: postId => feedKeys.detail(postId),
    },
    [StreamDestination.EVENTS]: {
      commentsDetail: postId => eventsKeys.comment.liveStream(postId),
      postDetail: postId =>
        eventsKeys.postDetail(
          detailsByDestination.EVENTS!.id.toString(),
          postId.toString(),
        ),
    },
  };

  return {
    destination,
    details: detailsByDestination[destination],
    actions: actionsByDestination[destination],
    keys: keysByDestination[destination],
    isLoading: isLoadingGroupDetails || isLoadingEventDetails,
  };
};
