import "root:/modules/common"
import "root:/services"
import "root:/modules/common/functions/string_utils.js" as StringUtils
import Qt5Compat.GraphicalEffects
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Widgets
import Quickshell.Hyprland
import Quickshell.Services.Notifications
import "./notification_utils.js" as NotificationUtils

Item {
    id: root
    property var notificationObject
    property bool popup: false
    property bool expanded: false
    property bool enableAnimation: true
    property int notificationListSpacing: 5
    property bool ready: false
    property int defaultTimeoutValue: 5000

    property var notificationXAnimation: Appearance.animation.elementMoveEnter

    Layout.fillWidth: true
    clip: !popup

    implicitHeight: ready ? notificationColumnLayout.implicitHeight + notificationListSpacing : 0
    Behavior on implicitHeight {
        enabled: enableAnimation
        NumberAnimation {
            duration: Appearance.animation.elementMoveFast.duration
            easing.type: Appearance.animation.elementMoveFast.type
            easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
        }
    }

    Component.onCompleted: {
        root.ready = true
        if (popup) timeoutTimer.start()
    }

    Timer {
        id: timeoutTimer
        interval: notificationObject.expireTimeout ?? root.defaultTimeoutValue
        repeat: false
        onTriggered: {
            root.notificationXAnimation = Appearance.animation.elementMoveExit
            Notifications.timeoutNotification(notificationObject.id);
        }
    }

    function destroyWithAnimation(delay = 0) {
        destroyTimer0.interval = delay
        destroyTimer0.start()
    }

    function toggleExpanded() {
        root.enableAnimation = true
        notificationRowWrapper.anchors.bottom = undefined
        root.expanded = !root.expanded
    }

    Timer {
        id: destroyTimer0
        interval: 0
        repeat: false
        onTriggered: {
            notificationRowWrapper.anchors.left = undefined
            notificationRowWrapper.anchors.right = undefined
            notificationRowWrapper.anchors.fill = undefined
            notificationBackground.anchors.left = undefined
            notificationBackground.anchors.right = undefined
            notificationBackground.anchors.fill = undefined
            notificationRowWrapper.x = width + 5 * 2 // Account for shadow
            notificationBackground.x = width + 5 * 2 // Account for shadow
            destroyTimer1.start()
        }
    }

    Timer {
        id: destroyTimer1
        interval: Appearance.animation.elementMoveFast.duration
        repeat: false
        onTriggered: {
            notificationRowWrapper.anchors.top = undefined
            notificationRowWrapper.anchors.bottom = root.bottom
            implicitHeight = 0
            destroyTimer2.start()
        }
    }

    Timer {
        id: destroyTimer2
        interval: Appearance.animation.elementMoveFast.duration
        repeat: false
        onTriggered: {
            root.destroy()
        }
    }

    MouseArea {
        // Middle click to close
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
        onClicked: (mouse) => {
            if (mouse.button == Qt.MiddleButton) 
                Notifications.discardNotification(notificationObject.id);
            else if (mouse.button == Qt.RightButton) 
                root.toggleExpanded()
        }

        // Flick right to dismiss/discard
        property real startX: 0
        property real dragStartThreshold: 10
        property real dragConfirmThreshold: 70
        property bool dragStarted: false

        onPressed: (mouse) => {
            if (mouse.button === Qt.LeftButton) {
                startX = mouse.x
            }
        }
        onPressAndHold: (mouse) => {
            if (mouse.button === Qt.LeftButton) {
                Hyprland.dispatch(`exec wl-copy '${StringUtils.shellSingleQuoteEscape(notificationObject.body)}'`)
                notificationSummaryText.text = `${notificationObject.summary} (copied)`
            }
        }
        onDragStartedChanged: () => {
            // Prevent drag focus being shifted to parent flickable
            if (root.parent.parent.parent.interactive !== undefined) root.parent.parent.parent.interactive = !dragStarted
            root.enableAnimation = !dragStarted
        }
        onReleased: (mouse) => {
            dragStarted = false
            if (mouse.button === Qt.LeftButton) {
                if (notificationRowWrapper.x > dragConfirmThreshold) {
                    root.notificationXAnimation = Appearance.animation.elementMoveEnter
                    Notifications.discardNotification(notificationObject.id);
                } else {
                    // Animate back if not far enough
                    root.notificationXAnimation = Appearance.animation.elementMoveFast
                    notificationRowWrapper.x = 0
                    notificationBackground.x = 0
                }
            }
        }
        onPositionChanged: (mouse) => {
            if (mouse.buttons & Qt.LeftButton) {
                let dx = mouse.x - startX
                if (dragStarted || dx > dragStartThreshold) {
                    dragStarted = true
                    notificationRowWrapper.anchors.left = undefined
                    notificationRowWrapper.anchors.right = undefined
                    notificationRowWrapper.anchors.fill = undefined
                    notificationBackground.anchors.left = undefined
                    notificationBackground.anchors.right = undefined
                    notificationBackground.anchors.fill = undefined
                    notificationRowWrapper.x = Math.max(0, dx)
                    notificationBackground.x = Math.max(0, dx)
                }
            }
        }
    }

    // Background
    Item {
        id: notificationBackgroundWrapper

        // anchors.fill: parent
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        // anchors.top: parent.top
        anchors.topMargin: notificationListSpacing
        implicitHeight: notificationColumnLayout.implicitHeight + notificationListSpacing

        Rectangle {
            id: notificationBackground
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            // anchors.top: parent.top
            height: notificationColumnLayout.implicitHeight

            color: (notificationObject.urgency == NotificationUrgency.Critical) ? 
                Appearance.mix(Appearance.m3colors.m3secondaryContainer, Appearance.colors.colLayer2, 0.35) : Appearance.colors.colLayer2
            radius: Appearance.rounding.normal

            Behavior on x {
                enabled: enableAnimation
                NumberAnimation {
                    duration: root.notificationXAnimation.duration
                    easing.type: root.notificationXAnimation.type
                    easing.bezierCurve: root.notificationXAnimation.bezierCurve
                }
            }
            Behavior on height {
                enabled: enableAnimation
                NumberAnimation {
                    duration: Appearance.animation.elementMoveFast.duration
                    easing.type: Appearance.animation.elementMoveFast.type
                    easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
                }
            }
        }

        Loader {
            active: popup
            anchors.fill: notificationBackground
            sourceComponent: DropShadow {
                id: notificationShadow
                source: notificationBackground
                radius: 5
                samples: radius * 2 + 1
                color: Appearance.colors.colShadow
                verticalOffset: 2
                horizontalOffset: 0
            }
        }
    }


    Item {
        id: notificationRowWrapper
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        // anchors.top: parent.top
        implicitHeight: notificationColumnLayout.implicitHeight + notificationListSpacing

        Behavior on x {
            enabled: enableAnimation
            NumberAnimation {
                duration: root.notificationXAnimation.duration
                easing.type: root.notificationXAnimation.type
                easing.bezierCurve: root.notificationXAnimation.bezierCurve
            }
        }

        ColumnLayout {
            id: notificationColumnLayout
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            spacing: 0
            Item {
                Layout.fillWidth: true
                implicitHeight: notificationRowLayout.implicitHeight
                Behavior on implicitHeight {
                    enabled: enableAnimation
                    NumberAnimation {
                        duration: Appearance.animation.elementMoveFast.duration
                        easing.type: Appearance.animation.elementMoveFast.type
                        easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
                    }
                }

                RowLayout {
                    id: notificationRowLayout
                    anchors.top: parent.top
                    anchors.left: parent.left
                    anchors.right: parent.right

                    Rectangle { // App icon
                        id: iconRectangle
                        implicitWidth: 47
                        implicitHeight: 47
                        Layout.leftMargin: 10
                        Layout.topMargin: 10
                        Layout.bottomMargin: 10
                        Layout.alignment: Qt.AlignTop
                        Layout.fillWidth: false
                        radius: Appearance.rounding.full
                        color: Appearance.m3colors.m3secondaryContainer
                        Loader {
                            id: materialSymbolLoader
                            active: notificationObject.appIcon == ""
                            anchors.fill: parent
                            sourceComponent: MaterialSymbol {
                                text: {
                                    const defaultIcon = NotificationUtils.findSuitableMaterialSymbol("")
                                    const guessedIcon = NotificationUtils.findSuitableMaterialSymbol(notificationObject.summary)
                                    return (notificationObject.urgency == NotificationUrgency.Critical && guessedIcon === defaultIcon) ?
                                        "release_alert" : guessedIcon
                                }
                                anchors.fill: parent
                                color: (notificationObject.urgency == NotificationUrgency.Critical) ? 
                                    Appearance.mix(Appearance.m3colors.m3onSecondary, Appearance.m3colors.m3onSecondaryContainer, 0.1) :
                                    Appearance.m3colors.m3onSecondaryContainer
                                iconSize: 27
                                horizontalAlignment: Text.AlignHCenter
                                verticalAlignment: Text.AlignVCenter
                            }
                        }
                        Loader {
                            id: appIconLoader
                            active: notificationObject.image == "" && notificationObject.appIcon != ""
                            anchors.centerIn: parent
                            sourceComponent: IconImage {
                                implicitSize: 33
                                asynchronous: true
                                source: Quickshell.iconPath(notificationObject.appIcon, "image-missing")
                            }
                        }
                        Loader {
                            id: notifImageLoader
                            active: notificationObject.image != ""
                            anchors.fill: parent
                            sourceComponent: Item {
                                anchors.fill: parent
                                Image {
                                    id: notifImage
                                    anchors.fill: parent
                                    readonly property int size: parent.width

                                    source: notificationObject?.image
                                    fillMode: Image.PreserveAspectCrop
                                    cache: false
                                    antialiasing: true
                                    asynchronous: true

                                    width: size
                                    height: size
                                    sourceSize.width: size
                                    sourceSize.height: size

                                    layer.enabled: true
                                    layer.effect: OpacityMask {
                                        maskSource: Rectangle {
                                            width: notifImage.size
                                            height: notifImage.size
                                            radius: Appearance.rounding.full
                                        }
                                    }
                                }
                                Loader {
                                    id: notifImageAppIconLoader
                                    active: notificationObject.appIcon != ""
                                    anchors.bottom: parent.bottom
                                    anchors.right: parent.right
                                    sourceComponent: IconImage {
                                        implicitSize: 23
                                        asynchronous: true
                                        source: Quickshell.iconPath(notificationObject.appIcon, "image-missing")
                                    }
                                }
                            }
                        }
                    }

                    ColumnLayout { // Notification content
                        spacing: 0
                        Layout.fillWidth: true

                        RowLayout { // Row of summary, time and expand button
                            Layout.topMargin: 10
                            Layout.leftMargin: 10
                            Layout.rightMargin: 10
                            Layout.fillWidth: true

                            StyledText { // Summary
                                id: notificationSummaryText
                                Layout.fillWidth: true
                                horizontalAlignment: Text.AlignLeft
                                verticalAlignment: Text.AlignBottom
                                font.pixelSize: Appearance.font.pixelSize.normal
                                color: Appearance.colors.colOnLayer2
                                text: notificationObject.summary
                                wrapMode: expanded ? Text.Wrap : Text.NoWrap
                                elide: Text.ElideRight
                            }

                            CircularProgress {
                                id: notificationProgress
                                visible: popup
                                Layout.alignment: Qt.AlignVCenter
                                lineWidth: 2
                                value: popup ? 1 : 0
                                size: 20
                                animationDuration: notificationObject.expireTimeout ?? root.defaultTimeoutValue
                                easingType: Easing.Linear

                                Component.onCompleted: {
                                    value = 0
                                }
                            }

                            StyledText { // Time
                                id: notificationTimeText
                                Layout.fillWidth: false
                                Layout.alignment: Qt.AlignTop
                                Layout.topMargin: 3
                                wrapMode: Text.Wrap
                                horizontalAlignment: Text.AlignLeft
                                font.pixelSize: Appearance.font.pixelSize.smaller
                                color: Appearance.m3colors.m3outline
                                text: NotificationUtils.getFriendlyNotifTimeString(notificationObject.time)

                                Connections {
                                    target: DateTime
                                    function onTimeChanged() {
                                        notificationTimeText.text = NotificationUtils.getFriendlyNotifTimeString(notificationObject.time)
                                    }
                                }
                            }

                            Button { // Expand button
                                Layout.alignment: Qt.AlignTop
                                id: expandButton
                                implicitWidth: 22
                                implicitHeight: 22

                                PointingHandInteraction{}
                                onClicked: {
                                    root.toggleExpanded()
                                }

                                background: Rectangle {
                                    anchors.fill: parent
                                    radius: Appearance.rounding.full
                                    color: (expandButton.down) ? Appearance.colors.colLayer2Active : (expandButton.hovered ? Appearance.colors.colLayer2Hover : Appearance.transparentize(Appearance.colors.colLayer2, 1))

                                    Behavior on color {
                                        ColorAnimation {
                                            duration: Appearance.animation.elementMoveFast.duration
                                            easing.type: Appearance.animation.elementMoveFast.type
                                            easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
                                        }

                                    }

                                }

                                contentItem: MaterialSymbol {
                                    anchors.centerIn: parent
                                    text: "keyboard_arrow_down"
                                    horizontalAlignment: Text.AlignHCenter
                                    verticalAlignment: Text.AlignVCenter
                                    iconSize: Appearance.font.pixelSize.normal
                                    color: Appearance.colors.colOnLayer2
                                    rotation: expanded ? 180 : 0
                                    Behavior on rotation {
                                        NumberAnimation {
                                            duration: Appearance.animation.elementMoveFast.duration
                                            easing.type: Appearance.animation.elementMoveFast.type
                                            easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
                                        }
                                    }
                                }

                            }
                        }

                        StyledText { // Notification body
                            id: notificationBodyText
                            Layout.fillWidth: true
                            Layout.leftMargin: 10
                            Layout.rightMargin: 10
                            Layout.bottomMargin: 10
                            clip: true

                            wrapMode: expanded ? Text.Wrap : Text.NoWrap
                            elide: Text.ElideRight
                            font.pixelSize: Appearance.font.pixelSize.small
                            horizontalAlignment: Text.AlignLeft
                            color: Appearance.m3colors.m3outline
                            textFormat: expanded ? Text.RichText : Text.StyledText
                            text: expanded 
                                ? `<style>img{max-width:${notificationBodyText.width}px;}</style>` + 
                                  `${notificationObject.body.replace(/\n/g, "<br/>")}` 
                                : notificationObject.body.replace(/<img/g, "\n <img").split("\n")[0]
                            onLinkActivated: (link) => {
                                Qt.openUrlExternally(link)
                                Hyprland.dispatch("global quickshell:sidebarRightClose")
                            }
                            MouseArea {
                                anchors.fill: parent
                                acceptedButtons: Qt.NoButton // Only for hover
                                hoverEnabled: true
                                cursorShape: parent.hoveredLink !== "" ? Qt.PointingHandCursor : Qt.ArrowCursor
                            }
                        }
                    }
                }
            }

            // Actions
            Flickable {
                id: actionsFlickable
                Layout.fillWidth: true
                // Layout.topMargin: -5
                Layout.leftMargin: 10
                Layout.rightMargin: 10
                Layout.bottomMargin: expanded ? 10 : 0
                implicitHeight: expanded ? actionRowLayout.implicitHeight : 0
                height: expanded ? actionRowLayout.implicitHeight : 0
                contentWidth: actionRowLayout.implicitWidth

                clip: true
                layer.enabled: true
                layer.effect: OpacityMask {
                    maskSource: Rectangle {
                        width: actionsFlickable.width
                        height: actionsFlickable.height
                        radius: Appearance.rounding.small
                    }
                }

                opacity: expanded ? 1 : 0
                visible: opacity > 0
                Behavior on opacity {
                    NumberAnimation {
                        duration: Appearance.animation.elementMoveFast.duration
                        easing.type: Appearance.animation.elementMoveFast.type
                        easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
                    }
                }
                Behavior on height {
                    NumberAnimation {
                        duration: Appearance.animation.elementMoveFast.duration
                        easing.type: Appearance.animation.elementMoveFast.type
                        easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
                    }
                }
                Behavior on implicitHeight {
                    NumberAnimation {
                        duration: Appearance.animation.elementMoveFast.duration
                        easing.type: Appearance.animation.elementMoveFast.type
                        easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
                    }
                }

                RowLayout {
                    id: actionRowLayout
                    Layout.alignment: Qt.AlignBottom

                    Repeater {
                        id: actionRepeater
                        model: notificationObject.actions
                        NotificationActionButton {
                            Layout.fillWidth: true
                            buttonText: modelData.text
                            urgency: notificationObject.urgency
                            onClicked: {
                                Notifications.attemptInvokeAction(notificationObject.id, modelData.identifier);
                            }
                        }
                    }

                    NotificationActionButton {
                        Layout.fillWidth: true
                        urgency: notificationObject.urgency
                        implicitWidth: (notificationObject.actions.length == 0) ? (actionsFlickable.width / 2) : 
                            (contentItem.implicitWidth + leftPadding + rightPadding)

                        onClicked: {
                            Hyprland.dispatch(`exec wl-copy '${StringUtils.shellSingleQuoteEscape(notificationObject.body)}'`)
                            copyIcon.text = "inventory"
                            copyIconTimer.stop()
                            copyIconTimer.start()
                        }

                        Timer {
                            id: copyIconTimer
                            interval: 1500
                            repeat: false
                            onTriggered: {
                                copyIcon.text = "content_copy"
                            }
                        }

                        contentItem: MaterialSymbol {
                            id: copyIcon
                            iconSize: Appearance.font.pixelSize.large
                            horizontalAlignment: Text.AlignHCenter
                            color: (notificationObject.urgency == NotificationUrgency.Critical) ? 
                                Appearance.m3colors.m3onSurfaceVariant : Appearance.m3colors.m3onSurface
                            text: "content_copy"
                        }
                    }

                    NotificationActionButton {
                        Layout.fillWidth: true
                        buttonText: qsTr("Close")
                        urgency: notificationObject.urgency
                        implicitWidth: (notificationObject.actions.length == 0) ? (actionsFlickable.width / 2) : 
                            (contentItem.implicitWidth + leftPadding + rightPadding)

                        onClicked: {
                            Notifications.discardNotification(notificationObject.id);
                        }

                        contentItem: MaterialSymbol {
                            iconSize: Appearance.font.pixelSize.large
                            horizontalAlignment: Text.AlignHCenter
                            color: (notificationObject.urgency == NotificationUrgency.Critical) ? 
                                Appearance.m3colors.m3onSurfaceVariant : Appearance.m3colors.m3onSurface
                            text: "close"
                        }
                    }
                    
                }
            }
        }
    }
}
