import { forwardRef, useCallback, useMemo, useState } from 'react';
import { useMutation, useQuery } from 'react-query';

import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';

import { logEvent } from 'src/config/logging';
import { useAuth } from 'src/contexts/JWTContext';
import useFeatureFlag from 'src/hooks/useFeatureFlag';
import useGeneralError from 'src/hooks/useGeneralError';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import { ButtonText } from 'src/pages/dashboard/feed/components/ButtonText';
import { getGif } from 'src/services/attachments';
import {
  addEventPostCommentReaction,
  getEventPostCommentReactionUsers,
  removeEventPostCommentReaction,
} from 'src/services/events';
import {
  addGroupCommentReaction,
  getGroupCommentReactionUsers,
  removeGroupCommentReaction,
} from 'src/services/groups';
import {
  addCommentReaction,
  getCommentReactionUsers,
  removeCommentReaction,
} from 'src/services/posts';
import { EventName } from 'src/types/amplitude';
import { FileTypes } from 'src/types/attachments';
import { Comment as CommentType } from 'src/types/comments';
import { FeatureFlags } from 'src/types/featureFlags';
import { DEFAULT_EMOJI } from 'src/types/feed';
import { getFormFileFromAttachment } from 'src/utils/files';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { canAddReaction } from 'src/utils/reactions';

import { File, MediaCarousel } from 'src/components/attachment';
import Gif from 'src/components/attachment/Gif';
import { attachmentKeys } from 'src/components/attachment/queries';
import CommentEdit from 'src/components/comments/CommentEdit';
import { ReactionsList } from 'src/components/dashboard/reactions';
import { invalidateReactionUserList } from 'src/components/dashboard/reactions/queries';
import PostText from 'src/components/post/PostText';
import TimeDistance from 'src/components/time/TimeDistance';
import ProfilePicture from 'src/components/user/ProfilePicture';

import { usePost } from '../post/PostContext';
import { UserNameLink } from '../UserNameLink';

import CommentActions from './CommentActions';
import { computeCommentPermissions } from './commentPermissions';

export type CommentProps = {
  comment: CommentType;
  postId: number;
  context: string;
  canManageComments?: boolean;
  canReact?: boolean;
  onDelete: (id: number, parentId: number | null) => void;
  onEdit: (commentData: CommentType) => void;
  onReply: (
    id: number,
    parentId: number | null,
    user: CommentType['user'],
  ) => void;
  onRemoveReaction: (
    id: number,
    parentId: number | null,
    emoji: string,
  ) => void;
  onAddReaction: (
    id: number,
    parentId: number | null,
    emoji: string,
    unified: string,
  ) => void;
  maxAttachmentsBytes: number;
  // Group-specific props
  isGroupArchived?: boolean;
  userIsMember?: boolean;
  isGroupAdmin?: boolean;
};

const MAX_CHARACTERS_LIMIT = 150;
const MAX_NEW_LINES_LIMIT = 2;

