import { __rest } from "tslib";
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useMemo, useRef, useState } from 'react';
import { styled } from '@mui/material/styles';
import { FormattedMessage } from 'react-intl';
import CommentObject from '../CommentObject';
import { Box } from '@mui/material';
import { SCCommentsOrderBy } from '../../types/comments';
import classNames from 'classnames';
import { useThemeProps } from '@mui/system';
import CommentsObject from '../CommentsObject';
import { SCOPE_SC_UI } from '../../constants/Errors';
import Typography from '@mui/material/Typography';
import { getContribution } from '../../utils/contribution';
import { Endpoints, http } from '@selfcommunity/api-services';
import { CacheStrategies, Logger } from '@selfcommunity/utils';
import { useSCFetchCommentObject, useSCFetchCommentObjects } from '@selfcommunity/react-core';
import { SCContributionType } from '@selfcommunity/types';
import { DEFAULT_PAGINATION_LIMIT } from '../../constants/Pagination';
import { PREFIX } from './constants';
const classes = {
    root: `${PREFIX}-root`,
    noComments: `${PREFIX}-no-comments`,
    commentNotFound: `${PREFIX}-comment-not-found`
};
const Root = styled(Box, {
    name: PREFIX,
    slot: 'Root'
})(() => ({}));
/**
 * > API documentation for the Community-JS Comments Feed Object component. Learn about the available props and the CSS API.
 *
 *
 * This component renders a list of comment items.
 * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CommentsFeedObject)

 #### Import

 ```jsx
 import {CommentsFeedObject} from '@selfcommunity/react-ui';
 ```

 #### Component Name

 The name `SCCommentsFeedObject` can be used when providing style overrides in the theme.

 #### CSS

 |Rule Name|Global class|Description|
 |---|---|---|
 |root|.SCCommentsFeedObject-root|Styles applied to the root element.|
 |noComments|.SCCommentsFeedObject-no-comments|Styles applied to the 'no comments' section.|
 |commentNotFound|.SCCommentsFeedObject-comment-not-found|Styles applied to the label 'Comment not found'.|

 * @param inProps
 */
