// 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 Controls

import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.components 3.0 as PC3
import org.kde.kirigami as Kirigami

import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio

import "./delegate"

MobileShell.GridView {
    id: root
    property Folio.HomeScreen folio

    cacheBuffer: cellHeight * 20
    reuseItems: true
    layer.enabled: true

    keyNavigationEnabled: true
    highlightMoveDuration: 0
    highlight: null // We supply our own highlight from the delegate

    property var homeScreen
    property real headerHeight

    readonly property int reservedSpaceForLabel: folio.HomeScreenState.pageDelegateLabelHeight
    readonly property int scrollBarAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialExtended)
    readonly property real effectiveContentWidth: width - leftMargin - rightMargin
    readonly property real horizontalMargin: Math.round(width * 0.05)

    leftMargin: horizontalMargin
    rightMargin: horizontalMargin

    cellWidth: effectiveContentWidth / Math.min(Math.floor(effectiveContentWidth / (folio.FolioSettings.delegateIconSize + Kirigami.Units.largeSpacing * 3.5)), 8)
    cellHeight: cellWidth + reservedSpaceForLabel

    boundsBehavior: Flickable.DragAndOvershootBounds

    readonly property int columns: Math.floor(effectiveContentWidth / cellWidth)
    readonly property int rows: Math.ceil(root.count / columns)

    // HACK: the first swipe from the top of the app drawer is done from HomeScreenState, not the flickable
    //       due to issues with Flickable getting its swipe stolen by SwipeArea
    // In convergence mode the drawer is a popup opened by a button — no swipe-open gesture,
    // so the grid must always be scrollable via mouse wheel/drag.
    interactive: ShellSettings.Settings.convergenceModeEnabled
                    || ((dragging || !atYBeginning) // allow us to drag to the top
                        && folio.HomeScreenState.swipeState !== Folio.HomeScreenState.SwipingAppDrawerGrid)

    Connections {
        target: folio.HomeScreenState

        function onSwipeStateChanged() {
            if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.SwipingAppDrawerGrid) {
                velocityCalculator.startMeasure();
                velocityCalculator.changePosition(root.contentY);
            }
        }

        function onAppDrawerGridYChanged(y) {
            const maxContentY = Math.max(0, root.contentHeight - root.height);
            let contentY = root.contentY - y;

            if (root.contentHeight < root.height) {
                // prevent bottom overscroll only if contents are smaller than the view
                contentY = Math.min(maxContentY, contentY);
            }

            root.contentY = contentY;
            velocityCalculator.changePosition(root.contentY);
        }

        function onAppDrawerGridFlickRequested() {
            root.flick(0, -velocityCalculator.velocity);
        }
    }

    MobileShell.VelocityCalculator {
        id: velocityCalculator
    }

    MobileShell.HapticsEffect {
        id: haptics
    }

    model: folio.ApplicationListSearchModel

    // Keyboard focus on app delegate when it is the selected item
    onCurrentItemChanged: {
        if (currentItem) {
            currentItem.keyboardFocus();
        }
    }

    delegate: AppDelegate {
        id: appDelegate

        folio: root.folio
        shadow: false
        application: model.delegate.application

        width: root.cellWidth
        height: root.cellHeight

        onPressAndHold: {
            // prevent editing if lock layout is enabled
            if (folio.FolioSettings.lockLayout) return;

            const mappedCoords = root.homeScreen.prepareStartDelegateDrag(model.delegate, appDelegate.delegateItem, true);
            folio.HomeScreenState.closeAppDrawer();
            haptics.buttonVibrate();

            // we need to adjust because app drawer delegates have a different size than regular homescreen delegates
            const centerX = mappedCoords.x + root.cellWidth / 2;
            const centerY = mappedCoords.y + root.cellHeight / 2;

            folio.HomeScreenState.startDelegateAppDrawerDrag(
                centerX - folio.HomeScreenState.pageCellWidth / 2,
                centerY - folio.HomeScreenState.pageCellHeight / 2,
                appDelegate.pressPosition.x * (folio.HomeScreenState.pageCellWidth / root.cellWidth),
                appDelegate.pressPosition.y * (folio.HomeScreenState.pageCellHeight / root.cellHeight),
                model.delegate.application.storageId
            );
        }
    }

    PC3.ScrollBar.vertical: PC3.ScrollBar {
        id: scrollBar
        interactive: true
        enabled: true
        implicitWidth: Kirigami.Units.smallSpacing

        Behavior on opacity {
            OpacityAnimator {
                duration: root.scrollBarAnimationDuration
                easing.type: MobileShell.Motion.easing(MobileShell.Motion.Standard)
            }
        }

        contentItem: Rectangle {
            radius: width / 2
            color: Qt.rgba(1, 1, 1, 0.3)
        }
    }
}
