// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later

import "./components"
import "./emoji"
import "./ui"
import "./voip"
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Window
import im.nheko

Item {
    id: timelineView

    required property PrivacyScreen privacyScreen
    property var room: null
    property var roomPreview: null
    property bool shouldEffectsRun: false
    property bool showBackButton: false

    clip: true

    // focus message input on key press, but not on Ctrl-C and such.
    Keys.onPressed: event => {
        if (event.text && event.key !== Qt.Key_Enter && event.key !== Qt.Key_Return && !topBar.searchHasFocus) {
            TimelineManager.focusMessageInput();
            if (event.modifiers != Qt.ControlModifier) {
                room.input.setText(room.input.text + event.text);
            }
        }
    }
    onRoomChanged: if (room != null)
        room.triggerSpecialEffects()

    StickerPicker {
        id: emojiPopup

        emoji: true
    }
    Shortcut {
        sequences: [StandardKey.Close]

        onActivated: Rooms.resetCurrentRoom()
    }
    Label {
        anchors.centerIn: parent
        font.pointSize: 24
        text: qsTr("No room open")
        color: palette.text
        visible: !room && !TimelineManager.isInitialSync && (!roomPreview || !roomPreview.roomid)
    }
    Spinner {
        anchors.centerIn: parent
        foreground: palette.mid
        // height is somewhat arbitrary here... don't set width because width scales w/ height
        height: parent.height / 16
        opacity: hh.hovered ? 0.3 : 1
        running: TimelineManager.isInitialSync
        visible: TimelineManager.isInitialSync
        z: 3

        Behavior on opacity  {
            NumberAnimation {
                duration: 100
            }
        }

        HoverHandler {
            id: hh

        }
    }
    ColumnLayout {
        id: timelineLayout

        anchors.fill: parent
        enabled: visible
        spacing: 0
        visible: room != null && !room.isSpace

        TopBar {
            id: topBar

            showBackButton: timelineView.showBackButton
        }
        Rectangle {
            Layout.fillWidth: true
            color: Nheko.theme.separator
            implicitHeight: 1
            z: 3
        }
        Rectangle {
            id: msgView

            Layout.fillHeight: true
            Layout.fillWidth: true
            color: palette.base

            ColumnLayout {
                anchors.fill: parent
                spacing: 0

                StackLayout {
                    id: stackLayout

                    currentIndex: 0

                    Connections {
                        function onRoomChanged() {
                            stackLayout.currentIndex = 0;
                        }

                        target: timelineView
                    }
                    MessageView {
                        Layout.fillWidth: true
                        implicitHeight: msgView.height - typingIndicator.height
                        searchString: topBar.searchString
                    }
                    Loader {
                        source: CallManager.isOnCall && CallManager.callType != Voip.VOICE ? (Qt.platform.os != "windows" ? "voip/VideoCall.qml" : "voip/VideoCallD3D11.qml") : ""

                        onLoaded: TimelineManager.setVideoCallItem()
                    }
                }
                TypingIndicator {
                    id: typingIndicator

                }
            }
        }
        CallInviteBar {
            id: callInviteBar

            Layout.fillWidth: true
            z: 3
        }
        ActiveCallBar {
            Layout.fillWidth: true
            z: 3
        }
        Rectangle {
            Layout.fillWidth: true
            color: Nheko.theme.separator
            implicitHeight: 1
            z: 3
        }
        UploadBox {
        }
        Repeater {
            model: room ? room.input.mentions : null

            MessageInputWarning {
                required property string modelData
                bubbleColor: modelData == "@room" ? Nheko.theme.error : Nheko.theme.orange
                text: modelData == "@room" ? qsTr("You are about to notify the whole room") : qsTr("You will be mentioning %1").arg(modelData)
                showRemove: true
                onRemoveClicked: room.input.removeMention(modelData);
            }
        }
        MessageInputWarning {
            text: qsTr("The command /%1 is not recognized and will be sent as part of your message").arg(room ? room.input.currentCommand : "")
            visible: room ? room.input.containsInvalidCommand && !room.input.containsIncompleteCommand : false
        }
        MessageInputWarning {
            bubbleColor: Nheko.theme.orange
            text: qsTr("/%1 looks like an incomplete command. To send it anyway, add a space to the end of your message.").arg(room ? room.input.currentCommand : "")
            visible: room ? room.input.containsIncompleteCommand : false
        }
        ReplyPopup {
        }
        MessageInput {
        }
    }
    ColumnLayout {
        id: preview

        property string avatarUrl: room ? room.roomAvatarUrl : (roomPreview ? roomPreview.roomAvatarUrl : "")
        property string reason: roomPreview ? roomPreview.reason : ""
        property string roomId: room ? room.roomId : (roomPreview ? roomPreview.roomid : "")
        property string roomName: room ? room.roomName : (roomPreview ? roomPreview.roomName : "")
        property string roomTopic: room ? room.roomTopic : (roomPreview ? roomPreview.roomTopic : "")

        anchors.fill: parent
        anchors.margins: Nheko.paddingLarge
        enabled: visible
        spacing: Nheko.paddingLarge
        visible: room != null && room.isSpace || roomPreview != null

        Item {
            Layout.fillHeight: true
            Layout.fillWidth: true
        }
        Avatar {
            Layout.alignment: Qt.AlignHCenter
            displayName: parent.roomName
            enabled: false
            implicitHeight: 130
            roomid: parent.roomId
            url: parent.avatarUrl.replace("mxc://", "image://MxcImage/")
            implicitWidth: 130
        }

        MatrixText {
            horizontalAlignment: TextEdit.AlignHCenter
            Layout.fillWidth: true
            font.pixelSize: 24
            text: (!room && !(roomPreview?.isFetched ?? false)) ? qsTr("No preview available") : preview.roomName

        }
        ImageButton {
            Layout.alignment: Qt.AlignHCenter
            ToolTip.text: qsTr("Settings")
            ToolTip.visible: hovered
            Layout.bottomMargin: Nheko.paddingMedium

            hoverEnabled: true
            image: ":/icons/icons/ui/settings.svg"
            visible: !!room

            onClicked: TimelineManager.openRoomSettings(room.roomId)
        }

        RowLayout {
            Layout.alignment: Qt.AlignHCenter
            spacing: Nheko.paddingMedium
            visible: !!room
            Layout.fillWidth: true

            MatrixText {
                Layout.preferredWidth: contentWidth
                text: qsTr("%n member(s)", "", room ? room.roomMemberCount : 0)
            }
            ImageButton {
                ToolTip.text: qsTr("View members of %1").arg(room ? room.roomName : "")
                ToolTip.visible: hovered
                hoverEnabled: true
                image: ":/icons/icons/ui/people.svg"

                onClicked: TimelineManager.openRoomMembers(room)
            }
        }
        ScrollView {
            Layout.alignment: Qt.AlignHCenter
            Layout.fillWidth: true
            Layout.leftMargin: Nheko.paddingLarge
            Layout.rightMargin: Nheko.paddingLarge
            Layout.maximumHeight: timelineView.height / 3

            MatrixText {
                background: null
                horizontalAlignment: TextEdit.AlignHCenter
                text: (room || (roomPreview?.isFetched ?? false)) ? TimelineManager.escapeEmoji(preview.roomTopic) : qsTr("This room is possibly inaccessible. If this room is private, you should remove it from this community.")
                textFormat: TextEdit.RichText
            }
        }
        FlatButton {
            Layout.alignment: Qt.AlignHCenter
            text: qsTr("join the conversation")
            visible: roomPreview && !roomPreview.isInvite

            onClicked: Rooms.joinPreview(roomPreview.roomid)
        }
        FlatButton {
            Layout.alignment: Qt.AlignHCenter
            text: qsTr("accept invite")
            visible: roomPreview && roomPreview.isInvite

            onClicked: Rooms.acceptInvite(roomPreview.roomid)
        }
        FlatButton {
            Layout.alignment: Qt.AlignHCenter
            text: qsTr("decline invite")
            visible: roomPreview && roomPreview.isInvite

            onClicked: Rooms.declineInvite(roomPreview.roomid)
        }
        FlatButton {
            Layout.alignment: Qt.AlignHCenter
            text: qsTr("decline invite and ignore user")
            visible: roomPreview && roomPreview.isInvite

            onClicked: {
                var inviter = TimelineManager.getGlobalUserProfile(roomPreview.inviterUserId)
                inviter.ignored = true
            }
        }
        FlatButton {
            Layout.alignment: Qt.AlignHCenter
            text: qsTr("leave")
            visible: !!room

            onClicked: TimelineManager.openLeaveRoomDialog(room.roomId)
        }
        RowLayout {
            Layout.alignment: Qt.AlignHCenter
            Layout.fillWidth: true
            spacing: Nheko.paddingMedium
            visible: roomPreview && roomPreview.isInvite && reasonField.showReason

            MatrixText {
                Layout.maximumWidth: contentWidth
                Layout.preferredWidth: contentWidth
                Layout.fillWidth: true
                text: qsTr("Invited by %1 (%2)").arg(TimelineManager.escapeEmoji(inviterAvatar.displayName)).arg(TimelineManager.escapeEmoji(TimelineManager.htmlEscape(inviterAvatar.userid)))
            }
            Avatar {
                id: inviterAvatar

                Layout.alignment: Qt.AlignHCenter
                displayName: roomPreview?.inviterDisplayName ?? ""
                enabled: true
                implicitHeight: 48
                roomid: preview.roomId
                url: (roomPreview?.inviterAvatarUrl ?? "").replace("mxc://", "image://MxcImage/")
                userid: roomPreview?.inviterUserId ?? ""
                implicitWidth: 48

                onClicked: TimelineManager.openGlobalUserProfile(roomPreview.inviterUserId)
            }
        }
        ScrollView {
            id: reasonField

            property bool showReason: false

            Layout.alignment: Qt.AlignHCenter
            Layout.fillWidth: true
            visible: preview.reason !== "" && showReason

            TextArea {
                background: null
                horizontalAlignment: TextEdit.AlignHCenter
                readOnly: true
                selectByMouse: true
                text: TimelineManager.escapeEmoji(preview.reason)
                textFormat: TextEdit.RichText
                wrapMode: TextEdit.WordWrap
            }
        }
        Button {
            id: showReasonButton

            Layout.alignment: Qt.AlignHCenter
            //Layout.fillWidth: true
            Layout.leftMargin: Nheko.paddingLarge
            Layout.rightMargin: Nheko.paddingLarge
            text: reasonField.showReason ? qsTr("Hide invite reason") : qsTr("Show invite reason")
            visible: roomPreview && roomPreview.isInvite

            onClicked: {
                reasonField.showReason = !reasonField.showReason;
            }
        }
        Item {
            Layout.preferredHeight: Math.ceil(fontMetrics.lineSpacing * 2)
            visible: room != null
        }
        Item {
            Layout.fillHeight: true
        }
    }

    ImageButton {
        id: backToRoomsButton

        ToolTip.text: qsTr("Back to room list")
        ToolTip.visible: hovered
        anchors.left: parent.left
        anchors.margins: Nheko.paddingMedium
        anchors.top: parent.top
        enabled: visible
        height: Nheko.avatarSize
        image: ":/icons/icons/ui/angle-arrow-left.svg"
        visible: (room == null || room.isSpace) && showBackButton
        width: Nheko.avatarSize

        onClicked: Rooms.resetCurrentRoom()
    }
    TimelineEffects {
        id: timelineEffects

        anchors.fill: parent
        shouldEffectsRun: timelineView.shouldEffectsRun
    }
    NhekoDropArea {
        anchors.fill: parent
        roomid: room ? room.roomId : ""
    }
    Timer {
        id: effectsTimer

        interval: timelineEffects.maxLifespan
        repeat: false
        running: false

        onTriggered: {
            timelineEffects.removeParticles()
            shouldEffectsRun = false
        }
    }
    Connections {
        function onConfetti() {
            if (!Settings.fancyEffects)
                return;
            shouldEffectsRun = true;
            timelineEffects.pulseConfetti();
            room.markSpecialEffectsDone();
        }
        function onConfettiDone() {
            if (!Settings.fancyEffects)
                return;
            effectsTimer.restart();
        }
        function onOpenReadReceiptsDialog(rr) {
            var dialog = readReceiptsDialog.createObject(timelineRoot, {
                    "readReceipts": rr,
                    "room": room
                });
            dialog.show();
            timelineRoot.destroyOnClose(dialog);
        }
        function onRainfall() {
            if (!Settings.fancyEffects)
                return;
            shouldEffectsRun = true;
            timelineEffects.pulseRainfall();
            room.markSpecialEffectsDone();
        }
        function onRainfallDone() {
            if (!Settings.fancyEffects)
                return;
            effectsTimer.restart();
        }
        function onShowRawMessageDialog(rawMessage) {
            var component = Qt.createComponent("qrc:/resources/qml/dialogs/RawMessageDialog.qml");
            if (component.status == Component.Ready) {
                var dialog = component.createObject(timelineRoot, {
                        "rawMessage": rawMessage
                    });
                dialog.show();
                timelineRoot.destroyOnClose(dialog);
            } else {
                console.error("Failed to create component: " + component.errorString());
            }
        }

        target: room
    }
}
