import { type FC, Fragment, useState } from 'react';
import { useInfiniteQuery, useMutation } from 'react-query';

import { useModal } from '@material-hu/hooks/useModal';
import { IconMessage2 } from '@material-hu/icons/tabler';
import Stack from '@material-hu/mui/Stack';
import { type CompleteFile } from '@material-hu/types/attachments';

import HuDialog from '@material-hu/components/design-system/Dialog';
import useHuSnackbar from '@material-hu/components/design-system/Snackbar';
import HuTitle from '@material-hu/components/design-system/Title';

import useFeatureFlag from 'src/hooks/useFeatureFlag';
import usePermissions from 'src/hooks/usePermissions';
import {
  createPost,
  deletePost,
  editPost,
  getEventPosts,
} from 'src/services/events';
import { FileTypes } from 'src/types/attachments';
import {
  type Event,
  EventFeedPublishPolicy,
  type EventPostType,
} from 'src/types/events';
import { FeatureFlags } from 'src/types/featureFlags';
import { StreamStatus } from 'src/types/stream';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { UserPermissions } from 'src/utils/permissions';

import { InfiniteList } from 'src/components/list';
import UnifiedPostCard from 'src/components/post/UnifiedPostCard';

import { useEventOrganizers } from '../hooks/useEventOrganizers';
import { useInvalidateEvent } from '../hooks/useInvalidateEvent';
import {
  useEventLivestreamSocket,
  useEventPostCommentsSocket,
  useEventRoom,
  usePostsSocket,
} from '../hooks/useSockets';
import { eventsKeys } from '../queries';
import { useIsEventCreator, useIsEventsManager } from '../utils';

import EmptyState from './EmptyState';
import { EventPost } from './EventPost';
import { EventPostCreate } from './EventPostCreate';
import { StartLivestreamCard } from './StartLivestreamCard';
import FeedPostSkeleton from './skeleton/FeedPostSkeleton';

type Props = {
  event: Event;
  isLivestreamActive: boolean;
};

