// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { isIOS } from '@fluentui/react';
import { mergeStyles, Stack } from '@fluentui/react';
import { PersonaSize } from '@fluentui/react';
import { ErrorBar, MessageThread, TypingIndicator, useTheme } from "../../../../react-components/src";
import React, { useCallback, useEffect, useMemo } from 'react';
import { useState } from 'react';
import { AvatarPersona } from '../common/AvatarPersona';
import { useAdapter } from './adapter/ChatAdapterProvider';
import { ChatHeader, getHeaderProps } from './ChatHeader';
import { useAdaptedSelector } from './hooks/useAdaptedSelector';
import { usePropsFor } from './hooks/usePropsFor';
import { chatArea, chatContainer, chatWrapper, messageThreadChatCompositeStyles, sendboxContainerStyles, typingIndicatorContainerStyles } from './styles/Chat.styles';
import { participantListContainerPadding } from '../common/styles/ParticipantContainer.styles';
import { toFlatCommunicationIdentifier } from "../../../../acs-ui-common/src";
import { ImageOverlay } from "../../../../react-components/src";
import { SendBoxPicker } from '../common/SendBoxPicker';
import { useSelector } from './hooks/useSelector';
import { getChatMessages, getThreadId, getUserId } from './selectors/baseSelectors';
/**
 * @private
 */
