// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later

import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2
import Qt5Compat.GraphicalEffects

import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio

import '../delegate'

Item {
    id: root
    property Folio.HomeScreen folio

    // given by parent:

    property real widgetWidth
    property real widgetHeight
    property real widgetX
    property real widgetY

    property real widgetTopMargin
    property real widgetBottomMargin
    property real widgetLeftMargin
    property real widgetRightMargin

    property int widgetRow
    property int widgetColumn
    property int widgetGridWidth
    property int widgetGridHeight

    // filled here, given to parent:

    // what the drag intends for the dimensions and position of the widget
    property int widgetRowAfterDrag: 0
    property int widgetColumnAfterDrag: 0
    property int widgetGridWidthAfterDrag: 0
    property int widgetGridHeightAfterDrag: 0

    property var lockDrag: null
    readonly property int resizeAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
    readonly property color resizeAccentColor: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.85)

    property alias handleContainer: handleContainer

    signal widgetChangeAfterDrag(int widgetRow, int widgetColumn, int widgetGridWidth, int widgetGridHeight)

    // solely used here:

    property real startDragWidth: 0
    property real startDragHeight: 0
    property real startX: 0
    property real startY: 0

    property int startWidgetRow: 0
    property int startWidgetColumn: 0

    onWidgetWidthChanged: {
        if (lockDrag === null) updateDimensions();
    }
    onWidgetHeightChanged: {
        if (lockDrag === null) updateDimensions();
    }
    onWidgetXChanged: {
        if (lockDrag === null) updateDimensions();
    }
    onWidgetYChanged: {
        if (lockDrag === null) updateDimensions();
    }

    function updateDimensions() {
        handleContainer.width = widgetWidth;
        handleContainer.height = widgetHeight;
        handleContainer.x = widgetX;
        handleContainer.y = widgetY;
    }

    function startDrag() {
        startDragWidth = handleContainer.width;
        startDragHeight = handleContainer.height;
        startX = handleContainer.x;
        startY = handleContainer.y;

        startWidgetRow = root.widgetRow;
        startWidgetColumn = root.widgetColumn;

        root.widgetChangeAfterDrag(startWidgetRow, startWidgetColumn, root.widgetGridWidth, root.widgetGridHeight);
    }

    function snapEdges() {
        lockDrag = null;

        // snaps the bounds to what we ended up at
        widthAnim.to = widgetWidth;
        widthAnim.restart();
        heightAnim.to = widgetHeight;
        heightAnim.restart();
        xAnim.to = widgetX;
        xAnim.restart();
        yAnim.to = widgetY;
        yAnim.restart();
    }

    function pressedHandler(orientation) {
        if (root.lockDrag !== orientation) {
            root.startDrag();
            root.lockDrag = orientation;
        }
    }

    function dragHandler(orientation, leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta) {
        if (root.lockDrag === orientation) {
            // update the handle container dimensions and position
            handleContainer.x = root.startX - leftEdgeDelta;
            handleContainer.y = root.startY - topEdgeDelta;
            handleContainer.width = root.startDragWidth + rightEdgeDelta + leftEdgeDelta;
            handleContainer.height = root.startDragHeight + bottomEdgeDelta + topEdgeDelta;

            // update the widget dimensions and position
            const columnsMovedRight = Math.round((handleContainer.x - root.startX) / folio.HomeScreenState.pageCellWidth);
            const rowsMovedDown = Math.round((handleContainer.y - root.startY) / folio.HomeScreenState.pageCellHeight);

            const realWidgetWidth = handleContainer.width + widgetLeftMargin + widgetRightMargin;
            const realWidgetHeight = handleContainer.height + widgetTopMargin + widgetBottomMargin;

            const widgetRowAfterDrag = startWidgetRow + rowsMovedDown;
            const widgetColumnAfterDrag = startWidgetColumn + columnsMovedRight;
            const widgetGridWidthAfterDrag = Math.round(realWidgetWidth / folio.HomeScreenState.pageCellWidth);
            const widgetGridHeightAfterDrag = Math.round(realWidgetHeight / folio.HomeScreenState.pageCellHeight);

            root.widgetChangeAfterDrag(widgetRowAfterDrag, widgetColumnAfterDrag, widgetGridWidthAfterDrag, widgetGridHeightAfterDrag);
        }
    }

    function releaseHandler(orientation) {
        if (root.lockDrag === orientation) {
            root.snapEdges();
        }
    }

    Item {
        id: handleContainer

        MobileShell.MotionNumberAnimation on width {
            id: widthAnim
            type: MobileShell.Motion.SpatialDefault
            duration: root.resizeAnimationDuration
        }

        MobileShell.MotionNumberAnimation on height {
            id: heightAnim
            type: MobileShell.Motion.SpatialDefault
            duration: root.resizeAnimationDuration
        }

        MobileShell.MotionNumberAnimation on x {
            id: xAnim
            type: MobileShell.Motion.SpatialDefault
            duration: root.resizeAnimationDuration
        }

        MobileShell.MotionNumberAnimation on y {
            id: yAnim
            type: MobileShell.Motion.SpatialDefault
            duration: root.resizeAnimationDuration
        }
    }

    Rectangle {
        id: resizeOutline
        color: 'transparent'
        border.color: root.resizeAccentColor
        radius: Kirigami.Units.cornerRadius
        border.width: 1

        anchors.fill: handleContainer
        anchors.leftMargin: -root.widgetLeftMargin
        anchors.rightMargin: -root.widgetRightMargin
        anchors.topMargin: -root.widgetTopMargin
        anchors.bottomMargin: -root.widgetBottomMargin
    }

    WidgetResizeHandle {
        id: topHandle
        orientation: WidgetHandlePosition.TopCenter

        x: resizeOutline.x + Math.round(resizeOutline.width / 2) - Math.round(width / 2)
        y: resizeOutline.y - Math.round(height / 2)

        width: Math.round(Math.max(height, resizeOutline.width * 0.3)) + touchPadding * 2

        onPressed: pressedHandler(orientation)
        onDragEvent: (leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta) => dragHandler(orientation, leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta)
        onReleased: releaseHandler(orientation)
    }

    WidgetResizeHandle {
        id: leftHandle
        orientation: WidgetHandlePosition.LeftCenter

        x: resizeOutline.x - (width / 2)
        y: resizeOutline.y + (resizeOutline.height / 2) - (height / 2)

        height: Math.round(Math.max(width, resizeOutline.height * 0.3)) + touchPadding * 2

        onPressed: pressedHandler(orientation)
        onDragEvent: (leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta) => dragHandler(orientation, leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta)
        onReleased: releaseHandler(orientation)
    }

    WidgetResizeHandle {
        id: rightHandle
        orientation: WidgetHandlePosition.RightCenter

        x: resizeOutline.x + resizeOutline.width - (width / 2)
        y: resizeOutline.y + (resizeOutline.height / 2) - (height / 2)

        height: Math.round(Math.max(width, resizeOutline.height * 0.3)) + touchPadding * 2

        onPressed: pressedHandler(orientation)
        onDragEvent: (leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta) => dragHandler(orientation, leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta)
        onReleased: releaseHandler(orientation)
    }

    WidgetResizeHandle {
        id: bottomHandle
        orientation: WidgetHandlePosition.BottomCenter

        x: resizeOutline.x + (resizeOutline.width / 2) - (width / 2)
        y: resizeOutline.y + resizeOutline.height - (height / 2)

        width: Math.round(Math.max(height, resizeOutline.width * 0.3)) + touchPadding * 2

        onPressed: pressedHandler(orientation)
        onDragEvent: (leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta) => dragHandler(orientation, leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta)
        onReleased: releaseHandler(orientation)
    }
}