export default function CommentsFeedObject(inProps) {
    const props = useThemeProps({
        props: inProps,
        name: PREFIX
    });
    // PROPS
    const { id = `comments_object_${props.feedObjectType ? props.feedObjectType : props.feedObject ? props.feedObject.type : ''}_${props.feedObjectId ? props.feedObjectId : props.feedObject ? props.feedObject.id : ''}`, className, feedObjectId, feedObject, feedObjectType = SCContributionType.POST, commentObjectId, commentObject, CommentComponent = CommentObject, CommentComponentProps = { variant: 'outlined', linkableCommentDateTime: false }, CommentObjectSkeletonProps = { elevation: 0, WidgetProps: { variant: 'outlined' } }, renderNoComments, renderCommentNotFound, page = 1, commentsPageCount = DEFAULT_PAGINATION_LIMIT, commentsOrderBy = SCCommentsOrderBy.ADDED_AT_ASC, showTitle = false, infiniteScrolling = true, onChangePage, comments = [], cacheStrategy = CacheStrategies.NETWORK_ONLY } = props, rest = __rest(props, ["id", "className", "feedObjectId", "feedObject", "feedObjectType", "commentObjectId", "commentObject", "CommentComponent", "CommentComponentProps", "CommentObjectSkeletonProps", "renderNoComments", "renderCommentNotFound", "page", "commentsPageCount", "commentsOrderBy", "showTitle", "infiniteScrolling", "onChangePage", "comments", "cacheStrategy"]);
    // STATE
    const commentsObject = useSCFetchCommentObjects({
        id: feedObjectId,
        feedObject,
        feedObjectType,
        offset: (page - 1) * commentsPageCount,
        pageSize: commentsPageCount,
        orderBy: commentsOrderBy,
        onChangePage: onChangePage,
        cacheStrategy
    });
    const [isLoading, setIsLoading] = useState(false);
    const [comment, setComment] = useState(null);
    const { obj: commentObj, error: errorCommentObj } = useSCFetchCommentObject({ id: commentObjectId, commentObject, cacheStrategy });
    const [commentError, setCommentError] = useState(null);
    // CONST
    const objId = commentsObject.feedObject ? commentsObject.feedObject.id : null;
    const commentObjId = commentObj ? commentObj.id : null;
    // REFS
    const commentsContainerRef = useRef();
    /**
     * Total number of comments
     */
    const total = commentsObject.total + comments.length;
    /**
     * Render title
     */
    const renderTitle = useMemo(() => () => {
        if (showTitle) {
            return (_jsx(Typography, Object.assign({ variant: "h6", gutterBottom: true, color: 'inherit' }, { children: _jsx(FormattedMessage, { id: "ui.commentsObject.title", defaultMessage: "ui.commentsObject.title", values: { total: total } }) })));
        }
        return null;
    }, [total, isLoading]);
    /**
     * Render no comments
     */
    function renderNoCommentsFound() {
        return (_jsx(_Fragment, { children: renderNoComments ? (renderNoComments()) : (_jsx(Box, Object.assign({ className: classes.noComments }, { children: _jsx(FormattedMessage, { id: "ui.commentsObject.noComments", defaultMessage: "ui.commentsObject.noComments" }) }))) }));
    }
    /**
     * Render comment not found
     */
    function renderCommentNotFoundError() {
        return (_jsx(_Fragment, { children: renderCommentNotFound ? (renderCommentNotFound()) : (_jsx(Box, Object.assign({ className: classes.commentNotFound }, { children: _jsx(FormattedMessage, { id: "ui.commentsObject.commentNotFound", defaultMessage: "ui.commentsObject.commentNotFound" }) }))) }));
    }
    /**
     * Get a single comment
     */
    const performFetchComment = useMemo(() => (commentId) => {
        return http
            .request({
            url: Endpoints.Comment.url({ id: commentId }),
            method: Endpoints.Comment.method
        })
            .then((res) => {
            if (res.status >= 300) {
                return Promise.reject(res);
            }
            return Promise.resolve(res.data);
        });
    }, [commentsObject.feedObject, commentObjectId, commentObj]);
    /**
     * Focus on comment
     * @param comment
     */
    function scrollToComment(comment) {
        // Add (window.innerHeight / 2) to scroll
        // (usually >= (topBar + offset) and in center of the screen)
        setTimeout(() => {
            // Get the comment inside commentsContainer
            const el = commentsContainerRef.current ? commentsContainerRef.current.querySelector(`#comment_object_${comment.id}`) : null;
            if (el) {
                el.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
            }
        }, 300);
    }
    /**
     * Fetch a single comment
     * and comment parent (if need it)
     */
    function fetchComment() {
        if (commentObj) {
            if (commentObj.parent) {
                setIsLoading(true);
                performFetchComment(commentObj.parent)
                    .then((parent) => {
                    const _parent = Object.assign({}, parent);
                    _parent.latest_comments = [commentObj];
                    if (getContribution(parent).id === commentsObject.feedObject.id) {
                        setComment(_parent);
                        scrollToComment(commentObj);
                    }
                    else {
                        setCommentError(true);
                    }
                    setIsLoading(false);
                })
                    .catch((error) => {
                    // Comment not found
                    setIsLoading(false);
                    Logger.error(SCOPE_SC_UI, error);
                });
            }
            else {
                if (getContribution(commentObj).id === commentsObject.feedObject.id) {
                    setComment(commentObj);
                    scrollToComment(commentObj);
                }
                else {
                    setCommentError(true);
                }
                setIsLoading(false);
            }
        }
        else if (errorCommentObj) {
            setIsLoading(false);
        }
    }
    /**
     * Prefetch comments only if obj exists
     */
    useEffect(() => {
        if (objId !== null && !isLoading) {
            if (commentObjectId || commentObj) {
                fetchComment();
            }
            else if (!isLoading) {
                commentsObject.getNextPage();
            }
        }
    }, [objId, commentObjId]);
    /**
     * Render comments
     */
    let commentsRendered = _jsx(_Fragment, {});
    if (commentsObject.componentLoaded && !total && !commentsObject.isLoadingNext && !isLoading) {
        /**
         * If comments were not found and loading is finished
         * and the component was not looking for a particular
         * comment render no comments message
         */
        commentsRendered = renderNoCommentsFound();
    }
    else {
        /**
         * Two modes available:
         *  - infinite scroll
         *  - load pagination with load more button
         *  !IMPORTANT:
         *  the component will switch to 'load more pagination' mode automatically
         *  in case it needs to display a single comment
         */
        commentsRendered = (_jsxs(_Fragment, { children: [Boolean((commentError || errorCommentObj) && !isLoading && !total) && renderCommentNotFoundError(), _jsx(CommentsObject, { feedObject: commentsObject.feedObject, comments: commentsObject.comments, endComments: [...(comment ? [comment] : []), ...(commentsOrderBy === SCCommentsOrderBy.ADDED_AT_ASC ? comments : [])], startComments: [...(commentsOrderBy === SCCommentsOrderBy.ADDED_AT_ASC ? [] : comments)], previous: commentsObject.previous, handlePrevious: commentsObject.getPreviousPage, isLoadingPrevious: commentsObject.isLoadingPrevious, next: commentsObject.next, isLoadingNext: commentsObject.isLoadingNext, handleNext: commentsObject.getNextPage, page: commentsObject.page, previousPage: commentsObject.previousPage, nextPage: commentsObject.nextPage, infiniteScrolling: infiniteScrolling && commentsObject.total > 0 && !comment && !comments.length, CommentComponent: CommentComponent, CommentComponentProps: CommentComponentProps, CommentObjectSkeletonProps: CommentObjectSkeletonProps })] }));
    }
    /**
     * Renders root object
     */
    return (_jsxs(Root, Object.assign({ id: id, className: classNames(classes.root, className) }, rest, { ref: commentsContainerRef }, { children: [renderTitle(), commentsRendered] })));
}
