import type React from 'react';
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

import Box from '@material-hu/mui/Box';
import CardActions from '@material-hu/mui/CardActions';
import Divider from '@material-hu/mui/Divider';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import { MAX_ATTACHMENTS_B } from 'src/constants/posts';
import { useAuth } from 'src/contexts/JWTContext';
import { useCommentsSystem } from 'src/hooks/useCommentsSystem';
import { type PostCommentPayload } from 'src/types/comments';
import { type TaggedUser } from 'src/types/user';
import { getCommentToScrollRef } from 'src/utils/comments';
import {
  buildCommentDraftKey,
  readComposerDraft,
} from 'src/utils/composerDrafts';

import CommentAdd from 'src/components/comments/CommentAdd';
import CommentCountPost from 'src/components/comments/CommentCountPost';
import CommentPostButton from 'src/components/comments/CommentPostButton';
import CommentSkeleton from 'src/components/comments/CommentSkeleton';
import ShowMoreCommentsButton from 'src/components/comments/ShowMoreCommentsButton';
import PostCardViewersInline from 'src/components/post/PostCardViewersInline';
import { usePost } from 'src/components/post/PostContext';

import { CommentList } from './CommentList';
import {
  type CommentItemBasePropsWithoutComment,
  type CommentsSystemComponentProps,
  type GroupVariantProps,
  type StandardVariantProps,
} from './types';

