// SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org>
// SPDX-License-Identifier: GPL-3.0-only

import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import QtMultimedia @QTMULTIMEDIA_MODULE_QML_VERSION@ 
import Qt.labs.platform 1.1 as Platform

import org.kde.kirigami 2.13 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as Components

import org.kde.neochat 1.0

/**
 * @brief A timeline delegate for a video message.
 *
 * @inherit TimelineContainer
 */
TimelineContainer {
    id: root

    /**
     * @brief The media info for the event.
     *
     * This should consist of the following:
     *  - source - The mxc URL for the media.
     *  - mimeType - The MIME type of the media (should be video/xxx for this delegate).
     *  - mimeIcon - The MIME icon name (should be video-xxx).
     *  - size - The file size in bytes.
     *  - duration - The length in seconds of the audio media.
     *  - width - The width in pixels of the audio media.
     *  - height - The height in pixels of the audio media.
     *  - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads.
     */
    required property var mediaInfo

    /**
     * @brief Whether the media has been downloaded.
     */
    readonly property bool downloaded: root.progressInfo && root.progressInfo.completed

    /**
     * @brief Whether the video should be played when downloaded.
     */
    property bool playOnFinished: false

    /**
     * @brief Whether the video can be streamed.
     */
    property bool supportStreaming: true

    /**
     * @brief The maximum width of the image.
     */
    readonly property var maxWidth: Kirigami.Units.gridUnit * 30

    /**
     * @brief The maximum height of the image.
     */
    readonly property var maxHeight: Kirigami.Units.gridUnit * 30

    onOpenContextMenu: openFileContext(vid)

    onDownloadedChanged: {
        if (downloaded) {
            vid.source = root.progressInfo.localPath
        }

        if (downloaded && playOnFinished) {
            playSavedFile()
            playOnFinished = false
        }
    }

    innerObject: Video {
        id: vid

        property var videoWidth: {
            if (root.mediaInfo.width > 0) {
                return root.mediaInfo.width;
            } else if (metaData.resolution && metaData.resolution.width) {
                return metaData.resolution.width;
            } else {
                return root.contentMaxWidth;
            }
        }
        property var videoHeight: {
            if (root.mediaInfo.height > 0) {
                return root.mediaInfo.height;
            } else if (metaData.resolution && metaData.resolution.height) {
                return metaData.resolution.height;
            } else {
                // Default to a 16:9 placeholder
                return root.contentMaxWidth / 16 * 9;
            }
        }

        readonly property var aspectRatio: videoWidth / videoHeight
        /**
         * Whether the video should be limited by height or width.
         * We need to prevent excessively tall as well as excessively wide media.
         *
         * @note In the case of a tie the media is width limited.
         */
        readonly property bool limitWidth: videoWidth >= videoHeight

        readonly property size maxSize: {
            if (limitWidth) {
                let width = Math.min(root.contentMaxWidth, root.maxWidth);
                let height = width / aspectRatio;
                return Qt.size(width, height);
            } else {
                let height = Math.min(root.maxHeight, root.contentMaxWidth / aspectRatio);
                let width = height * aspectRatio;
                return Qt.size(width, height);
            }
        }

        Layout.maximumWidth: maxSize.width
        Layout.maximumHeight: maxSize.height

        Layout.preferredWidth: videoWidth
        Layout.preferredHeight: videoHeight

        fillMode: VideoOutput.PreserveAspectFit
        @QTMULTIMEDIA_VIDEO_FLUSHMODE@

        states: [
            State {
                name: "notDownloaded"
                when: !root.progressInfo.completed && !root.progressInfo.active
                PropertyChanges {
                    target: noDownloadLabel
                    visible: true
                }
                PropertyChanges {
                    target: mediaThumbnail
                    visible: true
                }
            },
            State {
                name: "downloading"
                when: root.progressInfo.active && !root.progressInfo.completed
                PropertyChanges {
                    target: downloadBar
                    visible: true
                }
            },
            State {
                name: "paused"
                when: root.progressInfo.completed && (vid.playbackState === MediaPlayer.StoppedState || vid.playbackState === MediaPlayer.PausedState)
                PropertyChanges {
                    target: videoControls
                    stateVisible: true
                }
                PropertyChanges {
                    target: playButton
                    icon.name: "media-playback-start"
                    onClicked: vid.play()
                }
            },
            State {
                name: "playing"
                when: root.progressInfo.completed && vid.playbackState === MediaPlayer.PlayingState
                PropertyChanges {
                    target: videoControls
                    stateVisible: true
                }
                PropertyChanges {
                    target: playButton
                    icon.name: "media-playback-pause"
                    onClicked: vid.pause()
                }
            }
        ]

        onDurationChanged: {
            if (!duration) {
                vid.supportStreaming = false;
            }
        }

        onErrorChanged: {
            if (error != MediaPlayer.NoError) {
                vid.supportStreaming = false;
            }
        }

        Image {
            id: mediaThumbnail
            anchors.fill: parent
            visible: false

            source: root.mediaInfo.tempInfo.source
            fillMode: Image.PreserveAspectFit
        }

        QQC2.Label {
            id: noDownloadLabel
            anchors.centerIn: parent

            visible: false
            color: "white"
            text: i18n("Video")
            font.pixelSize: 16

            padding: 8

            background: Rectangle {
                radius: Kirigami.Units.smallSpacing
                color: "black"
                opacity: 0.3
            }
        }

        Rectangle {
            id: downloadBar
            anchors.fill: parent
            visible: false

            color: Kirigami.Theme.backgroundColor
            radius: Kirigami.Units.smallSpacing

            QQC2.ProgressBar {
                anchors.centerIn: parent

                width: parent.width * 0.8

                from: 0
                to: root.progressInfo.total
                value: root.progressInfo.progress
            }
        }

        QQC2.Control {
            id: videoControls
            property bool stateVisible: false

            anchors.bottom: vid.bottom
            anchors.left: vid.left
            anchors.right: vid.right
            visible: stateVisible && (videoHoverHandler.hovered || volumePopupHoverHandler.hovered || volumeSlider.hovered || videoControlTimer.running)

            contentItem: RowLayout {
                id: controlRow
                QQC2.ToolButton {
                    id: playButton
                }
                QQC2.Slider {
                    Layout.fillWidth: true
                    from: 0
                    to: vid.duration
                    value: vid.position
                    onMoved: vid.seek(value)
                }
                QQC2.Label {
                    text: Controller.formatDuration(vid.position) + "/" + Controller.formatDuration(vid.duration)
                }
                QQC2.ToolButton {
                    id: volumeButton
                    property var unmuteVolume: vid.volume

                    icon.name: vid.volume <= 0 ? "player-volume-muted" : "player-volume"

                    QQC2.ToolTip.visible: hovered
                    QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
                    QQC2.ToolTip.timeout: Kirigami.Units.toolTipDelay
                    QQC2.ToolTip.text: i18nc("@action:button", "Volume")

                    onClicked: {
                        if (vid.volume > 0) {
                            vid.volume = 0
                        } else {
                            if (unmuteVolume === 0) {
                                vid.volume = 1
                            } else {
                                vid.volume = unmuteVolume
                            }
                        }
                    }
                    onHoveredChanged: {
                        if (!hovered && (vid.state === "paused" || vid.state === "playing")) {
                            videoControlTimer.restart()
                            volumePopupTimer.restart()
                        }
                    }

                    QQC2.Popup {
                        id: volumePopup
                        y: -height
                        width: volumeButton.width
                        visible: videoControls.stateVisible && (volumeButton.hovered || volumePopupHoverHandler.hovered || volumeSlider.hovered || volumePopupTimer.running)

                        focus: true
                        padding: Kirigami.Units.smallSpacing
                        closePolicy: QQC2.Popup.NoAutoClose

                        QQC2.Slider {
                            id: volumeSlider
                            anchors.centerIn: parent
                            implicitHeight: Kirigami.Units.gridUnit * 7
                            orientation: Qt.Vertical
                            padding: 0
                            from: 0
                            to: 1
                            value: vid.volume
                            onMoved: {
                                vid.volume = value
                                volumeButton.unmuteVolume = value
                            }
                            onHoveredChanged: {
                                if (!hovered && (vid.state === "paused" || vid.state === "playing")) {
                                    videoControlTimer.restart()
                                    volumePopupTimer.restart()
                                }
                            }
                        }
                        Timer {
                            id: volumePopupTimer
                            interval: 500
                        }
                        HoverHandler {
                            id: volumePopupHoverHandler
                            onHoveredChanged: {
                                if (!hovered && (vid.state === "paused" || vid.state === "playing")) {
                                    videoControlTimer.restart()
                                    volumePopupTimer.restart()
                                }
                            }
                        }
                        background: Kirigami.ShadowedRectangle {
                            radius: 4
                            color: Kirigami.Theme.backgroundColor
                            opacity: 0.8

                            property color borderColor: Kirigami.Theme.textColor
                            border.color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3)
                            border.width: 1

                            shadow.xOffset: 0
                            shadow.yOffset: 4
                            shadow.color: Qt.rgba(0, 0, 0, 0.3)
                            shadow.size: 8
                        }
                    }
                }
                QQC2.ToolButton {
                    id: maximizeButton
                    display: QQC2.AbstractButton.IconOnly

                    action: Kirigami.Action {
                        text: i18n("Maximize")
                        icon.name: "view-fullscreen"
                        onTriggered: {
                            root.ListView.view.interactive = false
                            vid.pause()
                            root.ListView.view.showMaximizedMedia(root.index)
                        }
                    }
                }
            }
            background: Kirigami.ShadowedRectangle {
                radius: 4
                color: Kirigami.Theme.backgroundColor
                opacity: 0.8

                property color borderColor: Kirigami.Theme.textColor
                border.color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3)
                border.width: 1

                shadow.xOffset: 0
                shadow.yOffset: 4
                shadow.color: Qt.rgba(0, 0, 0, 0.3)
                shadow.size: 8
            }
        }

        Timer {
            id: videoControlTimer
            interval: 1000
        }
        HoverHandler {
            id: videoHoverHandler
            onHoveredChanged: {
                if (!hovered && (vid.state === "paused" || vid.state === "playing")) {
                    videoControlTimer.restart()
                }
            }
        }

        TapHandler {
            acceptedButtons: Qt.LeftButton
            onTapped: if (vid.supportStreaming || root.progressInfo.completed) {
                if (vid.playbackState == MediaPlayer.PlayingState) {
                    vid.pause()
                } else {
                    vid.play()
                }
            } else {
                root.downloadAndPlay()
            }
        }
    }

    function downloadAndPlay() {
        if (vid.downloaded) {
            playSavedFile()
        } else {
            playOnFinished = true
            currentRoom.downloadFile(root.eventId, Platform.StandardPaths.writableLocation(Platform.StandardPaths.CacheLocation) + "/" + root.eventId.replace(":", "_").replace("/", "_").replace("+", "_") + currentRoom.fileNameToDownload(root.eventId))
        }
    }

    function playSavedFile() {
        vid.stop()
        vid.play()
    }
}
