import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Services.Pipewire

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

Rectangle {
    id: root

    property real panelRadius: Cfg.Config.radius / 2
    property int  borderWidth: Cfg.Config.panelBorderWidth
    property bool isTop:       true
    property var  targetScreen: null
    property int  barHeight:    Cfg.Config.barHeight
    property int  barMargin:    Cfg.Config.margin

    readonly property var t: Cfg.Config.theme

    property int outputMaxVolume: Cfg.Config.volumeOutputMax
    property int inputMaxVolume:  Cfg.Config.volumeInputMax

    readonly property var sink:   Pipewire.defaultAudioSink
    readonly property var source: Pipewire.defaultAudioSource

    PwObjectTracker {
        objects: root.sinkNodes.concat(root.sourceNodes)
    }

    readonly property var sinkNodes: {
        if (!Pipewire.nodes) return []
        return Pipewire.nodes.values.filter(n => !n.isStream && n.isSink)
    }
    readonly property var sourceNodes: {
        if (!Pipewire.nodes) return []
        return Pipewire.nodes.values.filter(n => !n.isStream && !n.isSink)
    }

    property int _outVol: 0
    property int _inVol:  0
    
    readonly property int outputVolume: {
        if (sink && sink.ready) { _outVol = Math.round(sink.audio.volume * 100); return _outVol }
        return _outVol
    }
    readonly property int inputVolume: {
        if (source && source.ready) { _inVol = Math.round(source.audio.volume * 100); return _inVol }
        return _inVol
    }
                                        
    readonly property bool outputMuted:  sink   && sink.ready ? sink.audio.muted   : false
    readonly property bool inputMuted:   source && source.ready ? source.audio.muted : false

    readonly property string outputDeviceName: sink   ? (sink.description   || sink.nickName   || sink.name)   : "No device"
    readonly property string inputDeviceName:  source ? (source.description || source.nickName || source.name) : "No device"

    function setOutputVol(pct)  { if (sink   && sink.ready) sink.audio.volume   = pct / 100 }
    function setInputVol(pct)   { if (source && source.ready) source.audio.volume = pct / 100 }
    function toggleOutputMute() { if (sink   && sink.ready) sink.audio.muted     = !sink.audio.muted   }
    function toggleInputMute()  { if (source && source.ready) source.audio.muted  = !source.audio.muted }

    Process {
        id: defaultSetter
        running: false
        property string nodeId: "0"
        command: ["wpctl", "set-default", nodeId]
    }
    function setDefaultDevice(node) {
        defaultSetter.nodeId = node.id.toString()
        defaultSetter.running = true
    }

    readonly property string iconSpeakerHigh:  "󰕾"
    readonly property string iconSpeakerMed:   "󰖀"
    readonly property string iconSpeakerLow:   "󰕿"
    readonly property string iconSpeakerMuted: "󰖁"
    readonly property string iconMic:          "󰍬"
    readonly property string iconMicMuted:     "󰍭"

    function speakerGlyph(muted, vol) {
        if (muted || vol === 0) return iconSpeakerMuted
        if (vol > 60)           return iconSpeakerHigh
        if (vol > 25)           return iconSpeakerMed
        return iconSpeakerLow
    }

    width:  chipLayout.implicitWidth + 15
    height: Cfg.Config.moduleHeight
    radius: panelRadius

    color:        hoverHandler.hovered ? t.volBgHover : t.volBg
    border.color: (hoverHandler.hovered || volumePopup.popupOpen) ? t.volBorderHover : t.volBorder
    border.width: borderWidth

    Behavior on color        { ColorAnimation { duration: 150 } }
    Behavior on border.color { ColorAnimation { duration: 150 } }

    HoverHandler { 
        id: hoverHandler
        cursorShape: Qt.PointingHandCursor 
        onHoveredChanged: {
            if (hovered) shakeAnim.restart()
        }
    }
    TapHandler   { onTapped: volumePopup.toggle() }

    SequentialAnimation {
        id: shakeAnim
        NumberAnimation { target: chipLayout; property: "rotation"; to: -15; duration: 40; easing.type: Easing.OutQuad }
        NumberAnimation { target: chipLayout; property: "rotation"; to: 15; duration: 80; easing.type: Easing.InOutQuad }
        NumberAnimation { target: chipLayout; property: "rotation"; to: -10; duration: 80; easing.type: Easing.InOutQuad }
        NumberAnimation { target: chipLayout; property: "rotation"; to: 10; duration: 80; easing.type: Easing.InOutQuad }
        NumberAnimation { target: chipLayout; property: "rotation"; to: 0; duration: 40; easing.type: Easing.InQuad }
    }

    RowLayout {
        id: chipLayout
        anchors.centerIn: parent
        spacing: 5
        transformOrigin: Item.Center

        Text {
            text:           root.speakerGlyph(root.outputMuted, root.outputVolume)
            color:          root.outputMuted ? root.t.volIconMuted : root.t.volIcon
            font.pixelSize: Cfg.Config.volumeIconSize
            Layout.alignment: Qt.AlignVCenter
        }
    }

    PanelWindow {
        id: volumePopup
        screen:  root.targetScreen
        visible: false
        color:   "transparent"

        property bool popupOpen: false

        function open()   { hideTimer.stop(); visible = true; popupOpen = true }
        function close()  { popupOpen = false; hideTimer.restart() }
        function toggle() { popupOpen ? close() : open() }

        Timer {
            id: hideTimer
            interval: Cfg.Config.popupAnimDuration + 70
            onTriggered: volumePopup.visible = false
        }

        anchors { top: true; bottom: true; left: true; right: true }
        WlrLayershell.layer:         WlrLayer.Top
        WlrLayershell.namespace:     "main-shell-volume"
        WlrLayershell.exclusiveZone: -1
        mask: popupOpen ? null : _noInput
        Region { id: _noInput }

        MouseArea {
            anchors.fill: parent
            onClicked: volumePopup.close()
        }

        Item {
            id: volClipContainer
            readonly property int cardW:     Cfg.Config.volumePopupWidth
            readonly property int screenPad: root.barMargin + 10

            x: {
                let cx = root.mapToItem(null, 0, 0).x + root.width / 2
                return Math.max(screenPad, Math.min(cx - cardW / 2, parent.width - cardW - screenPad))
            }
            width: cardW

            anchors.top:          root.isTop ? parent.top    : undefined
            anchors.bottom:       root.isTop ? undefined     : parent.bottom
            anchors.topMargin:    root.isTop ? (root.barHeight + 10) : 0
            anchors.bottomMargin: root.isTop ? 0 : (root.barHeight + 10)
            height: parent.height - root.barHeight - 10

            clip: true

            Rectangle {
                id: volCard
                width:  parent.width
                height: popupCol.implicitHeight + 32

                anchors.top:    root.isTop ? parent.top    : undefined
                anchors.bottom: root.isTop ? undefined     : parent.bottom

                transform: Translate {
                    y: volumePopup.popupOpen ? 0 : (root.isTop ? -volCard.height : volCard.height)
                    
                    Behavior on y { 
                        NumberAnimation { 
                            duration: Cfg.Config.popupAnimDuration; 
                            easing.type: Easing.OutExpo 
                        }
                        enabled: volumePopup.visible
                    }
                }

                opacity: volumePopup.popupOpen ? 1.0 : 0.0
                Behavior on opacity { NumberAnimation { duration: 200 } }

                radius: Cfg.Config.popupRadius
                color:  root.t.volPopupBg
                border.color: root.t.volPopupBorder
                border.width: Cfg.Config.popupBorderWidth
                layer.enabled: true

                MouseArea { anchors.fill: parent; propagateComposedEvents: false }

                ColumnLayout {
                    id: popupCol
                    anchors { left: parent.left; right: parent.right; top: parent.top }
                    anchors.margins:   16
                    anchors.topMargin: 18
                    spacing: 14

                    VolumeSection {
                        id: outputSection
                        Layout.fillWidth: true
                        label:       "Output"
                        icon:        root.speakerGlyph(root.outputMuted, root.outputVolume)
                        iconColor:   root.t.accent
                        volume:      root.outputVolume
                        maxVolume:   root.outputMaxVolume
                        muted:       root.outputMuted
                        accentColor: root.t.volHandle
                        dimColor:    root.t.textDim
                        textColor:   root.t.textMain
                        trackColor:  root.t.volTrack
                        deviceName:  root.outputDeviceName
                        nodes:       root.sinkNodes
                        currentNode: root.sink
                        onSliderMoved:    vol  => root.setOutputVol(vol)
                        onMuteToggled:    root.toggleOutputMute()
                        onDeviceSelected: node => root.setDefaultDevice(node)
                    }

                    Rectangle { Layout.fillWidth: true; height: 1; color: root.t.separator }

                    VolumeSection {
                        id: inputSection
                        Layout.fillWidth: true
                        label:       "Input"
                        icon:        root.inputMuted ? root.iconMicMuted : root.iconMic
                        iconColor:   root.t.statusInfo
                        volume:      root.inputVolume
                        maxVolume:   root.inputMaxVolume
                        muted:       root.inputMuted
                        accentColor: root.t.statusInfo
                        dimColor:    root.t.textDim
                        textColor:   root.t.textMain
                        trackColor:  root.t.volTrack
                        deviceName:  root.inputDeviceName
                        nodes:       root.sourceNodes
                        currentNode: root.source
                        onSliderMoved:    vol  => root.setInputVol(vol)
                        onMuteToggled:    root.toggleInputMute()
                        onDeviceSelected: node => root.setDefaultDevice(node)
                    }

                    Rectangle { Layout.fillWidth: true; height: 1; color: root.t.separator }

                    ColumnLayout {
                        Layout.fillWidth: true
                        spacing: 10
                        Text {
                            text: "Volume Limits"
                            color: root.t.textDim
                            font.pixelSize: 10
                            font.capitalization: Font.AllUppercase
                            Layout.fillWidth: true
                        }
                        LimitRow {
                            Layout.fillWidth: true
                            icon:        root.iconSpeakerHigh
                            iconColor:   root.t.accent
                            labelText:   "Output max"
                            value:       root.outputMaxVolume
                            minValue:    10
                            maxValue:    300
                            textColor:   root.t.textMain
                            dimColor:    root.t.textDim
                            borderColor: root.t.volPopupBorder
                            onDecrement: root.outputMaxVolume = Math.max(10,  root.outputMaxVolume - 10)
                            onIncrement: root.outputMaxVolume = Math.min(300, root.outputMaxVolume + 10)
                        }
                        LimitRow {
                            Layout.fillWidth: true
                            icon:        root.iconMic
                            iconColor:   root.t.statusInfo
                            labelText:   "Input max"
                            value:       root.inputMaxVolume
                            minValue:    10
                            maxValue:    300
                            textColor:   root.t.textMain
                            dimColor:    root.t.textDim
                            borderColor: root.t.volPopupBorder
                            onDecrement: root.inputMaxVolume = Math.max(10,  root.inputMaxVolume - 10)
                            onIncrement: root.inputMaxVolume = Math.min(300, root.inputMaxVolume + 10)
                        }
                    }
                    Item { height: 2 }
                }
            }
        }
    }

    component VolumeSection: ColumnLayout {
        id: vs
        spacing: 8
        required property string label
        required property string icon
        required property color  iconColor
        required property int    volume
        required property int    maxVolume
        required property bool   muted
        required property color  accentColor
        required property color  dimColor
        required property color  textColor
        required property color  trackColor
        required property string deviceName
        required property var    nodes
        required property var    currentNode

        signal sliderMoved(int vol)
        signal muteToggled()
        signal deviceSelected(var node)

        property bool pickerOpen: false

        RowLayout {
            Layout.fillWidth: true
            spacing: 6
            Text {
                text:                  vs.icon
                color:                 vs.muted ? vs.dimColor : vs.iconColor
                font.pixelSize:        Cfg.Config.volumeIconSize
                Layout.alignment:      Qt.AlignVCenter
                Layout.preferredWidth: Cfg.Config.volumeIconSize + 4
                horizontalAlignment:   Text.AlignHCenter
            }
            Text {
                text:             vs.label
                color:            vs.textColor
                font.pixelSize:   13
                font.bold:        true
                Layout.fillWidth: true
            }
            Text {
                text:                  vs.muted ? "muted" : vs.volume + "%"
                color:                 vs.muted ? vs.dimColor : vs.textColor
                font.pixelSize:        12
                font.bold:             !vs.muted
                horizontalAlignment:   Text.AlignHCenter
                Layout.preferredWidth: 44
            }
            // ── Mute toggle button ────────────────────────────────────────
            Rectangle {
                width: 22; height: 22; radius: 6
                color: muteHover.hovered ? (vs.muted ? "#33ffffff" : "#22ffffff") : (vs.muted ? root.t.volMuteBg : "transparent")
                border.color: vs.muted ? vs.accentColor : vs.dimColor
                border.width: Cfg.Config.popupBorderWidth
                Text {
                    anchors.centerIn: parent
                    text:           vs.muted ? "󰖁" : "󰕾"
                    color:          vs.muted ? vs.accentColor : vs.dimColor
                    font.pixelSize: 11
                }
                HoverHandler { id: muteHover; cursorShape: Qt.PointingHandCursor }
                TapHandler   { onTapped: vs.muteToggled() }
            }
        }

        Item {
            id: sliderItem
            Layout.fillWidth: true
            height: 22
            Rectangle {
                anchors.verticalCenter: parent.verticalCenter
                width: parent.width; height: Cfg.Config.volumeSliderHeight; radius: 2
                color: vs.trackColor
                Rectangle {
                    width:  Math.min(parent.width, parent.width * (vs.volume / Math.max(1, vs.maxVolume)))
                    height: parent.height; radius: parent.radius
                    color:  vs.muted ? vs.dimColor : vs.accentColor
                }
            }
            // ── Volume slider handle ──────────────────────────────────────
            Rectangle {
                readonly property real ratio: vs.volume / Math.max(1, vs.maxVolume)
                x:      Math.min(sliderItem.width - width, Math.max(0, sliderItem.width * ratio - width / 2))
                anchors.verticalCenter: parent.verticalCenter
                width: Cfg.Config.volumeHandleSize; height: Cfg.Config.volumeHandleSize; radius: width / 2
                color:        vs.muted ? vs.dimColor : vs.accentColor
                border.color: root.t.volHandleBorder
                border.width: Cfg.Config.popupBorderWidth
            }
            MouseArea {
                anchors.fill: parent; cursorShape: Qt.PointingHandCursor
                onPressed:         pos => sliderItem.seek(pos.x)
                onPositionChanged: pos => { if (pressed) sliderItem.seek(pos.x) }
            }
            function seek(x) {
                let ratio = Math.max(0.0, Math.min(1.0, x / sliderItem.width))
                vs.sliderMoved(Math.round(ratio * vs.maxVolume))
            }
        }

        RowLayout {
            Layout.fillWidth: true
            spacing: 6
            Text { text: "󰒓"; color: vs.dimColor; font.pixelSize: 11 }
            Text {
                text:             vs.deviceName
                color:            vs.textColor
                font.pixelSize:   11
                elide:            Text.ElideRight
                Layout.fillWidth: true
            }
            // ── Device picker chevron ─────────────────────────────────────
            Rectangle {
                width: 20; height: 20; radius: 5
                color:        chevHover.hovered ? "#22ffffff" : "transparent"
                border.color: vs.pickerOpen ? vs.accentColor : root.t.volPopupBorder
                border.width: Cfg.Config.popupBorderWidth
                Text {
                    anchors.centerIn: parent
                    text:           vs.pickerOpen ? "󰅃" : "󰅀"
                    color:          vs.pickerOpen ? vs.accentColor : vs.dimColor
                    font.pixelSize: 10
                }
                HoverHandler { id: chevHover; cursorShape: Qt.PointingHandCursor }
                TapHandler   { onTapped: vs.pickerOpen = !vs.pickerOpen }
            }
        }

        Item {
            Layout.fillWidth: true
            Layout.preferredHeight: vs.pickerOpen ? Math.min(deviceFlickable.contentHeight, 120) : 0
            opacity:          vs.pickerOpen ? 1.0 : 0.0
            clip:             true

            Behavior on Layout.preferredHeight { NumberAnimation { duration: 150; easing.type: Easing.OutCubic } }
            Behavior on opacity { NumberAnimation { duration: 150; easing.type: Easing.OutCubic } }

            Flickable {
                id: deviceFlickable
                anchors.fill: parent
                contentWidth:  width
                contentHeight: deviceList.implicitHeight
                clip:          true
                boundsBehavior: Flickable.StopAtBounds

                ColumnLayout {
                    id: deviceList
                    width: deviceFlickable.width
                    spacing: 2
                    Repeater {
                        model: vs.nodes
                        delegate: Rectangle {
                            required property var  modelData
                            readonly property bool isActive: vs.currentNode !== null && modelData.id === vs.currentNode.id
                            Layout.fillWidth: true; height: 28; radius: 7
                            color: isActive ? Qt.alpha(vs.accentColor, 0.18) : (rowHover.hovered ? root.t.volPickerHover : "transparent")
                            // ── Device row border ─────────────────────────────
                            border.color: isActive ? Qt.alpha(vs.accentColor, 0.45) : "transparent"
                            border.width: Cfg.Config.popupBorderWidth
                            RowLayout {
                                anchors { fill: parent; leftMargin: 8; rightMargin: 8 }
                                spacing: 8
                                Rectangle {
                                    width: 6; height: 6; radius: 3
                                    color:        isActive ? vs.accentColor : "transparent"
                                    border.color: isActive ? "transparent" : vs.dimColor
                                    border.width: Cfg.Config.popupBorderWidth
                                }
                                Text {
                                    text:             modelData.description || modelData.nickName || modelData.name
                                    color:            isActive ? vs.accentColor : vs.textColor
                                    font.pixelSize:   11; font.bold: isActive
                                    elide:            Text.ElideRight; Layout.fillWidth: true
                                }
                            }
                            HoverHandler { id: rowHover; cursorShape: Qt.PointingHandCursor }
                            TapHandler { onTapped: { vs.deviceSelected(modelData); vs.pickerOpen = false } }
                        }
                    }
                }
            }
        }
    }

    component LimitRow: RowLayout {
        id: lr
        spacing: 8
        required property string icon
        required property color  iconColor
        required property string labelText
        required property int    value
        required property int    minValue
        required property int    maxValue
        required property color  textColor
        required property color  dimColor
        required property color  borderColor

        signal decrement()
        signal increment()

        Text { text: lr.icon; color: lr.iconColor; font.pixelSize: 13 }
        Text {
            text:             lr.labelText
            color:            lr.textColor
            font.pixelSize:   11
            Layout.fillWidth: true
        }
        // ── Decrement button ──────────────────────────────────────────────
        Rectangle {
            width: 22; height: 22; radius: 5
            color:        decHover.hovered ? "#22ffffff" : "transparent"
            border.color: lr.borderColor
            border.width: Cfg.Config.popupBorderWidth
            Text {
                anchors.centerIn: parent; text: "−"
                color: lr.value <= lr.minValue ? lr.dimColor : lr.textColor
                font.pixelSize: 14
            }
            HoverHandler { id: decHover; cursorShape: Qt.PointingHandCursor }
            TapHandler   { onTapped: { if (lr.value > lr.minValue) lr.decrement() } }
        }
        Text {
            text:                  lr.value + "%"
            color:                 lr.textColor
            font.pixelSize:        12; font.bold: true
            horizontalAlignment:   Text.AlignHCenter
            Layout.preferredWidth: 44
        }
        // ── Increment button ──────────────────────────────────────────────
        Rectangle {
            width: 22; height: 22; radius: 5
            color:        incHover.hovered ? "#22ffffff" : "transparent"
            border.color: lr.borderColor
            border.width: Cfg.Config.popupBorderWidth
            Text {
                anchors.centerIn: parent; text: "+"
                color: lr.value >= lr.maxValue ? lr.dimColor : lr.textColor
                font.pixelSize: 14
            }
            HoverHandler { id: incHover; cursorShape: Qt.PointingHandCursor }
            TapHandler   { onTapped: { if (lr.value < lr.maxValue) lr.increment() } }
        }
    }
}
