import QtQuick
import qs.Common
import qs.Services
import qs.Widgets

DankListView {
    id: listView

    property var keyboardController: null
    property bool keyboardActive: false
    property bool autoScrollDisabled: false
    property bool isAnimatingExpansion: false
    property alias listContentHeight: listView.contentHeight
    property real stableContentHeight: 0
    property bool cardAnimateExpansion: true
    property bool listInitialized: false
    property int swipingCardIndex: -1
    property real swipingCardOffset: 0
    property bool _stableHeightUpdatePending: false
    property var transientSurfaceTracker: null
    readonly property real shadowBlurPx: Theme.elevationEnabled ? ((Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined) ? Theme.elevationLevel1.blurPx : 4) : 0
    readonly property real shadowHorizontalGutter: Theme.snap(Math.max(Theme.spacingS, Math.min(32, shadowBlurPx * 1.5 + 6)), 1)
    readonly property real shadowVerticalGutter: Theme.snap(Math.max(Theme.spacingXS, 6), 1)
    readonly property real delegateShadowGutter: Theme.snap(Math.max(Theme.spacingXS, 4), 1)

    Component.onCompleted: {
        Qt.callLater(() => {
            if (listView) {
                listView.listInitialized = true;
                listView.syncStableContentHeight(false);
            }
        });
    }

    function targetContentHeight() {
        if (count <= 0)
            return contentHeight;

        let total = topMargin + bottomMargin + Math.max(0, count - 1) * spacing;
        for (let i = 0; i < count; i++) {
            const item = itemAtIndex(i);
            if (!item || item.nonAnimHeight === undefined)
                return contentHeight;
            total += item.nonAnimHeight;
        }
        return Math.max(0, total);
    }

    function syncStableContentHeight(useTarget) {
        const nextHeight = useTarget ? targetContentHeight() : contentHeight;
        if (Math.abs(nextHeight - stableContentHeight) <= 0.5)
            return;
        stableContentHeight = nextHeight;
    }

    function queueStableContentHeightUpdate(useTarget) {
        if (_stableHeightUpdatePending)
            return;
        _stableHeightUpdatePending = true;
        Qt.callLater(() => {
            _stableHeightUpdatePending = false;
            syncStableContentHeight(useTarget || isAnimatingExpansion);
        });
    }

    onContentHeightChanged: {
        if (!isAnimatingExpansion)
            queueStableContentHeightUpdate(false);
    }

    onIsAnimatingExpansionChanged: {
        if (isAnimatingExpansion) {
            syncStableContentHeight(true);
        } else {
            queueStableContentHeightUpdate(false);
        }
    }

    clip: true
    model: NotificationService.groupedNotifications
    spacing: Theme.spacingL
    topMargin: shadowVerticalGutter
    bottomMargin: shadowVerticalGutter

    onIsUserScrollingChanged: {
        if (isUserScrolling && keyboardController && keyboardController.keyboardNavigationActive) {
            autoScrollDisabled = true;
        }
    }

    function enableAutoScroll() {
        autoScrollDisabled = false;
    }

    Timer {
        id: positionPreservationTimer
        interval: 200
        running: keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled && !isAnimatingExpansion
        repeat: true
        onTriggered: {
            if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled && !isAnimatingExpansion) {
                keyboardController.ensureVisible();
            }
        }
    }

    Timer {
        id: expansionEnsureVisibleTimer
        interval: Theme.mediumDuration + 50
        repeat: false
        onTriggered: {
            if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) {
                keyboardController.ensureVisible();
            }
        }
    }

    NotificationEmptyState {
        visible: listView.count === 0
        y: 20
        anchors.horizontalCenter: parent.horizontalCenter
    }

    onModelChanged: {
        if (!keyboardController || !keyboardController.keyboardNavigationActive) {
            return;
        }
        keyboardController.rebuildFlatNavigation();
        Qt.callLater(() => {
            if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) {
                keyboardController.ensureVisible();
            }
        });
    }

    delegate: Item {
        id: delegateRoot
        required property var modelData
        required property int index

        readonly property bool isExpanded: (NotificationService.expandedGroups[modelData && modelData.key] || false)
        property real swipeOffset: 0
        property bool isDismissing: false
        readonly property real dismissThreshold: width * 0.35
        property bool __delegateInitialized: false

        readonly property bool isAdjacentToSwipe: listView.count >= 2 && listView.swipingCardIndex !== -1 && (index === listView.swipingCardIndex - 1 || index === listView.swipingCardIndex + 1)
        readonly property real adjacentSwipeInfluence: isAdjacentToSwipe ? listView.swipingCardOffset * 0.10 : 0
        readonly property real adjacentScaleInfluence: isAdjacentToSwipe ? 1.0 - Math.abs(listView.swipingCardOffset) / width * 0.02 : 1.0
        readonly property real swipeFadeStartOffset: width * 0.75
        readonly property real swipeFadeDistance: Math.max(1, width - swipeFadeStartOffset)
        readonly property real nonAnimHeight: notificationCard.targetHeight + listView.delegateShadowGutter

        Component.onCompleted: {
            Qt.callLater(() => {
                if (delegateRoot) {
                    delegateRoot.__delegateInitialized = true;
                    listView.queueStableContentHeightUpdate(listView.isAnimatingExpansion);
                }
            });
        }

        width: ListView.view.width
        height: notificationCard.height + listView.delegateShadowGutter
        clip: false

        NotificationCard {
            id: notificationCard
            width: Math.max(0, parent.width - (listView.shadowHorizontalGutter * 2))
            y: listView.delegateShadowGutter / 2
            x: listView.shadowHorizontalGutter + delegateRoot.swipeOffset + delegateRoot.adjacentSwipeInfluence
            listLevelAdjacentScaleInfluence: delegateRoot.adjacentScaleInfluence
            listLevelScaleAnimationsEnabled: listView.swipingCardIndex === -1 || !delegateRoot.isAdjacentToSwipe
            notificationGroup: modelData
            keyboardNavigationActive: listView.keyboardActive
            animateExpansion: listView.cardAnimateExpansion && listView.listInitialized
            transientSurfaceTracker: listView.transientSurfaceTracker
            opacity: {
                const swipeAmount = Math.abs(delegateRoot.swipeOffset);
                if (swipeAmount <= delegateRoot.swipeFadeStartOffset)
                    return 1;
                const fadeProgress = (swipeAmount - delegateRoot.swipeFadeStartOffset) / delegateRoot.swipeFadeDistance;
                return Math.max(0, 1 - fadeProgress);
            }
            onIsAnimatingChanged: {
                if (isAnimating) {
                    listView.isAnimatingExpansion = true;
                    listView.syncStableContentHeight(true);
                } else {
                    Qt.callLater(() => {
                        if (!notificationCard || !listView)
                            return;
                        let anyAnimating = false;
                        for (let i = 0; i < listView.count; i++) {
                            const item = listView.itemAtIndex(i);
                            if (item && item.children[0] && item.children[0].isAnimating) {
                                anyAnimating = true;
                                break;
                            }
                        }
                        listView.isAnimatingExpansion = anyAnimating;
                    });
                }
            }

            onTargetHeightChanged: {
                if (isAnimating || listView.isAnimatingExpansion)
                    listView.syncStableContentHeight(true);
                else
                    listView.queueStableContentHeightUpdate(false);
            }

            isGroupSelected: {
                if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive)
                    return false;
                keyboardController.selectionVersion;
                const selection = keyboardController.getCurrentSelection();
                return selection.type === "group" && selection.groupIndex === index;
            }

            selectedNotificationIndex: {
                if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive)
                    return -1;
                keyboardController.selectionVersion;
                const selection = keyboardController.getCurrentSelection();
                return (selection.type === "notification" && selection.groupIndex === index) ? selection.notificationIndex : -1;
            }

            Behavior on x {
                enabled: !swipeDragHandler.active && !delegateRoot.isDismissing && (listView.swipingCardIndex === -1 || !delegateRoot.isAdjacentToSwipe) && listView.listInitialized
                NumberAnimation {
                    duration: Theme.shortDuration
                    easing.type: Theme.standardEasing
                }
            }

            Behavior on opacity {
                enabled: listView.listInitialized
                NumberAnimation {
                    duration: listView.listInitialized ? Theme.shortDuration : 0
                }
            }
        }

        DragHandler {
            id: swipeDragHandler
            target: null
            yAxis.enabled: false
            xAxis.enabled: true

            onActiveChanged: {
                if (active) {
                    listView.swipingCardIndex = index;
                    return;
                }
                listView.swipingCardIndex = -1;
                listView.swipingCardOffset = 0;
                if (delegateRoot.isDismissing)
                    return;
                if (Math.abs(delegateRoot.swipeOffset) > delegateRoot.dismissThreshold) {
                    delegateRoot.isDismissing = true;
                    swipeDismissAnim.to = delegateRoot.swipeOffset > 0 ? delegateRoot.width : -delegateRoot.width;
                    swipeDismissAnim.start();
                } else {
                    delegateRoot.swipeOffset = 0;
                }
            }

            onTranslationChanged: {
                if (delegateRoot.isDismissing)
                    return;
                delegateRoot.swipeOffset = translation.x;
                listView.swipingCardOffset = translation.x;
            }
        }

        NumberAnimation {
            id: swipeDismissAnim
            target: delegateRoot
            property: "swipeOffset"
            to: 0
            duration: Theme.notificationExitDuration
            easing.type: Easing.OutCubic
            onStopped: NotificationService.dismissGroup(delegateRoot.modelData?.key || "")
        }
    }

    Connections {
        target: NotificationService

        function onGroupedNotificationsChanged() {
            if (!keyboardController) {
                return;
            }

            if (keyboardController.isTogglingGroup) {
                keyboardController.rebuildFlatNavigation();
                return;
            }

            keyboardController.rebuildFlatNavigation();

            if (keyboardController.keyboardNavigationActive) {
                Qt.callLater(() => {
                    if (!autoScrollDisabled) {
                        keyboardController.ensureVisible();
                    }
                });
            }
        }

        function onExpandedGroupsChanged() {
            if (!keyboardController || !keyboardController.keyboardNavigationActive)
                return;
            expansionEnsureVisibleTimer.restart();
        }

        function onExpandedMessagesChanged() {
            if (!keyboardController || !keyboardController.keyboardNavigationActive)
                return;
            expansionEnsureVisibleTimer.restart();
        }
    }
}
