import { type FC, Suspense, useMemo } from 'react';

import { type AxiosResponse } from 'axios';
import Box from '@material-hu/mui/Box';
import Stack from '@material-hu/mui/Stack';

import HuSpinner from '@material-hu/components/design-system/ProgressIndicators/Spinner';

import { useAuth } from 'src/contexts/JWTContext';
import useCommunityFeature from 'src/hooks/useCommunityFeature';
import { type UsePostReactionsReturn } from 'src/hooks/usePostReactions';
import { feedKeys } from 'src/pages/dashboard/feed/queries';
import { groupsKeys } from 'src/pages/dashboard/groups/queries';
import {
  getGroupLiveStreamPoll,
  getTranslatedPost as getTranslatedPostForGroup,
  joinLiveStream as joinGroupLiveStream,
  voteGroupLiveStreamPoll,
} from 'src/services/groups';
import {
  getPostLiveStreamPoll,
  getTranslatedPost as getTranslatedPostForFeed,
  joinLiveStream as joinFeedLiveStream,
  votePostLiveStreamPoll,
} from 'src/services/posts';
import { CommunityFeature } from 'src/types/communityFeatures';
import { type Post } from 'src/types/posts';
import { type JoinLivestreamResponse } from 'src/types/stream';
import { lazyRetry } from 'src/utils/lazyRetry';

import PostBody from './PostBody';
import PostTranslate from './PostTranslate';

const PostPlayerStreaming = lazyRetry(
  () => import('src/pages/dashboard/feed/components/PostPlayerStreaming'),
);

const MAX_CHARACTERS_LIMIT = 250;
const MAX_NEW_LINES_LIMIT = 4;

export type PostCardContentProps = Pick<
  Post,
  | 'body'
  | 'bodyHtml'
  | 'bodyAttributes'
  | 'languageCode'
  | 'stream'
  | 'reactions'
  | 'updatedAt'
  | 'createdAt'
  | 'commentCount'
  | 'commentsEnabled'
> & {
  postId: Post['id'];

  // Stream
  hasAttachments?: boolean;

  // Context
  groupId?: number | string;
  groupTitle?: string;

  // Reactions handlers for streaming
  onAddReaction?: UsePostReactionsReturn['handleAddReaction'];
  onRemoveReaction?: UsePostReactionsReturn['handleRemoveReaction'];
  getReactionUsers?: UsePostReactionsReturn['getReactionUsers'];

  // Post data for streaming component
  user?: Post['user'];

  // UI options
  matchText?: string;
  hideTranslation?: boolean;
  showSeeMoreToggle?: boolean;
  onShowMore?: () => void;
  onShowLess?: () => void;
};

export const PostCardContent: FC<PostCardContentProps> = ({
  postId,
  body,
  bodyHtml,
  bodyAttributes,
  languageCode,
  stream,
  hasAttachments = false,
  groupId,
  groupTitle,
  reactions,
  onAddReaction,
  onRemoveReaction,
  getReactionUsers,
  user,
  updatedAt,
  createdAt,
  commentCount,
  commentsEnabled,
  matchText = '',
  hideTranslation = false,
  showSeeMoreToggle,
  onShowMore,
  onShowLess,
}) => {
  const { user: loggedUser } = useAuth();
  const canTranslate = useCommunityFeature(CommunityFeature.TRANSLATE_POSTS);

  const isFeedPage = !groupId;

  // Determine if translation should be shown
  const allowTranslation = useMemo(
    () =>
      !hideTranslation &&
      canTranslate &&
      body &&
      body.length > 0 &&
      languageCode &&
      loggedUser &&
      loggedUser.postTranslationLanguage &&
      languageCode !== loggedUser.postTranslationLanguage,
    [hideTranslation, body, languageCode, loggedUser?.postTranslationLanguage],
  );

  // Translation query key
  const translateKey = useMemo(
    () =>
      isFeedPage
        ? feedKeys.translate.detail(postId)
        : groupsKeys.translate.detail(String(groupId), postId),
    [isFeedPage, postId, groupId],
  );

  // Translation fetch function
  const getTranslatedPost = useMemo(
    () =>
      isFeedPage
        ? getTranslatedPostForFeed
        : (id: number) => getTranslatedPostForGroup(String(groupId), id),
    [isFeedPage, groupId],
  );

  // Live stream join function
  const joinLiveStreamRoom = useMemo(
    (): (() => Promise<AxiosResponse<JoinLivestreamResponse>>) =>
      isFeedPage
        ? () => joinFeedLiveStream(postId)
        : () => joinGroupLiveStream(Number(groupId), postId),
    [isFeedPage, postId, groupId],
  );

  // Should show streaming player
  const showStreamingPlayer = stream && !hasAttachments;

  // Reactions handlers for streaming component
  const reactionsHandlers = useMemo(
    () =>
      getReactionUsers && onAddReaction && onRemoveReaction
        ? {
            getReactionUsers,
            handleAddReaction: onAddReaction,
            handleRemoveReaction: onRemoveReaction,
          }
        : undefined,
    [getReactionUsers, onAddReaction, onRemoveReaction],
  );

  return (
    <>
      <Box sx={{ px: 2 }}>
        <PostBody
          bodyHtml={bodyHtml}
          body={body}
          bodyAttributes={bodyAttributes}
          maxCharacters={MAX_CHARACTERS_LIMIT}
          maxNewLines={MAX_NEW_LINES_LIMIT}
          matchText={matchText}
          onReadMore={onShowMore}
          onReadLess={onShowLess}
          showSeeMoreToggle={showSeeMoreToggle}
          readOnlyShowSeeMoreButton={showSeeMoreToggle}
        />
        {showStreamingPlayer && user && reactionsHandlers && (
          <Suspense fallback={<HuSpinner />}>
            <Stack sx={{ mt: 1 }}>
              <PostPlayerStreaming
                stream={stream}
                post={{
                  user,
                  group: groupId
                    ? { id: String(groupId), title: groupTitle }
                    : undefined,
                  updatedAt,
                  createdAt,
                  reactions,
                  id: postId,
                  commentCount,
                  commentsEnabled,
                  body,
                  bodyAttributes,
                  bodyHtml,
                }}
                reactionsHandlers={reactionsHandlers}
                joinLiveStreamRoom={joinLiveStreamRoom}
                pollService={
                  isFeedPage
                    ? {
                        get: () => getPostLiveStreamPoll(postId),
                        vote: (pollId: number, pollOptionId: number) =>
                          votePostLiveStreamPoll(postId, pollId, pollOptionId),
                        key: feedKeys.poll.livestream(stream.id),
                      }
                    : {
                        get: () =>
                          getGroupLiveStreamPoll(postId, Number(groupId)),
                        vote: (pollId: number, pollOptionId: number) =>
                          voteGroupLiveStreamPoll(
                            postId,
                            Number(groupId),
                            pollId,
                            pollOptionId,
                          ),
                        key: groupsKeys.poll.livestream(stream.id),
                      }
                }
              />
            </Stack>
          </Suspense>
        )}
      </Box>
      {allowTranslation && (
        <PostTranslate
          postId={postId}
          translateKey={translateKey}
          getTranslatedPost={getTranslatedPost}
        />
      )}
    </>
  );
};

export default PostCardContent;
