// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
// SPDX-License-Identifier: LGPL-3.0-or-later

import QtQuick 2.12
import QtQuick.Layouts 1.12
import "../../../Base"
import "../../.."

HRowLayout {
    id: eventContent

    readonly property var mentions: JSON.parse(model.mentions)

    readonly property string mentionsCSS: {
        const lines = []

        for (const [name, link] of mentions) {
            if (! link.match(/^https?:\/\/matrix.to\/#\/@.+/)) continue

            lines.push(
                `.mention[data-mention='${utils.escapeHtml(name)}'] ` +
                `{ color: ${utils.nameColor(name)} }`
            )
        }

        return "<style type='text/css'>" + lines.join("\n") + "</style>"
    }

    readonly property string senderText:
        hideNameLine ? "" : (
            `<${compact ? "span" : "div"} class='sender'>` +
            utils.coloredNameHtml(model.sender_name, model.sender_id) +
            (compact ? ": " : "") +
            (compact ? "</span>" : "</div>")
        )
    property string contentText: utils.processedEventText(model)
    readonly property string timeText: utils.formatTime(model.date, false)

    readonly property string stateText:
    `<a href="#state-text" style="text-decoration: none">` +
    `<font size=${theme.fontSize.small}px><font ` + (
            model.is_local_echo ?
            `color="${theme.chat.message.localEcho}">&nbsp;⧗` :  // U+29D7

            model.read_by_count ?
            `color="${theme.chat.message.readCounter}">&nbsp;⦿&nbsp;` +
            model.read_by_count :  // U+29BF

            ">"
        ) + "</font></font></a>"

    readonly property bool pureMedia: ! contentText && linksRepeater.count

    readonly property bool hoveredSelectable: contentHover.hovered
    readonly property string hoveredLink:
        linksRepeater.lastHovered && linksRepeater.lastHovered.hovered ?
        linksRepeater.lastHovered.mediaUrl :
        contentLabel.hoveredLink

    readonly property alias contentLabel: contentLabel

    readonly property int xOffset:
        onRight ?
        Math.min(
            contentColumn.width - contentLabel.paintedWidth -
            contentLabel.leftPadding - contentLabel.rightPadding,

            contentColumn.width - linksRepeater.widestChild -
            (
                pureMedia ?
                0 : contentLabel.leftPadding + contentLabel.rightPadding
            ),
        ) :
        0

    readonly property int maxMessageWidth:
        contentText.includes("<pre>") || contentText.includes("<table>") ?
        -1 :
        window.settings.Chat.max_messages_line_length < 0 ?
        -1 :
        Math.ceil(
            mainUI.fontMetrics.averageCharacterWidth *
            window.settings.Chat.max_messages_line_length
        )

    readonly property alias selectedText: contentLabel.selectedPlainText

    spacing: theme.chat.message.horizontalSpacing
    layoutDirection: onRight ? Qt.RightToLeft: Qt.LeftToRight

    Item {
        id: avatarWrapper
        visible: ! onRight
        opacity: combine ? 0 : 1

        Layout.alignment: Qt.AlignTop
        Layout.preferredHeight: combine ? 1 : Layout.preferredWidth
        Layout.preferredWidth:
            compact ?
            theme.chat.message.collapsedAvatarSize :
            theme.chat.message.avatarSize

        HUserAvatar {
            id: avatar
            clientUserId: chat.userId
            userId: model.sender_id
            displayName: model.sender_name
            mxc: model.sender_avatar
            width: parent.width
            height: combine ? 1 : parent.Layout.preferredWidth
            radius: theme.chat.message.avatarRadius

        }
    }

    HColumnLayout {
        id: contentColumn

        Layout.fillWidth: true
        Layout.alignment: Qt.AlignVCenter

        HSelectableLabel {
            id: contentLabel
            visible: ! pureMedia
            enableLinkActivation: ! eventList.selectedCount

            selectByMouse:
                eventList.selectedCount <= 1 &&
                eventDelegate.checked &&
                textSelectionBlocker.point.scenePosition === Qt.point(0, 0)

            topPadding: theme.chat.message.verticalSpacing
            bottomPadding: topPadding
            leftPadding: eventContent.spacing
            rightPadding: leftPadding

            color: model.event_type === "RoomMessageNotice" ?
                   theme.chat.message.noticeBody :
                   theme.chat.message.body

            font.italic: model.event_type === "RoomMessageEmote"
            wrapMode: TextEdit.Wrap
            textFormat: Text.RichText
            text:
                // CSS
                theme.chat.message.styleInclude + mentionsCSS +

                // Sender name & message body
                (
                    compact && contentText.match(/^\s*<(p|h[1-6])>/) ?
                    contentText.replace(
                        /(^\s*<(p|h[1-6])>)/, "$1" + senderText,
                    ) :
                    senderText + contentText
                ) +

                // Time
                // For some reason, if there's only one space,
                // times will be on their own lines most of the time.
                "  " +
                `<font size=${theme.fontSize.small}px ` +
                      `color=${theme.chat.message.date}>` +
                timeText +
                "</font>" +

                stateText

            transform: Translate { x: xOffset }

            Layout.maximumWidth: eventContent.maxMessageWidth
            Layout.fillWidth: true

            onSelectedTextChanged: if (selectedPlainText) {
                eventList.delegateWithSelectedText = model.id
                eventList.selectedText             = selectedPlainText
            } else if (eventList.delegateWithSelectedText === model.id) {
                eventList.delegateWithSelectedText = ""
                eventList.selectedText             = ""
            }

            Connections {
                target: eventList
                onCheckedChanged: contentLabel.deselect()
                onDelegateWithSelectedTextChanged: {
                    if (eventList.delegateWithSelectedText !== model.id)
                        contentLabel.deselect()
                }
            }

            HoverHandler { id: contentHover }

            PointHandler {
                id: mousePointHandler

                property bool checkedNow: false

                acceptedButtons: Qt.LeftButton
                acceptedModifiers: Qt.NoModifier
                acceptedPointerTypes:
                    PointerDevice.GenericPointer | PointerDevice.Eraser

                onActiveChanged: {
                    if (active &&
                            ! eventDelegate.checked &&
                            (! parent.hoveredLink ||
                            ! parent.enableLinkActivation)) {

                        eventList.check(model.index)
                        checkedNow = true
                    }

                    if (! active && eventDelegate.checked) {
                        checkedNow ?
                        checkedNow = false :
                        eventList.uncheck(model.index)
                    }
                }
            }

            PointHandler {
                id: mouseShiftPointHandler
                acceptedButtons: Qt.LeftButton
                acceptedModifiers: Qt.ShiftModifier
                acceptedPointerTypes:
                    PointerDevice.GenericPointer | PointerDevice.Eraser

                onActiveChanged: {
                    if (active &&
                            ! eventDelegate.checked &&
                            (! parent.hoveredLink ||
                            ! parent.enableLinkActivation)) {

                        eventList.checkFromLastToHere(model.index)
                    }
                }
            }

            TapHandler {
                id: touchTapHandler
                acceptedButtons: Qt.LeftButton
                acceptedPointerTypes: PointerDevice.Finger | PointerDevice.Pen
                onTapped:
                    if (! parent.hoveredLink || ! parent.enableLinkActivation)
                        eventDelegate.toggleChecked()
            }

            TapHandler {
                id: textSelectionBlocker
                acceptedPointerTypes: PointerDevice.Finger | PointerDevice.Pen
            }

            HToolTip {
                readonly property bool keyboardShow:
                    eventList.showFocusedSeenTooltips &&
                    eventList.currentIndex === model.index &&
                    model.read_by_count > 0

                instant: keyboardShow
                visible:
                    eventContent.hoveredLink === "#state-text" || keyboardShow

                label.textFormat: HLabel.StyledText
                text: {
                    if (! visible) return ""

                    if (model.is_local_echo) return qsTr("Sending message...")

                    const members =
                        ModelStore.get(chat.userId, chat.roomId, "members")

                    const readBy = Object.entries(
                        JSON.parse(model.last_read_by)
                    ).sort((a, b) => a[1] - b[1])  // sort by values (dates)

                    const lines  = []

                    for (const [userId, epoch] of readBy) {
                        const member = members.find(userId)

                        const by  = utils.coloredNameHtml(
                            member ? member.display_name: userId, userId,
                        )
                        const at = utils.formatRelativeTime(
                            new Date(epoch) - model.date,
                        )
                        lines.push(qsTr("Seen by %1 %2 after").arg(by).arg(at))
                    }

                    return lines.join("<br>")
                }
            }

            Rectangle {
                id: contentBackground
                width: Math.max(
                    parent.paintedWidth +
                    parent.leftPadding + parent.rightPadding,

                    linksRepeater.summedWidth +
                    (pureMedia ? 0 : parent.leftPadding + parent.rightPadding),
                )
                height: contentColumn.height
                radius: theme.chat.message.radius
                z: -100
                color: eventDelegate.checked &&
                       ! contentLabel.selectedPlainText &&
                       ! mousePointHandler.active &&
                       ! mouseShiftPointHandler.active ?
                       theme.chat.message.checkedBackground :

                       isOwn?
                       theme.chat.message.ownBackground :

                       theme.chat.message.background

                Behavior on color { HColorAnimation {} }

                Rectangle {
                    visible: model.event_type === "RoomMessageNotice"
                    // y: parent.height / 2 - height / 2
                    width: theme.chat.message.noticeLineWidth
                    height: parent.height
                    radius: parent.radius
                    color: utils.nameColor(
                        model.sender_name || model.sender_id.substring(1),
                    )
                }
            }
        }

        HRepeater {
            id: linksRepeater

            property EventMediaLoader lastHovered: null

            model: {
                const links = JSON.parse(eventDelegate.currentModel.links)

                if (eventDelegate.currentModel.media_url)
                    links.push(eventDelegate.currentModel.media_url)

                return links
            }

            EventMediaLoader {
                singleMediaInfo: eventDelegate.currentModel
                mediaUrl: modelData
                showSender: pureMedia ? senderText : ""
                showDate: pureMedia ? timeText : ""
                showLocalEcho: pureMedia && (
                    singleMediaInfo.is_local_echo ||
                    singleMediaInfo.read_by_count
                ) ? stateText : ""

                transform: Translate { x: xOffset }

                onHoveredChanged: if (hovered) linksRepeater.lastHovered = this

                Layout.bottomMargin: pureMedia ? 0 : contentLabel.bottomPadding
                Layout.leftMargin: pureMedia ? 0 : eventContent.spacing
                Layout.rightMargin: pureMedia ? 0 : eventContent.spacing
                Layout.preferredWidth: item ? item.width : -1
                Layout.preferredHeight: item ? item.height : -1
            }
        }
    }

    HSpacer {}
}
