import * as React from "react";
import { useLayoutEffect, useRef } from "react";
import * as classNames from "classnames";
import * as moment from "moment";
import { AlertMessage } from "./AlertMessage";
import { MessageMetadata } from "./MessageMetadata";
import { cssClass as FlexBoxCSS } from "../flex/FlexBox";
import { cssClass as FlexItemCSS } from "../flex/FlexItem";
import "./MessagingThreadHistory.less";
var cssClasses = {
    CONTAINER: "ThreadHistory--Container",
    DIVIDER: "ThreadHistory--Divider",
    FIRST_MESSAGE: "ThreadHistory--FirstMessage",
};
var SCROLL_BUFFER = 200;
// Always returns true with current mobile strategy of scrolling the entire thread history
function calcIsScrolledToBottom(ref) {
    return (ref &&
        ref.current &&
        ref.current.scrollTop + SCROLL_BUFFER >= ref.current.scrollHeight - ref.current.clientHeight);
}
function isOwnMessage(message) {
    return message.placement === "right";
}
export var MessagingThreadHistory = React.forwardRef(function (_a, containerRef) {
    // ----------- Scroll position references
    var className = _a.className, threadID = _a.threadID, messages = _a.messages, onScroll = _a.onScroll, ariaLabel = _a.ariaLabel;
    // Reference attached to the last message's DOM element
    var lastMessageRef = useRef(null);
    // Maintains a reference as to what the last (highest) messages index was on the last render
    var lastMessageIndex = useRef(messages.length > 0 ? messages[messages.length - 1].index : null);
    // Determines whether the user was scrolled to the bottom before we potentially
    //  insert new messages at _interleaveMessagesWithDividers()
    var isScrolledToBottom = calcIsScrolledToBottom(containerRef);
    // ----------- Scroll effects
    // Scroll to the bottom if the user switches to a new non-null thread
    useLayoutEffect(function () {
        if (lastMessageRef.current) {
            lastMessageRef.current.scrollIntoView();
        }
    }, [threadID]);
    // Scroll to bottom if:
    //  1. the user sends a new message OR
    //  2. if they are viewing the last message when a new message comes in
    useLayoutEffect(function () {
        var isNewMessage = messages.length > 0 && messages[messages.length - 1].index !== lastMessageIndex.current;
        if (isNewMessage) {
            var newMessage = messages[messages.length - 1];
            if (isOwnMessage(newMessage) || isScrolledToBottom) {
                lastMessageRef.current.scrollIntoView();
            }
            lastMessageIndex.current = newMessage.index;
        }
    }, [messages]);
    // ----------- Render
    var messagesWithDividers = _interleaveMessagesWithDividers(messages, lastMessageRef);
    return (React.createElement("div", { className: classNames(cssClasses.CONTAINER, FlexBoxCSS.FLEXBOX, FlexBoxCSS.COLUMN, FlexItemCSS.GROW, className), ref: containerRef, onScroll: onScroll, tabIndex: 0, role: "log", "aria-label": ariaLabel }, messagesWithDividers));
});
function _interleaveMessagesWithDividers(messages, lastMessageRef) {
    // Interleave dividers (e.g. "Today," "Yesterday", "May 20") with messages.
    var messagesWithDividers = [];
    var currentDay = "";
    messages.forEach(function (message, i) {
        // If the message has a timestamp (i.e. is not Clever-generated) and was sent on a different
        // day than the previous message, we want a divider (with the date) in between.
        if (message.timestamp) {
            var messageDay = _formatDateForDivider(message.timestamp);
            if (currentDay !== messageDay) {
                messagesWithDividers.push(React.createElement("div", { key: "divider-" + messageDay, className: cssClasses.DIVIDER }, messageDay));
                currentDay = messageDay;
            }
        }
        // All content is wrapped in MessageMetadata, which handles placement and timestamps.
        messagesWithDividers.push(React.createElement(MessageMetadata, { key: "message-" + message.index, 
            // Last message in the history gets a ref, to allow scrolling down to bottom message.
            ref: i === messages.length - 1 ? lastMessageRef : undefined, placement: message.placement, readStatusText: isOwnMessage(message) && message.readStatusText, 
            // First message needs 'auto' top margin to have messages fill container from bottom -> top
            className: i === 0 ? cssClasses.FIRST_MESSAGE : undefined, errorMsg: message.errorMsg }, message.content));
        if (message.displayAlertMessageAfter) {
            var _a = message.displayAlertMessageAfter, icon = _a.icon, messageText = _a.messageText;
            messagesWithDividers.push(React.createElement(AlertMessage, { key: "alertMessage-" + message.index, icon: icon, messageText: messageText }));
        }
    });
    return messagesWithDividers;
}
// Helper function: Format a Date for our pretty timestamps.
//  Returns "Today"/"Yesterday" if appropriate, or "<month> <day>" date otherwise.
function _formatDateForDivider(date) {
    var _a = [
        moment(date),
        moment().hours(0),
        moment().hours(0).subtract(1, "days"),
    ], messageTimestamp = _a[0], midnightToday = _a[1], midnightYesterday = _a[2];
    if (messageTimestamp.isAfter(midnightToday)) {
        return "Today";
    }
    if (messageTimestamp.isAfter(midnightYesterday)) {
        return "Yesterday";
    }
    return messageTimestamp.format("MMM D");
}