export const EventFeed: FC<Props> = props => {
  const { event, isLivestreamActive } = props;
  const { t } = useLokaliseTranslation('events');
  const { enqueueSnackbar } = useHuSnackbar();
  const isEventManager = useIsEventsManager();
  const isEventCreator = useIsEventCreator(event);
  const invalidateEvent = useInvalidateEvent(event.id);
  const isEventsNewFeatures = useFeatureFlag(
    FeatureFlags.EVENTS_COMMENTS_ENABLED,
  );
  const isMultipleOrganizersEnabled = useFeatureFlag(
    FeatureFlags.EVENTS_MULTIPLE_ORGANIZERS_ENABLED,
  );
  const isEventLivestreamEnabled = useFeatureFlag(
    FeatureFlags.EVENTS_LIVESTREAM_ENABLED,
  );
  const { hasAll: hasLivestreamPermission } = usePermissions([
    UserPermissions.CREATE_LIVESTREAM,
    UserPermissions.VIEW_LIVESTREAM,
  ]);
  const { isCoOrganizer } = useEventOrganizers(event);

  const canCreatePost = isMultipleOrganizersEnabled
    ? event.feedPublishPolicy === EventFeedPublishPolicy.ALL_INVITES ||
      isCoOrganizer ||
      isEventCreator
    : isEventManager || isEventCreator;
  const canCreateLivestream =
    isEventLivestreamEnabled &&
    event.liveStream &&
    hasLivestreamPermission &&
    (isCoOrganizer || isEventCreator);

  const [editingPostId, setEditingPostId] = useState<number | null>(null);

  const mutation = useMutation((data: Partial<EventPostType>) => {
    const attachments = [...(data.media || []), ...(data.files || [])].map(
      q => q.attachment,
    );
    return createPost(event.id, { body: data.body, attachments });
  });

  const editPostMutation = useMutation(
    ({ postId, data }: { postId: number; data: Partial<EventPostType> }) => {
      const attachments = [...(data.media || []), ...(data.files || [])].map(
        q => ({
          ...q.attachment,
          url: q.attachment.url.split('?')[0],
        }),
      );

      return editPost(event.id, postId, { ...data, attachments });
    },
    {
      onSuccess: () => {
        setEditingPostId(null);
        invalidateEvent();
        enqueueSnackbar({ title: t('POST_EDITED'), variant: 'success' });
      },
    },
  );

  const allPosts = useInfiniteQuery(
    eventsKeys.eventPosts(event.id),
    ({ pageParam = '' }) => getEventPosts(event.id, pageParam),
    {
      getNextPageParam: lastPage => lastPage?.data?.cursor,
      cacheTime: 0,
      select: data => ({
        ...data,
        pages: data.pages.map(page => ({
          ...page,
          data: {
            ...page.data,
            items: page.data.items.map(item => {
              const media: CompleteFile[] = [];
              const files: CompleteFile[] = [];

              item.attachments.forEach(attachment => {
                if (
                  [FileTypes.IMAGE, FileTypes.VIDEO].includes(
                    attachment.type,
                  ) &&
                  attachment.id &&
                  attachment.url
                ) {
                  media.push({
                    id: attachment.id,
                    attachment: {
                      url: attachment.url,
                      name: attachment.name ?? '',
                      type: attachment.type,
                      size: attachment.size ?? '',
                      bytes: attachment.bytes ?? 0,
                    },
                  });
                } else if (
                  attachment.type === FileTypes.FILE &&
                  attachment.id &&
                  attachment.url
                ) {
                  files.push({
                    id: attachment.id,
                    attachment: {
                      url: attachment.url,
                      name: attachment.name ?? '',
                      type: attachment.type,
                      size: attachment.size ?? '',
                      bytes: attachment.bytes ?? 0,
                    },
                  });
                }
              });

              return {
                ...item,
                media,
                files,
              };
            }),
          },
        })),
      }),
    },
  );

  usePostsSocket(allPosts.refetch, event.id);
  useEventRoom(event.id);
  useEventPostCommentsSocket(event.id);
  useEventLivestreamSocket(event.id);

  const deletePostMutation = useMutation(
    (post: EventPostType) => deletePost(event.id, post.id),
    {
      onSuccess: () => {
        invalidateEvent();
        enqueueSnackbar({ title: t('POST_DELETED'), variant: 'success' });
      },
    },
  );

  const handleEditPost = (post: EventPostType) => {
    setEditingPostId(post.id);
  };

  const handleDeletePost = (post: EventPostType) => {
    deletePostModal.showModal({ post });
  };

  const deletePostModal = useModal<{ post: EventPostType }>(({ post }) => (
    <HuDialog
      title={t('DELETE_POST_SURE')}
      textBody={t('DELETE_POST_SURE_DESCRIPTION')}
      onClose={deletePostModal.closeModal}
      primaryButtonProps={{
        children: t('ELIMINATE'),
        onClick: () =>
          deletePostMutation.mutate(post, {
            onSettled: deletePostModal.closeModal,
          }),
        loading: deletePostMutation.isLoading,
      }}
      secondaryButtonProps={{
        children: t('CANCEL'),
        onClick: deletePostModal.closeModal,
        disabled: deletePostMutation.isLoading,
      }}
    />
  ));

  const isEmpty =
    allPosts.isSuccess && !allPosts.data?.pages[0]?.data?.items?.length;

  return (
    <Stack
      sx={{
        gap: 2,
        mt: 2,
      }}
    >
      {deletePostModal.modal}
      <HuTitle
        variant="L"
        title={t('EVENT_FEED')}
        sx={{ mb: 1 }}
      />
      {canCreateLivestream && (
        <StartLivestreamCard
          eventId={event.id}
          isLivestreamActive={isLivestreamActive}
        />
      )}
      {canCreatePost && allPosts.isSuccess && (
        <EventPostCreate handlePost={post => mutation.mutateAsync(post)} />
      )}
      <InfiniteList
        isEmpty={isEmpty}
        isSuccess={allPosts.isSuccess}
        isLoading={allPosts.isLoading}
        fetchNextPage={allPosts.fetchNextPage}
        hasNextPage={allPosts.hasNextPage}
        isFetchingNextPage={allPosts.isFetchingNextPage}
        noResultsLabel={
          <EmptyState
            Icon={IconMessage2}
            sx={{ mt: 2 }}
            titleProps={{
              title: t('EVENT_FEED_EMPTY'),
              description: t('EVENT_FEED_EMPTY_DESCRIPTION'),
            }}
          />
        }
        renderSkeleton={<FeedPostSkeleton />}
        loadingSkeleton={allPosts.isLoading}
      >
        {isEventsNewFeatures && (
          <Stack sx={{ gap: 2 }}>
            {allPosts.data?.pages
              ?.flatMap(page => page.data.items)
              .map(post => (
                <Fragment key={post.id}>
                  {editingPostId === post.id && (
                    <EventPostCreate
                      handlePost={newPost =>
                        editPostMutation.mutateAsync({
                          postId: post.id,
                          data: newPost,
                        })
                      }
                      existingPost={post}
                      onCancel={() => setEditingPostId(null)}
                      sx={{ my: 4 }}
                    />
                  )}
                  {editingPostId !== post.id &&
                    post.stream?.status !== StreamStatus.LIVE && (
                      <UnifiedPostCard
                        context="events"
                        post={post}
                        eventId={event.id}
                        isEventManager={isEventManager}
                        isEventCreator={isEventCreator}
                        onEditPost={handleEditPost}
                        onDeletePost={handleDeletePost}
                        onAddReaction={() => allPosts.refetch()}
                        onRemoveReaction={() => allPosts.refetch()}
                      />
                    )}
                </Fragment>
              ))}
          </Stack>
        )}
        {!isEventsNewFeatures &&
          allPosts.data?.pages
            .flatMap(page => page.data.items)
            .map(post => (
              <EventPost
                event={event}
                post={post}
                key={post.id}
                refetchPosts={allPosts.refetch}
              />
            ))}
      </InfiniteList>
    </Stack>
  );
};