export const CommentsSystem = (props: CommentsSystemComponentProps) => {
  const { t } = useTranslation('post');
  const {
    context,
    postId,
    commentCount,
    lastComments = [],
    isDetail = false,
    commentsEnabled = true,
    containerSx,
    commentToScrollToRef,
    viewerCount,
    getViewers,
    viewersDisabled,

    FeedProps,
    GroupsProps,
    ArticlesProps,
    EventsProps,
  } = props;

  const parentIdParams =
    (context === 'feed' && FeedProps?.parentIdParams) ||
    (context === 'groups' && GroupsProps?.parentIdParams) ||
    (context === 'articles' && ArticlesProps?.parentIdParams) ||
    (context === 'events' && EventsProps?.parentIdParams) ||
    undefined;
  const { groupId, eventId } = usePost();
  const { user: loggedUser } = useAuth();
  const isDraftSupportedContext = context === 'feed' || context === 'groups';
  const draftScope =
    context === 'groups' || groupId !== undefined ? 'groups' : 'feed';
  const defaultScrollRef = useRef<HTMLElement>(null);
  const scrollRef = commentToScrollToRef ?? defaultScrollRef;

  const {
    comments,
    data,
    isLoading,
    isFetchingNextPage,
    state,
    setIsFocused,
    postCommentMutation,
    replyCommentMutation,
    fetchNextPage,
    handlers,
    canReact,
    canManageComments,
  } = useCommentsSystem({
    context,
    postId,
    lastComments,
    groupId: groupId ? String(groupId) : undefined,
    eventId,
    isDetail,
    shouldAutoLoad: context === 'articles',
    commentsEnabled,
  });

  // Handle scroll to comment
  useEffect(() => {
    handlers.handleScrollToComment(scrollRef, comments);
  }, [scrollRef, comments?.length, handlers, comments]);

  // Show load more comments logic
  const showLoadMoreComments = useMemo(() => {
    return handlers.showLoadMoreComments(data, lastComments, commentCount);
  }, [data, lastComments, commentCount, handlers]);

  // Handle load more comments
  const handleLoadMoreComments = () => {
    fetchNextPage();
  };

  const handleClickViewComments = () => {
    if (isFetchingNextPage) {
      return;
    }
    if (commentCount <= 0) {
      handlers.handleClickComment();
      setIsFocused(true);
      return;
    }
    // Avoid fetching when we already have all comments
    if (!showLoadMoreComments) {
      return;
    }
    fetchNextPage();
  };

  // Handle click comment
  const handleClickComment = () => {
    handlers.handleClickComment();
    setIsFocused(true);
  };

  // Handle post comment
  const handlePostComment = async (
    formData: PostCommentPayload,
    taggedUsers: TaggedUser[] = [],
  ) => {
    await postCommentMutation.mutateAsync([formData, taggedUsers]);
  };

  const topLevelDraftKey =
    isDraftSupportedContext && loggedUser
      ? buildCommentDraftKey({
          scope: draftScope,
          postId,
          userId: loggedUser.id,
          parentId: null,
          groupId,
        })
      : null;
  const [hasTopLevelDraft, setHasTopLevelDraft] = useState(false);

  useEffect(() => {
    if (!topLevelDraftKey) {
      setHasTopLevelDraft(false);
      return;
    }

    setHasTopLevelDraft(!!readComposerDraft(topLevelDraftKey).trim());
  }, [topLevelDraftKey, state.isFocused, commentCount, comments.length]);

  // Choose appropriate container component
  const ContainerComponent: React.ComponentType<{
    sx?: Record<string, unknown>;
    children?: React.ReactNode;
  }> = context === 'acknowledgements' ? Stack : Box;
  const containerProps = {
    sx: { px: 2, ...containerSx },
  };

  // Render segmentation section (feed only)
  const renderSegmentation = () => {
    if (context !== 'feed' || !FeedProps?.showSegmentation) return null;

    return (
      <>
        <Box
          sx={{ display: 'flex', alignItems: 'center' }}
          onClick={FeedProps?.onOpenSegmentationDrawer}
        >
          <Typography>{FeedProps?.amountOfUsersReach}</Typography>
        </Box>
        {FeedProps.segmentationDrawer}
      </>
    );
  };

  const renderCommentsDisabled = () => {
    if (commentsEnabled || (context !== 'feed' && context !== 'groups'))
      return null;

    return (
      <Box sx={{ pt: 1 }}>
        <Typography variant="globalXXS">
          {t('post:comments_disabled')}
        </Typography>
      </Box>
    );
  };

  const hasNoComments = commentCount === null || commentCount === 0;

  const renderDivider = () => (
    <Divider
      sx={{ borderColor: theme => theme.palette.new.background.layout.default }}
    />
  );

  // Render comment actions section
  const renderCommentActions = () => {
    if (GroupsProps?.isGroupArchived) {
      return <Stack mt={2} />;
    }

    // Acknowledgements detail view should mirror the wall and keep the
    // comment button visible (see SQDP-4006).
    const showCommentButton = !isDetail || context === 'acknowledgements';

    return (
      <CardActions sx={{ py: 0, px: 0, mt: 2 }}>
        <Box
          sx={{
            display: 'flex',
            justifyContent: 'space-between',
            width: '100%',
          }}
        >
          <Box
            sx={{
              display: 'flex',
              alignItems: 'center',
              justifyContent: showCommentButton ? 'flex-start' : 'flex-end',
              width: '100%',
            }}
          >
            {showCommentButton && (
              <CommentPostButton handleClickComment={handleClickComment} />
            )}
            <Box
              sx={{
                ml: 'auto',
                display: 'flex',
                alignItems: 'center',
                gap: 1.5,
              }}
            >
              <CommentCountPost
                handleClickViewComments={handleClickViewComments}
                commentCount={commentCount}
              />
              {viewerCount !== undefined && viewerCount > 0 && getViewers && (
                <PostCardViewersInline
                  postId={postId}
                  viewerCount={viewerCount}
                  getViewers={getViewers}
                  disabled={viewersDisabled}
                />
              )}
            </Box>
            {renderSegmentation()}
          </Box>
        </Box>
      </CardActions>
    );
  };

  const renderCommentAdd = () => {
    // If there are no comments, show input when focused or when there's a saved root draft.
    if (commentCount <= 0 && !state.isFocused && !hasTopLevelDraft) {
      return null;
    }

    if (!commentsEnabled) {
      return null;
    }

    // For groups context: if userIsMember is defined, we're
    // inside a group detail and need to check permissions
    const isInsideGroupDetail =
      context === 'groups' && GroupsProps?.userIsMember !== undefined;

    if (
      isInsideGroupDetail &&
      (!GroupsProps?.userIsMember || GroupsProps?.isGroupArchived)
    ) {
      return null;
    }

    return (
      <CommentAdd
        id={postId}
        onSubmit={handlePostComment}
        maxAttachmentsBytes={MAX_ATTACHMENTS_B}
        setInitialFocus={state.isFocused}
        onBlur={handlers.handleBlur}
        isPost
        draftKey={topLevelDraftKey}
        {...(context === 'groups' ? { isNewTheme: true } : {})}
      />
    );
  };

  const commentListCommonProps: CommentItemBasePropsWithoutComment &
    (GroupVariantProps | StandardVariantProps) = {
    handlers,
    reply: state.reply,
    postId,
    maxAttachmentsBytes: MAX_ATTACHMENTS_B,
    replyCommentMutation,
    isReplyFocused: state.isReplyFocused,
    handleReplyBlur: handlers.handleReplyBlur,
    handleDeleteUserReply: handlers.handleDeleteUserReply,
    ...(context === 'groups'
      ? {
          context: 'groups',
          isGroupArchived: GroupsProps.isGroupArchived,
          userIsMember: GroupsProps.userIsMember,
          isGroupAdmin: GroupsProps.isGroupAdmin,
        }
      : {
          context,
          canManageComments,
          canReact,
          parentIdParams: parentIdParams ?? null,
          commentToScrollToRef: scrollRef,
          getCommentToScrollRef,
        }),
  };

  const renderComments = () => {
    const shouldShowPaginatedComments =
      // state.openViewComments &&
      !isLoading && comments.length > 0;
    if (shouldShowPaginatedComments) {
      return (
        <CommentList
          comments={comments}
          {...commentListCommonProps}
        />
      );
    }

    const shouldShowLastComments = lastComments && lastComments.length > 0;
    if (shouldShowLastComments) {
      // TODO: See why [comment]
      return (
        <>
          {lastComments.map(comment => (
            <Fragment key={comment?.id}>
              <CommentList
                comments={[comment]}
                {...commentListCommonProps}
              />
            </Fragment>
          ))}
        </>
      );
    }

    return null;
  };

  if (GroupsProps?.isGroupArchived && hasNoComments) {
    return null;
  }

  if (!commentsEnabled) {
    return (
      <ContainerComponent {...containerProps}>
        {renderDivider()}
        {renderCommentsDisabled()}
      </ContainerComponent>
    );
  }

  return (
    <ContainerComponent {...containerProps}>
      {renderDivider()}

      {renderCommentActions()}

      {renderCommentAdd()}

      {postCommentMutation.isLoading && (
        <Box sx={{ textAlign: 'center', mt: 1 }}>
          <CommentSkeleton />
        </Box>
      )}

      {renderComments()}

      {(isLoading || isFetchingNextPage) && (
        <Box sx={{ textAlign: 'center', mt: 1 }}>
          <CommentSkeleton />
        </Box>
      )}

      {showLoadMoreComments && (
        <ShowMoreCommentsButton
          handleLoadMoreComments={handleLoadMoreComments}
        />
      )}
    </ContainerComponent>
  );
};