export const ChatScreen = (props) => {
    const { onFetchAvatarPersonaData, onRenderMessage, onRenderTypingIndicator, options, styles, formFactor } = props;
    const defaultNumberOfChatMessagesToReload = 5;
    const [overlayImageItem, setOverlayImageItem] = useState();
    const [isImageOverlayOpen, setIsImageOverlayOpen] = useState(false);
    const adapter = useAdapter();
    const theme = useTheme();
    useEffect(() => {
        // Initial data should be always fetched by the composite(or external caller) instead of the adapter
        const fetchData = () => __awaiter(void 0, void 0, void 0, function* () {
            // Fetch initial data for adapter
            yield adapter.fetchInitialData();
            // Fetch initial set of messages. Without fetching messages here, if the Composite's adapter is changed the message thread does not load new messages.
            yield adapter.loadPreviousChatMessages(defaultNumberOfChatMessagesToReload);
        });
        fetchData();
    }, [adapter]);
    const messageThreadProps = usePropsFor(MessageThread);
    const typingIndicatorProps = usePropsFor(TypingIndicator);
    const headerProps = useAdaptedSelector(getHeaderProps);
    const errorBarProps = usePropsFor(ErrorBar);
    const overlayImageItemRef = React.useRef(overlayImageItem);
    overlayImageItemRef.current = overlayImageItem;
    const adapterChatMessages = useSelector(getChatMessages);
    useEffect(() => {
        var _a;
        if (overlayImageItemRef.current === undefined) {
            return;
        }
        const message = adapterChatMessages[overlayImageItemRef.current.messageId];
        if (message === undefined) {
            return;
        }
        const resourceFetchResult = (_a = message.resourceCache) === null || _a === void 0 ? void 0 : _a[overlayImageItemRef.current.imageUrl];
        if (overlayImageItemRef.current.imageSrc === '' && resourceFetchResult) {
            const fullSizeImageSrc = getResourceSourceUrl(resourceFetchResult);
            if (fullSizeImageSrc === undefined || fullSizeImageSrc === '' || overlayImageItemRef.current.imageSrc === fullSizeImageSrc) {
                return;
            }
            setOverlayImageItem(Object.assign(Object.assign({}, overlayImageItemRef.current), { imageSrc: fullSizeImageSrc }));
        }
    }, [adapterChatMessages]);
    const getResourceSourceUrl = (result) => {
        let src = '';
        if (result.error || !result.sourceUrl) {
            src = 'blob://';
        }
        else {
            src = result.sourceUrl;
        }
        return src;
    };
    const onRenderAvatarCallback = useCallback((userId, defaultOptions) => {
        return React.createElement(AvatarPersona, Object.assign({ userId: userId, hidePersonaDetails: true }, defaultOptions, { dataProvider: onFetchAvatarPersonaData }));
    }, [onFetchAvatarPersonaData]);
    const messageThreadStyles = useMemo(() => {
        return Object.assign({}, messageThreadChatCompositeStyles(theme.semanticColors.bodyBackground), styles === null || styles === void 0 ? void 0 : styles.messageThread);
    }, [styles === null || styles === void 0 ? void 0 : styles.messageThread, theme.semanticColors.bodyBackground]);
    const typingIndicatorStyles = useMemo(() => {
        return Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.typingIndicator);
    }, [styles === null || styles === void 0 ? void 0 : styles.typingIndicator]);
    const sendBoxStyles = useMemo(() => {
        return Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.sendBox);
    }, [styles === null || styles === void 0 ? void 0 : styles.sendBox]);
    const userIdObject = useSelector(getUserId);
    const userId = toFlatCommunicationIdentifier(userIdObject);
    const threadId = useSelector(getThreadId);
    const onInlineImageClicked = useCallback((attachmentId, messageId) => {
        var _a, _b, _c;
        const message = adapterChatMessages[messageId];
        const inlinedImages = (_b = (_a = message === null || message === void 0 ? void 0 : message.content) === null || _a === void 0 ? void 0 : _a.attachments) === null || _b === void 0 ? void 0 : _b.filter(attachment => {
            return attachment.attachmentType === 'image' && attachment.id === attachmentId;
        });
        const attachment = inlinedImages === null || inlinedImages === void 0 ? void 0 : inlinedImages[0];
        if (!attachment) {
            return;
        }
        let imageSrc = '';
        if (attachment.url) {
            const resourceFetchResult = (_c = message === null || message === void 0 ? void 0 : message.resourceCache) === null || _c === void 0 ? void 0 : _c[attachment.url];
            if (resourceFetchResult) {
                imageSrc = getResourceSourceUrl(resourceFetchResult);
            }
            else {
                adapter.downloadResourceToCache({
                    threadId,
                    messageId,
                    resourceUrl: attachment.url
                });
            }
        }
        const titleIconRenderOptions = {
            text: message === null || message === void 0 ? void 0 : message.senderDisplayName,
            size: PersonaSize.size32,
            showOverflowTooltip: false,
            imageAlt: message === null || message === void 0 ? void 0 : message.senderDisplayName
        };
        const messageSenderId = (message === null || message === void 0 ? void 0 : message.sender) !== undefined ? toFlatCommunicationIdentifier(message.sender) : userId;
        const titleIcon = onRenderAvatarCallback && onRenderAvatarCallback(messageSenderId, titleIconRenderOptions);
        const overlayImage = {
            title: (message === null || message === void 0 ? void 0 : message.senderDisplayName) || '',
            titleIcon: titleIcon,
            attachmentId: attachment.id,
            imageSrc: imageSrc,
            messageId: messageId,
            imageUrl: attachment.url || ''
        };
        setIsImageOverlayOpen(true);
        setOverlayImageItem(overlayImage);
    }, [adapter, adapterChatMessages, onRenderAvatarCallback, userId, threadId]);
    const onRenderInlineImage = useCallback((inlineImage, defaultOnRender) => {
        var _a, _b, _c;
        const message = adapterChatMessages[inlineImage.messageId];
        const attachment = (_b = (_a = message === null || message === void 0 ? void 0 : message.content) === null || _a === void 0 ? void 0 : _a.attachments) === null || _b === void 0 ? void 0 : _b.find(attachment => attachment.id === inlineImage.imageAttributes.id);
        if (attachment === undefined) {
            return defaultOnRender(inlineImage);
        }
        let pointerEvents = inlineImage.imageAttributes.src === '' ? 'none' : 'auto';
        const resourceCache = message === null || message === void 0 ? void 0 : message.resourceCache;
        if (resourceCache && attachment.previewUrl && resourceCache[attachment.previewUrl] && ((_c = resourceCache[attachment.previewUrl]) === null || _c === void 0 ? void 0 : _c.error)) {
            pointerEvents = 'none';
        }
        return React.createElement("span", { key: inlineImage.imageAttributes.id, onClick: () => onInlineImageClicked(inlineImage.imageAttributes.id || '', inlineImage.messageId), tabIndex: 0, role: "button", onKeyDown: e => {
                if (e.key === 'Enter') {
                    onInlineImageClicked(inlineImage.imageAttributes.id || '', inlineImage.messageId);
                }
            }, style: {
                cursor: 'pointer',
                pointerEvents
            } }, defaultOnRender(inlineImage));
    }, [adapterChatMessages, onInlineImageClicked]);
    const inlineImageOptions = useMemo(() => {
        return {
            onRenderInlineImage: onRenderInlineImage
        };
    }, [onRenderInlineImage]);
    const onDownloadButtonClicked = useCallback((imageSrc) => {
        if (imageSrc === '') {
            return;
        }
        if (isIOS()) {
            window.open(imageSrc, '_blank');
        }
        else {
            // Create a new anchor element
            const a = document.createElement('a');
            // Set the href and download attributes for the anchor element
            a.href = imageSrc;
            a.download = (overlayImageItem === null || overlayImageItem === void 0 ? void 0 : overlayImageItem.attachmentId) || '';
            a.rel = 'noopener noreferrer';
            a.target = '_blank';
            // Programmatically click the anchor element to trigger the download
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
        }
    }, [overlayImageItem === null || overlayImageItem === void 0 ? void 0 : overlayImageItem.attachmentId]);
    const onSendMessageHandler = useCallback(function (content) {
        return __awaiter(this, void 0, void 0, function* () {
            yield adapter.sendMessage(content, {});
        });
    }, [adapter]);
    const onUpdateMessageHandler = useCallback(function (messageId, content) {
        return __awaiter(this, void 0, void 0, function* () {
            yield messageThreadProps.onUpdateMessage(messageId, content);
        });
    }, [messageThreadProps]);
    return React.createElement(Stack, { className: chatContainer, grow: true },
        (options === null || options === void 0 ? void 0 : options.topic) !== false && React.createElement(ChatHeader, Object.assign({}, headerProps)),
        React.createElement(Stack, { className: chatArea, tokens: participantListContainerPadding, horizontal: true, grow: true },
            React.createElement(Stack, { className: chatWrapper, grow: true },
                (options === null || options === void 0 ? void 0 : options.errorBar) !== false && React.createElement(ErrorBar, Object.assign({}, errorBarProps)),
                React.createElement(MessageThread, Object.assign({}, messageThreadProps, { onUpdateMessage: onUpdateMessageHandler, onRenderAvatar: onRenderAvatarCallback, onRenderMessage: onRenderMessage, inlineImageOptions: inlineImageOptions, numberOfChatMessagesToReload: defaultNumberOfChatMessagesToReload, styles: messageThreadStyles })),
                React.createElement(Stack, { className: mergeStyles(sendboxContainerStyles) },
                    React.createElement("div", { className: mergeStyles(typingIndicatorContainerStyles) }, onRenderTypingIndicator ? onRenderTypingIndicator(typingIndicatorProps.typingUsers) : React.createElement(TypingIndicator, Object.assign({}, typingIndicatorProps, { styles: typingIndicatorStyles }))),
                    React.createElement(Stack, { horizontal: formFactor === 'mobile' },
                        formFactor === 'mobile',
                        React.createElement(Stack, { grow: true },
                            React.createElement(SendBoxPicker, { styles: sendBoxStyles, autoFocus: options === null || options === void 0 ? void 0 : options.autoFocus, 
                                // we need to overwrite onSendMessage for SendBox because we need to clear attachment state
                                // when submit button is clicked
                                onSendMessage: onSendMessageHandler })),
                        formFactor !== 'mobile')))),
        overlayImageItem && React.createElement(ImageOverlay, Object.assign({}, overlayImageItem, { isOpen: isImageOverlayOpen, onDismiss: () => {
                setOverlayImageItem(undefined);
                setIsImageOverlayOpen(false);
                adapter.removeResourceFromCache({
                    threadId,
                    messageId: overlayImageItem.messageId,
                    resourceUrl: overlayImageItem.imageUrl
                });
            }, onDownloadButtonClicked: onDownloadButtonClicked })));
};
//# sourceMappingURL=ChatScreen.js.map