import QtQuick
import Quickshell
import Quickshell.Wayland
import Quickshell.Services.Polkit

import "../config" as Cfg
import "../components"


Item {
    id: root

    readonly property var t:   Cfg.Config.theme
    readonly property var cfg: Cfg.Config

    property bool interactionAvailable: false
    property bool windowShouldExist:    false

    PolkitAgent {
        id: agent

        onAuthenticationRequestStarted: {
            root.windowShouldExist    = true
            root.interactionAvailable = true
            resetInput()
        }
    }

    readonly property var flow: agent.flow ?? null

    Connections {
        target: flow
        function onAuthenticationFailed() {
            root.interactionAvailable = true
            resetInput()
        }
    }

    function submitAuth() {
        if (!root.interactionAvailable) return
        if (flow?.isResponseRequired) {
            root.interactionAvailable = false
            flow.submit(windowLoader.item?.passwordText ?? "")
            windowLoader.item?.clearPassword()
        }
    }

    function resetInput() {
        windowLoader.item?.resetInput()
    }

    Loader {
        id: windowLoader
        active: root.windowShouldExist

        sourceComponent: Component {
            PanelWindow {
                id: overlay

                property bool exiting: false
                property bool authFailed: false
                property var displayFlow: null

                function captureFlowSnapshot(flow) {
                    if (!flow) return null
                    return {
                        message:              flow.message,
                        actionId:             flow.actionId,
                        supplementaryMessage: flow.supplementaryMessage,
                        supplementaryIsError: flow.supplementaryIsError,
                        identities:           flow.identities?.slice() ?? [],
                        selectedIdentity:     flow.selectedIdentity,
                        isResponseRequired:   flow.isResponseRequired,
                        inputPrompt:          flow.inputPrompt,
                        responseVisible:      flow.responseVisible
                    }
                }

                readonly property string passwordText: passwordInput.text
                function clearPassword() { passwordInput.clear() }
                function resetInput() {
                    passwordInput.clear()
                    passwordInput.forceActiveFocus()
                }

                visible: true

                anchors { top: true; bottom: true; left: true; right: true }
                color: "transparent"

                WlrLayershell.layer:         WlrLayer.Overlay
                WlrLayershell.exclusiveZone: -1
                WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
                WlrLayershell.namespace:     "main-shell-polkit"

                Timer {
                    id: exitDebounce
                    interval: 250
                    onTriggered: {
                        if (!agent.isActive && !overlay.exiting) {
                            overlay.exiting = true
                            exitAnim.start()
                        }
                    }
                }

                function cancelAndClose() {
                    if (overlay.exiting) return
                    overlay.exiting = true
                    exitAnim.start()
                    root.flow?.cancelAuthenticationRequest()
                }

                Rectangle {
                    anchors.fill: parent
                    color: t.polkitOverlayBg
                }

                component DialogButton: HoverButton {
                    property string label
                    property int    labelWeight:    Font.Normal
                    property color  labelColor
                    signal tapped()

                    width:  (parent.width - 12) / 2
                    height: 44
                    radius: 10
                    border.width: 1

                    onClicked: tapped()

                    Text {
                        anchors.centerIn: parent
                        text:             label
                        color:            labelColor
                        font.pixelSize:   13
                        font.weight:      labelWeight
                        font.letterSpacing: 0.2
                    }
                }

                Rectangle {
                    id: card

                    property real shakeX: 0

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

                    width:  440
                    height: content.implicitHeight + 64

                    radius:       cfg.popupRadius
                    color:        t.polkitCardBg
                    border.color: t.polkitCardBorder
                    border.width: 1

                    opacity: 0
                    scale:   0.86

                    transform: Scale {
                        yScale: 1
                        origin.y: card.height / 2
                    }

                    Component.onCompleted: {
                        overlay.displayFlow = agent.flow
                        enterAnim.start()
                    }

                    ParallelAnimation {
                        id: enterAnim
                        NumberAnimation {
                            target: card; property: "opacity"
                            from: 0; to: 1
                            duration: 260; easing.type: Easing.OutCubic
                        }
                        NumberAnimation {
                            target: card; property: "scale"
                            from: 0.86; to: 1.0
                            duration: 360; easing.type: Easing.OutBack; easing.overshoot: 0.6
                        }
                        NumberAnimation {
                            target: card.transform; property: "yScale"
                            from: 0; to: 1
                            duration: 360; easing.type: Easing.OutBack; easing.overshoot: 0.6
                        }
                    }

                    ParallelAnimation {
                        id: exitAnim
                        NumberAnimation {
                            target: card; property: "opacity"
                            from: 1; to: 0
                            duration: 200; easing.type: Easing.InCubic
                        }
                        NumberAnimation {
                            target: card; property: "scale"
                            from: 1.0; to: 0.88
                            duration: 260; easing.type: Easing.InBack
                        }
                        NumberAnimation {
                            target: card.transform; property: "yScale"
                            from: 1; to: 0
                            duration: 260; easing.type: Easing.InBack
                        }
                        onFinished: {
                            overlay.exiting        = false
                            root.windowShouldExist = false
                        }
                    }

                    Connections {
                        target: agent
                        function onIsActiveChanged() {
                            if (agent.isActive) {
                                overlay.authFailed  = false
                                overlay.displayFlow = agent.flow
                                exitDebounce.stop()
                                if (overlay.exiting) {
                                    exitAnim.stop()
                                    overlay.exiting = false
                                }
                                card.opacity          = 0
                                card.scale            = 0.86
                                card.transform.yScale = 0
                                enterAnim.restart()
                            } else {
                                if (overlay.displayFlow)
                                    overlay.displayFlow = captureFlowSnapshot(overlay.displayFlow)
                                exitDebounce.restart()
                            }
                        }
                    }

                    Connections {
                        target: flow
                        function onAuthenticationFailed() {
                            overlay.authFailed = true
                            shakeAnim.restart()
                        }
                    }

                    SequentialAnimation {
                        id: shakeAnim
                        NumberAnimation { target: card; property: "shakeX"; to:  12; duration: 45; easing.type: Easing.InOutQuad }
                        NumberAnimation { target: card; property: "shakeX"; to: -10; duration: 45 }
                        NumberAnimation { target: card; property: "shakeX"; to:   8; duration: 45 }
                        NumberAnimation { target: card; property: "shakeX"; to:  -5; duration: 45 }
                        NumberAnimation { target: card; property: "shakeX"; to:   3; duration: 45 }
                        NumberAnimation { target: card; property: "shakeX"; to:   0; duration: 45 }
                    }

                    Column {
                        id: content

                        anchors {
                            top:   parent.top
                            left:  parent.left
                            right: parent.right
                            topMargin:   32
                            leftMargin:  32
                            rightMargin: 32
                        }
                        spacing: 16

                        Item {
                            width:  parent.width
                            height: 72

                            Rectangle {
                                anchors.centerIn: parent
                                width:  66
                                height: 66
                                radius: 33
                                color:        t.polkitIconBg
                                border.color: t.polkitIconBorder
                                border.width: 1

                                Text {
                                    anchors.centerIn: parent
                                    text:           "󰌆"
                                    font.pixelSize: 28
                                    color:          t.polkitIconColor
                                    Component.onCompleted: {
                                        if (implicitWidth < 4) text = "🔒"
                                    }
                                }
                            }
                        }

                        Text {
                            width:               parent.width
                            horizontalAlignment: Text.AlignHCenter
                            text:                "Authentication Required"
                            color:               t.polkitTitle
                            font.pixelSize:      17
                            font.weight:         Font.DemiBold
                            font.letterSpacing:  0.3
                        }

                        Text {
                            visible:             !!displayFlow?.message
                            width:               parent.width
                            wrapMode:            Text.WordWrap
                            horizontalAlignment: Text.AlignHCenter
                            text:                displayFlow?.message ?? ""
                            color:               t.polkitMessage
                            font.pixelSize:      13
                            lineHeight:          1.50
                        }

                        Item {
                            visible: !!displayFlow?.actionId
                            width:   parent.width
                            height:  pillBg.height

                            Rectangle {
                                id: pillBg
                                anchors.horizontalCenter: parent.horizontalCenter
                                width:  Math.min(pillText.implicitWidth + 22, parent.width)
                                height: pillText.implicitHeight + 10
                                radius: 6
                                color:  t.polkitPillBg

                                Text {
                                    id: pillText
                                    anchors.centerIn: parent
                                    width:          parent.width - 22
                                    elide:          Text.ElideMiddle
                                    text:           displayFlow?.actionId ?? ""
                                    color:          t.polkitPillText
                                    font.pixelSize: 11
                                    font.family:    "monospace"
                                }
                            }
                        }

                        Rectangle {
                            width:  parent.width
                            height: 1
                            color:  t.polkitDivider
                        }

                        Rectangle {
                            visible: overlay.authFailed || !!displayFlow?.supplementaryMessage
                            width:   parent.width
                            height:  suppRow.implicitHeight + 20
                            radius:  10
                            color:        overlay.authFailed || displayFlow?.supplementaryIsError ? t.polkitSuppErrBg     : t.polkitSuppOkBg
                            border.color: overlay.authFailed || displayFlow?.supplementaryIsError ? t.polkitSuppErrBorder : t.polkitSuppOkBorder
                            border.width: 1

                            Row {
                                id: suppRow
                                anchors {
                                    top:    parent.top;    topMargin:    10
                                    bottom: parent.bottom; bottomMargin: 10
                                    left:   parent.left;   leftMargin:   14
                                    right:  parent.right;  rightMargin:  14
                                }
                                spacing: 9

                                Text {
                                    anchors.top: parent.top
                                    text:           "✕"
                                    font.pixelSize: 12
                                    font.weight:    Font.Medium
                                    lineHeight:     1.8
                                    color:          t.polkitSuppErrText
                                }

                                Text {
                                    width:          parent.width - 22
                                    wrapMode:       Text.WordWrap
                                    text:           overlay.authFailed ? "Authentication failed, please try again." : (displayFlow?.supplementaryMessage ?? "")
                                    font.pixelSize: 12
                                    lineHeight:     1.45
                                    color:          overlay.authFailed || displayFlow?.supplementaryIsError ? t.polkitSuppErrText : t.polkitSuppOkText
                                }
                            }
                        }

                        Text {
                            visible:        true
                            width:          parent.width
                            text:           displayFlow?.inputPrompt ?? "Password"
                            color:          t.polkitInputPrompt
                            font.pixelSize: 12
                        }

                        Rectangle {
                            visible: true
                            width:   parent.width
                            height:  46
                            radius:  10
                            color:        t.polkitFieldBg
                            border.color: passwordInput.activeFocus ? t.polkitFieldBorderFocus : t.polkitFieldBorder
                            border.width: passwordInput.activeFocus ? 1.5 : 1

                            Behavior on border.color { ColorAnimation { duration: 120 } }
                            Behavior on border.width { NumberAnimation  { duration: 120 } }

                            TextInput {
                                id: passwordInput

                                enabled: root.interactionAvailable

                                anchors {
                                    left:           parent.left;  leftMargin:  16
                                    right:          eyeBtn.left;  rightMargin:  8
                                    verticalCenter: parent.verticalCenter
                                }

                                property bool showPassword: false

                                echoMode: (displayFlow?.responseVisible || showPassword)
                                          ? TextInput.Normal : TextInput.Password

                                color:             t.polkitInputText
                                selectionColor:    t.polkitInputSelection
                                selectedTextColor: t.polkitInputSelectedText
                                font.pixelSize:    14
                                passwordCharacter: "•"
                                clip:              true

                                Keys.onReturnPressed: root.submitAuth()
                                Keys.onEnterPressed:  root.submitAuth()
                                Keys.onEscapePressed: overlay.cancelAndClose()
                            }

                            Text {
                                id: eyeBtn
                                anchors {
                                    right:          parent.right; rightMargin: 14
                                    verticalCenter: parent.verticalCenter
                                }
                                text:           passwordInput.showPassword ? "🙈" : "👁"
                                font.pixelSize: 20
                                color:          eyeHover.hovered ? t.polkitEyeIconHover : t.polkitEyeIcon

                                Behavior on color { ColorAnimation { duration: 120 } }

                                HoverHandler { id: eyeHover }
                                MouseArea {
                                    anchors.fill:    parent
                                    anchors.margins: -8
                                    cursorShape:     Qt.PointingHandCursor
                                    onClicked:       passwordInput.showPassword = !passwordInput.showPassword
                                }
                            }
                        }

                        Item { width: 1; height: 2 }

                        Row {
                            width:           parent.width
                            spacing:         12
                            layoutDirection: Qt.RightToLeft

                            DialogButton {
                                label:            "Authenticate"
                                labelWeight:      Font.Medium
                                labelColor:       t.polkitAuthText
                                idleColor:        t.polkitAuthBg
                                hoverColor:       t.polkitAuthBgHover
                                borderIdleColor:  t.polkitAuthBg
                                borderHoverColor: t.polkitAuthBgHover
                                animDuration:     200
                                onTapped:         root.submitAuth()
                            }

                            DialogButton {
                                label:            "Cancel"
                                labelColor:       t.polkitCancelText
                                idleColor:        t.polkitCancelBg
                                hoverColor:       t.polkitCancelBgHover
                                borderIdleColor:  t.polkitCancelBorder
                                borderHoverColor: t.polkitCancelBgHover
                                animDuration:     200
                                onTapped:         overlay.cancelAndClose()
                            }
                        }
                    }

                    Rectangle {
                        anchors.fill: parent
                        radius:       cfg.popupRadius
                        color:        Qt.rgba(
                                          t.polkitCardBg.r,
                                          t.polkitCardBg.g,
                                          t.polkitCardBg.b, 0.78)
                        opacity:      root.interactionAvailable ? 0 : 1
                        visible:      opacity > 0

                        Behavior on opacity { NumberAnimation { duration: 180; easing.type: Easing.InOutSine } }

                        Canvas {
                            id: spinnerCanvas
                            anchors.centerIn: parent
                            width:  40
                            height: 40

                            property real angle: 0

                            NumberAnimation on angle {
                                running:  !root.interactionAvailable
                                from:     0
                                to:       360
                                duration: 700
                                loops:    Animation.Infinite
                            }

                            onAngleChanged: requestPaint()

                            onPaint: {
                                const ctx = getContext("2d")
                                ctx.clearRect(0, 0, width, height)
                                const cx = width / 2, cy = height / 2
                                const r  = width / 2 - 3

                                ctx.strokeStyle = Qt.rgba(
                                    t.polkitTitle.r, t.polkitTitle.g, t.polkitTitle.b, 0.12)
                                ctx.lineWidth = 3.5
                                ctx.beginPath()
                                ctx.arc(cx, cy, r, 0, 2 * Math.PI)
                                ctx.stroke()

                                const start = (angle - 90) * Math.PI / 180
                                ctx.strokeStyle = Qt.rgba(
                                    t.polkitTitle.r, t.polkitTitle.g, t.polkitTitle.b, 0.88)
                                ctx.lineCap = "round"
                                ctx.beginPath()
                                ctx.arc(cx, cy, r, start, start + 1.3 * Math.PI)
                                ctx.stroke()
                            }
                        }
                    }
                }
            }
        }
    }
}
