// SPDX-FileCopyrightText: 2022 Devin Lin <espidev@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later

import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as Controls
import QtQuick.Effects

import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.kquickcontrolsaddons 2.0

import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.plasmoid

import org.kde.kirigami as Kirigami

Item {
    id: delegate
    property MobileShell.MaskManager maskManager

    property int visualIndex: 0
    property real dragFolderAnimationProgress: 0

    property list<Kirigami.Action> menuActions

    // whether this delegate is a folder
    property bool isFolder

    // folder object
    property var folder
    readonly property string folderName: folder ? folder.name : ""

    // app object
    property var application
    readonly property string applicationName: application ? application.name : ""
    readonly property string applicationStorageId: application ? application.storageId : ""
    readonly property string applicationIcon: application ? application.icon : ""
    readonly property int pressAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
    readonly property color pressFeedbackColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.18)
    readonly property color folderFeedbackColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.24)

    signal folderOpenRequested()

    property alias drag: mouseArea.drag
    Drag.active: delegate.drag.active
    Drag.source: delegate
    Drag.hotSpot.x: delegate.width / 2
    Drag.hotSpot.y: delegate.height / 2

    // close context menu if drag move
    onXChanged: {
        if (dialogLoader.item) {
            dialogLoader.item.close()
        }
    }
    onYChanged: {
        if (dialogLoader.item) {
            dialogLoader.item.close()
        }
    }

    function openContextMenu() {
        dialogLoader.active = true;
        dialogLoader.item.open();
    }

    function launch() {
        if (isFolder) {
            folderOpenRequested();
        } else {
            if (application.running) {
                launchAppWithAnim(0, 0, "", applicationName, applicationStorageId);
            } else {
                launchAppWithAnim(delegate.x + (Kirigami.Units.smallSpacing * 2), delegate.y + (Kirigami.Units.smallSpacing * 2), delegate.applicationIcon, applicationName, applicationStorageId);
            }
        }
    }

    function launchAppWithAnim(x: int, y: int, source, title: string, storageId: string) {
        if (source !== "") {
            MobileShellState.ShellDBusClient.openAppLaunchAnimationWithPosition(
                Plasmoid.screen,
                source,
                title,
                storageId,
                iconLoader.Kirigami.ScenePosition.x + iconLoader.width/2,
                iconLoader.Kirigami.ScenePosition.y + iconLoader.height/2,
                Math.min(iconLoader.width, iconLoader.height));
        }

        application.setMinimizedDelegate(delegate);
        MobileShell.AppLaunch.launchOrActivateApp(application.storageId);
    }

    Loader {
        id: dialogLoader
        active: false

        sourceComponent: PlasmaComponents.Menu {
            id: menu
            title: label.text
            closePolicy: PlasmaComponents.Menu.CloseOnReleaseOutside | PlasmaComponents.Menu.CloseOnEscape

            Repeater {
                model: menuActions
                delegate: PlasmaComponents.MenuItem {
                    icon.name: modelData.iconName
                    text: modelData.text
                    onClicked: modelData.triggered()
                }
            }

            onClosed: dialogLoader.active = false
        }
    }

    MouseArea {
        id: mouseArea

        anchors.fill: parent

        property bool inDrag: false

        cursorShape: Qt.PointingHandCursor
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        onReleased: {
            delegate.Drag.drop();
            inDrag = false;
        }
        onPressAndHold: { inDrag = true; openContextMenu() }
        drag.target: inDrag ? delegate : undefined

        // grow/shrink animation
        property real zoomScale: 1
        transform: Scale {
            origin.x: mouseArea.width / 2;
            origin.y: mouseArea.height / 2;
            xScale: mouseArea.zoomScale
            yScale: mouseArea.zoomScale
        }

        property bool launchAppRequested: false

        MobileShell.MotionNumberAnimation on zoomScale {
            id: shrinkAnim
            type: MobileShell.Motion.Press
            running: false
            duration: delegate.pressAnimationDuration
            to: MobileShell.Motion.pressScaleIn
            onFinished: {
                if (!mouseArea.pressed) {
                    growAnim.restart();
                }
            }
        }

        MobileShell.MotionNumberAnimation on zoomScale {
            id: growAnim
            type: MobileShell.Motion.Press
            running: false
            duration: delegate.pressAnimationDuration
            to: 1
            onFinished: {
                if (mouseArea.launchAppRequested) {
                    delegate.launch();
                    mouseArea.launchAppRequested = false;
                }
            }
        }

        onPressedChanged: {
            if (pressed) {
                growAnim.stop();
                shrinkAnim.restart();
            } else if (!pressed && !shrinkAnim.running) {
                growAnim.restart();
            }
        }

        // launch app handled by press animation
        onClicked: mouse => {
            if (mouse.button === Qt.RightButton) {
                openContextMenu();
            } else {
                launchAppRequested = true;
            }
        }

        Rectangle {
            anchors.fill: parent
            radius: height / 2
            color: mouseArea.pressed ? delegate.pressFeedbackColor : "transparent"
        }

        RowLayout {
            id: rowLayout
            anchors {
                fill: parent
                leftMargin: Kirigami.Units.smallSpacing * 2
                topMargin: Kirigami.Units.smallSpacing
                rightMargin: Kirigami.Units.smallSpacing * 2
                bottomMargin: Kirigami.Units.smallSpacing
            }
            spacing: 0

            Loader {
                id: iconLoader
                Layout.alignment: Qt.AlignLeft
                Layout.minimumWidth: Layout.minimumHeight
                Layout.preferredWidth: Layout.minimumHeight
                Layout.minimumHeight: parent.height
                Layout.preferredHeight: Layout.minimumHeight

                sourceComponent: delegate.isFolder ? folderIconComponent : appIconComponent
            }

            PlasmaComponents.Label {
                id: label
                visible: text.length > 0
                textFormat: Text.MarkdownText

                Layout.fillWidth: true
                Layout.leftMargin: Kirigami.Units.smallSpacing * 2
                Layout.rightMargin: Kirigami.Units.gridUnit
                wrapMode: Text.WordWrap
                maximumLineCount: 1
                elide: Text.ElideRight

                text: delegate.isFolder ? delegate.folderName : delegate.applicationName

                font.pointSize: Kirigami.Theme.defaultFont.pointSize
                font.weight: Font.Bold
                color: "white"

                layer.enabled: true
                layer.effect: MobileShell.TextDropShadow {}
            }

            Kirigami.Icon {
                Layout.alignment: Qt.AlignRight
                Layout.preferredWidth: Kirigami.Units.iconSizes.small
                Layout.preferredHeight: Kirigami.Units.iconSizes.small

                isMask: true
                color: 'white'
                source: 'arrow-right'
                visible: delegate.isFolder

                layer.enabled: true
                layer.effect: MultiEffect {
                    shadowEnabled: true
                    shadowVerticalOffset: 1
                    blurMax: 8
                    shadowOpacity: 0.7
                }
            }
        }
    }

    Component {
        id: appIconComponent

        Item {
            Rectangle {
                anchors.fill: parent
                anchors.margins: Kirigami.Units.smallSpacing
                color: delegate.folderFeedbackColor
                radius: Kirigami.Units.cornerRadius
                opacity: delegate.dragFolderAnimationProgress

                Component.onCompleted: {
                    if (maskManager) {
                        maskManager.assignToMask(this)
                    }
                }
            }

            Kirigami.Icon {
                id: icon
                anchors.fill: parent
                source: delegate.isFolder ? 'document-open-folder' : delegate.applicationIcon

                transform: Scale {
                    origin.x: icon.width / 2
                    origin.y: icon.height / 2
                    xScale: 1 - delegate.dragFolderAnimationProgress * 0.5
                    yScale: 1 - delegate.dragFolderAnimationProgress * 0.5
                }

                Rectangle {
                    anchors {
                        horizontalCenter: parent.horizontalCenter
                        bottom: parent.bottom
                    }
                    visible: application ? application.running : false
                    radius: width
                    width: Kirigami.Units.smallSpacing
                    height: width
                    color: Kirigami.Theme.highlightColor
                }

                layer.enabled: true
                layer.effect: MultiEffect {
                    shadowEnabled: true
                    shadowVerticalOffset: 1
                    blurMax: 16
                    shadowOpacity: 0.5
                }
            }
        }
    }

    Component {
        id: folderIconComponent

        Item {
            Rectangle {
                id: rect
                anchors.fill: parent
                anchors.margins: Kirigami.Units.smallSpacing
                color: delegate.folderFeedbackColor
                radius: Kirigami.Units.cornerRadius

                transform: Scale {
                    origin.x: rect.width / 2
                    origin.y: rect.height / 2
                    xScale: 1 + delegate.dragFolderAnimationProgress * 0.5
                    yScale: 1 + delegate.dragFolderAnimationProgress * 0.5
                }

                Component.onCompleted: {
                    if (maskManager) {
                        maskManager.assignToMask(this)
                    }
                }
            }

            Grid {
                id: grid
                anchors.fill: parent
                anchors.margins: Kirigami.Units.smallSpacing * 2
                columns: 2
                spacing: Kirigami.Units.smallSpacing

                property var previews: model.folder.appPreviews

                Repeater {
                    model: grid.previews
                    delegate: Kirigami.Icon {
                        implicitWidth: (grid.width - Kirigami.Units.smallSpacing) / 2
                        implicitHeight: (grid.width - Kirigami.Units.smallSpacing) / 2
                        source: modelData.icon

                        layer.enabled: true
                        layer.effect: MultiEffect {
                            shadowEnabled: true
                            shadowVerticalOffset: 1
                            blurMax: 16
                            shadowOpacity: 0.6
                        }
                    }
                }
            }
        }
    }
}