export const Comment = forwardRef<HTMLInputElement, CommentProps>(
  function CommentComponent(props, ref) {
    const {
      comment,
      postId,
      context,
      onDelete,
      onEdit,
      onReply,
      onRemoveReaction,
      onAddReaction,
      maxAttachmentsBytes,
      canManageComments,
      canReact: canReactProp,
      isGroupArchived,
      userIsMember,
      isGroupAdmin,
    } = props;

    const {
      id,
      body,
      bodyAttributes,
      createdAt,
      attachments,
      reactions,
      user,
      parentId,
    } = comment;

    const [toEdit, setToEdit] = useState(false);

    const showGeneralError = useGeneralError();

    const isMultipleEventOrganizersEnabled = useFeatureFlag(
      FeatureFlags.EVENTS_MULTIPLE_ORGANIZERS_ENABLED,
    );

    const { t } = useLokaliseTranslation(['web_only']);
    const HugoThemeProvider = useHuGoTheme();
    const theme = useTheme();
    const { user: loggedUser } = useAuth();
    const { groupId, eventId } = usePost();
    const isFeedPost = !groupId && !eventId;

    const isGroupComment = groupId !== undefined;
    const isEventComment = eventId !== undefined;

    // Compute permissions using centralized logic
    const permissions = computeCommentPermissions({
      context,
      loggedUserId: loggedUser?.id,
      commentUserId: user.id,
      isGroupComment,
      isGroupArchived,
      userIsMember,
      isGroupAdmin,
      canManageComments,
      canReact: canReactProp,
      links: isMultipleEventOrganizersEnabled ? comment._links : undefined,
    });

    const { canDelete, canReact, canEdit, canReply } = permissions;

    const gif = attachments?.find(
      attachment => attachment.type === FileTypes.GIF,
    );
    const gifId = gif?.externalReference?.id;

    const { data: gifInfo } = useQuery(
      attachmentKeys.gif(gifId!),
      () => getGif(gifId!),
      { enabled: !!gifId },
    );

    const addReactionMutation = useMutation(
      ({ emoji, unified }: any) => {
        if (isEventComment) {
          return addEventPostCommentReaction(
            eventId!,
            postId,
            comment.id,
            emoji,
            unified,
          );
        }
        if (isGroupComment) {
          return addGroupCommentReaction(
            comment.id,
            postId,
            groupId!,
            emoji,
            unified,
          );
        }
        return addCommentReaction(id, emoji, unified);
      },
      {
        onMutate: ({ emoji, unified }) => {
          onAddReaction(id, parentId, emoji, unified);
        },
        onSuccess: (_, { emoji }) => {
          invalidateReactionUserList(comment.id, emoji);

          if (eventId !== undefined) {
            logEvent(EventName.EVENT_POST_COMMENT_REACTION, {
              postId,
              commentId: id,
              reaction: emoji,
              eventId,
              isChildComment: !!parentId,
            });
          } else if (groupId !== undefined) {
            logEvent(EventName.GROUPS_POST_COMMENT_REACTIONED, {
              postId,
              commentId: id,
              reaction: emoji,
              groupId,
              isChildComment: !!parentId,
            });
          } else {
            logEvent(EventName.POST_COMMENT_REACTION, {
              postId,
              commentId: id,
              reaction: emoji,
              isChildComment: !!parentId,
            });
          }
        },
        onError: (err, { emoji }) => {
          onRemoveReaction(id, parentId, emoji);
          showGeneralError(err, t('web_only:reactions.add_reaction_error'));
        },
      },
    );
    const removeReactionMutation = useMutation(
      (emoji: string) => {
        if (isEventComment) {
          return removeEventPostCommentReaction(eventId!, postId, id, emoji);
        }
        if (isGroupComment) {
          return removeGroupCommentReaction(id, postId, groupId!, emoji);
        }
        return removeCommentReaction(id, emoji);
      },
      {
        onMutate: emoji => {
          const unified = reactions?.find(r => r.emoji === emoji)?.unified;
          onRemoveReaction(id, parentId, emoji);
          return { unified };
        },
        onSuccess: (_, emoji) => {
          invalidateReactionUserList(comment.id, emoji);
        },
        onError: (err, emoji, context) => {
          if (context?.unified) {
            onAddReaction(id, parentId, emoji, context.unified);
          }
          showGeneralError(err, t('web_only:reactions.remove_reaction_error'));
        },
      },
    );

    const getReactionUsers = useCallback(
      (emoji: string, params?: { timestamp?: string; cursor?: string }) => {
        if (isEventComment) {
          return getEventPostCommentReactionUsers(
            eventId!,
            postId,
            id,
            emoji,
            params?.cursor ?? '',
          );
        }
        if (isGroupComment) {
          return getGroupCommentReactionUsers(
            postId,
            groupId!,
            id,
            emoji,
            params?.cursor ?? '',
          );
        }
        return getCommentReactionUsers(id, emoji, params?.timestamp);
      },
      [postId, groupId, eventId, id, isFeedPost, isEventComment],
    );

    const handleEditOpen = () => setToEdit(true);
    const handleEditClose = () => setToEdit(false);

    const handleAddReaction = useCallback(
      async (emoji: string, unified: string) => {
        if (!canAddReaction(reactions, emoji)) return;

        await addReactionMutation.mutateAsync({ emoji, unified });
      },
      [reactions],
    );

    const handleRemoveReaction = useCallback(async (emoji: string) => {
      await removeReactionMutation.mutateAsync(emoji);
    }, []);

    const mediaList = attachments?.filter(
      attachment =>
        FileTypes.VIDEO === attachment.type ||
        FileTypes.IMAGE === attachment.type,
    );

    const fileList = attachments?.filter(
      attachment => attachment.type === FileTypes.FILE,
    );

    const handleEdit = (commentData: CommentType) => {
      if (onEdit) {
        onEdit(commentData);
      }
      handleEditClose();
    };

    const handleReply = () => {
      onReply(id, parentId, user);
    };

    const handleDelete = () => {
      onDelete(id, parentId);
    };

    const images = attachments
      ?.filter(attachment => attachment.type === FileTypes.IMAGE)
      .map(getFormFileFromAttachment);

    const reactionsList = useMemo(() => reactions, [reactions]);

    return (
      <HugoThemeProvider>
        <Stack ref={ref}>
          <Stack
            sx={{
              flexDirection: 'row',
              mb: onReply !== undefined ? 0 : '12px',
              '& .MuiCardMedia-root': { width: '100%' },
            }}
          >
            <ProfilePicture
              id={user.id}
              user={user}
              sx={{ width: '40px', height: '40px' }}
              withLink
            />
            <Stack
              sx={{
                backgroundColor: th => th.palette.new.background.layout.default,
                borderRadius: 2,
                flexGrow: 1,
                ml: 1,
                px: 1.5,
                py: 1,
              }}
            >
              <Stack
                sx={{
                  justifyContent: 'space-between',
                  alignItems: 'center',
                  flexDirection: 'row',
                  mb: 1,
                }}
              >
                <Stack>
                  <Stack
                    direction="row"
                    alignItems="center"
                    gap={1}
                  >
                    <UserNameLink
                      user={{ ...user, isExternal: comment.isExternal }}
                    />
                  </Stack>
                  {createdAt && (
                    <TimeDistance
                      typographySx={{
                        fontSize: theme.typography.caption,
                      }}
                      date={new Date(createdAt)}
                      showIcon={false}
                    />
                  )}
                </Stack>
                <CommentActions
                  id={id}
                  postId={postId}
                  handleDelete={handleDelete}
                  handleEditOpen={handleEditOpen}
                  isEditEnabled={canEdit}
                  isDeleteEnabled={canDelete}
                  groupId={groupId}
                  eventId={eventId}
                />
              </Stack>
              <Stack>
                {toEdit && canEdit && (
                  <CommentEdit
                    commentId={id}
                    postId={postId}
                    defaultText={body}
                    defaultImages={images}
                    defaultGif={gifInfo?.data}
                    defaultBodyAttributes={bodyAttributes}
                    onEdit={handleEdit}
                    onCancel={handleEditClose}
                    maxAttachmentsBytes={maxAttachmentsBytes}
                    withoutAttachments
                  />
                )}
                {body && !toEdit && (
                  <PostText
                    body={body}
                    bodyAttributes={bodyAttributes}
                    maxCharacters={MAX_CHARACTERS_LIMIT}
                    maxNewLines={MAX_NEW_LINES_LIMIT}
                  />
                )}
                {fileList?.length > 0 && (
                  <Stack sx={{ mt: 2 }}>
                    {fileList.map(file => (
                      <Stack
                        key={file.url}
                        sx={{ mr: 1 }}
                      >
                        <File file={file} />
                      </Stack>
                    ))}
                  </Stack>
                )}
                {gif && !toEdit && (
                  <Stack sx={{ mt: 2 }}>
                    <Gif media={gif} />
                  </Stack>
                )}
                {mediaList?.length > 0 && !toEdit && (
                  <Stack sx={{ mt: 2 }}>
                    <MediaCarousel mediaList={mediaList} />
                  </Stack>
                )}
                {!toEdit && canReact && (
                  <ReactionsList
                    id={comment.id}
                    stackProps={{ mt: 2 }}
                    reactions={reactionsList}
                    getReactionUsers={getReactionUsers}
                    onAdd={handleAddReaction}
                    onRemove={handleRemoveReaction}
                    defaultEmoji={DEFAULT_EMOJI}
                    withUserList
                  />
                )}
              </Stack>
            </Stack>
          </Stack>
          {canReply && (
            <Stack sx={{ flexDirection: 'row', justifyContent: 'flex-end' }}>
              <ButtonText
                variant="tertiary"
                onClick={handleReply}
                sx={{ my: 1 }}
              >
                <Typography
                  variant="globalXS"
                  fontWeight="fontWeightSemiBold"
                  sx={{
                    color: theme => theme.palette.new.text.neutral.lighter,
                  }}
                >
                  {t('web_only:comments.reply_comment')}
                </Typography>
              </ButtonText>
            </Stack>
          )}
        </Stack>
      </HugoThemeProvider>
    );
  },
);

export default Comment;
