pragma ComponentBehavior: Bound

import ".."
import "../components"
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import Caelestia.Config
import qs.components
import qs.components.containers
import qs.components.controls
import qs.components.effects
import qs.services

Item {
    id: root

    required property Session session

    anchors.fill: parent

    SplitPaneLayout {
        anchors.fill: parent

        leftContent: Component {
            StyledFlickable {
                id: leftAudioFlickable

                flickableDirection: Flickable.VerticalFlick
                contentHeight: leftContent.height

                StyledScrollBar.vertical: StyledScrollBar {
                    flickable: leftAudioFlickable
                }

                ColumnLayout {
                    id: leftContent

                    anchors.left: parent.left
                    anchors.right: parent.right
                    spacing: Tokens.spacing.medium

                    RowLayout {
                        Layout.fillWidth: true
                        spacing: Tokens.spacing.medium

                        StyledText {
                            text: qsTr("Audio")
                            font: Tokens.font.body.builders.large.weight(Font.Medium).build()
                        }

                        Item {
                            Layout.fillWidth: true
                        }
                    }

                    CollapsibleSection {
                        id: outputDevicesSection

                        Layout.fillWidth: true
                        title: qsTr("Output devices")
                        expanded: true

                        ColumnLayout {
                            Layout.fillWidth: true
                            spacing: Tokens.spacing.small

                            RowLayout {
                                Layout.fillWidth: true
                                spacing: Tokens.spacing.small

                                StyledText {
                                    text: qsTr("Devices (%1)").arg(Audio.sinks.length)
                                    font: Tokens.font.body.builders.medium.weight(Font.Medium).build()
                                }
                            }

                            StyledText {
                                Layout.fillWidth: true
                                text: qsTr("All available output devices")
                                color: Colours.palette.m3outline
                            }

                            Repeater {
                                Layout.fillWidth: true
                                model: Audio.sinks

                                delegate: StyledRect {
                                    required property var modelData

                                    Layout.fillWidth: true

                                    color: Audio.sink?.id === modelData.id ? Colours.layer(Colours.palette.m3surfaceContainer, 2) : "transparent"
                                    radius: Tokens.rounding.large
                                    implicitHeight: outputRowLayout.implicitHeight + Tokens.padding.medium * 2

                                    StateLayer {
                                        onClicked: {
                                            Audio.setAudioSink(modelData);
                                        }
                                    }

                                    RowLayout {
                                        id: outputRowLayout

                                        anchors.left: parent.left
                                        anchors.right: parent.right
                                        anchors.verticalCenter: parent.verticalCenter
                                        anchors.margins: Tokens.padding.medium

                                        spacing: Tokens.spacing.medium

                                        MaterialIcon {
                                            text: Audio.sink?.id === modelData.id ? "speaker" : "speaker_group"
                                            fontStyle: Tokens.font.icon.large
                                            fill: Audio.sink?.id === modelData.id ? 1 : 0
                                        }

                                        StyledText {
                                            Layout.fillWidth: true
                                            elide: Text.ElideRight
                                            maximumLineCount: 1

                                            text: modelData.description || qsTr("Unknown")
                                            font: Audio.sink?.id === modelData.id ? Tokens.font.body.builders.small.weight(Font.Medium).build() : Tokens.font.body.builders.small.weight(Font.Normal).build()
                                        }
                                    }
                                }
                            }
                        }
                    }

                    CollapsibleSection {
                        id: inputDevicesSection

                        Layout.fillWidth: true
                        title: qsTr("Input devices")
                        expanded: true

                        ColumnLayout {
                            Layout.fillWidth: true
                            spacing: Tokens.spacing.small

                            RowLayout {
                                Layout.fillWidth: true
                                spacing: Tokens.spacing.small

                                StyledText {
                                    text: qsTr("Devices (%1)").arg(Audio.sources.length)
                                    font: Tokens.font.body.builders.medium.weight(Font.Medium).build()
                                }
                            }

                            StyledText {
                                Layout.fillWidth: true
                                text: qsTr("All available input devices")
                                color: Colours.palette.m3outline
                            }

                            Repeater {
                                Layout.fillWidth: true
                                model: Audio.sources

                                delegate: StyledRect {
                                    required property var modelData

                                    Layout.fillWidth: true

                                    color: Audio.source?.id === modelData.id ? Colours.layer(Colours.palette.m3surfaceContainer, 2) : "transparent"
                                    radius: Tokens.rounding.large
                                    implicitHeight: inputRowLayout.implicitHeight + Tokens.padding.medium * 2

                                    StateLayer {
                                        onClicked: {
                                            Audio.setAudioSource(modelData);
                                        }
                                    }

                                    RowLayout {
                                        id: inputRowLayout

                                        anchors.left: parent.left
                                        anchors.right: parent.right
                                        anchors.verticalCenter: parent.verticalCenter
                                        anchors.margins: Tokens.padding.medium

                                        spacing: Tokens.spacing.medium

                                        MaterialIcon {
                                            text: "mic"
                                            fontStyle: Tokens.font.icon.large
                                            fill: Audio.source?.id === modelData.id ? 1 : 0
                                        }

                                        StyledText {
                                            Layout.fillWidth: true
                                            elide: Text.ElideRight
                                            maximumLineCount: 1

                                            text: modelData.description || qsTr("Unknown")
                                            font: Audio.source?.id === modelData.id ? Tokens.font.body.builders.small.weight(Font.Medium).build() : Tokens.font.body.builders.small.weight(Font.Normal).build()
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        rightContent: Component {
            StyledFlickable {
                id: rightAudioFlickable

                flickableDirection: Flickable.VerticalFlick
                contentHeight: contentLayout.height

                StyledScrollBar.vertical: StyledScrollBar {
                    flickable: rightAudioFlickable
                }

                ColumnLayout {
                    id: contentLayout

                    anchors.left: parent.left
                    anchors.right: parent.right
                    anchors.top: parent.top
                    spacing: Tokens.spacing.medium

                    SettingsHeader {
                        icon: "volume_up"
                        title: qsTr("Audio Settings")
                    }

                    SectionHeader {
                        title: qsTr("Output volume")
                        description: qsTr("Control the volume of your output device")
                    }

                    SectionContainer {
                        contentSpacing: Tokens.spacing.medium

                        ColumnLayout {
                            Layout.fillWidth: true
                            spacing: Tokens.spacing.small

                            RowLayout {
                                Layout.fillWidth: true
                                spacing: Tokens.spacing.medium

                                StyledText {
                                    text: qsTr("Volume")
                                    font: Tokens.font.body.builders.medium.weight(Font.Medium).build()
                                }

                                Item {
                                    Layout.fillWidth: true
                                }

                                StyledInputField {
                                    id: outputVolumeInput

                                    Layout.preferredWidth: 70
                                    validator: IntValidator {
                                        bottom: 0
                                        top: 100
                                    }
                                    enabled: !Audio.muted

                                    Component.onCompleted: {
                                        text = Math.round(Audio.volume * 100).toString();
                                    }

                                    onTextEdited: text => {
                                        if (hasFocus) {
                                            const val = parseInt(text);
                                            if (!isNaN(val) && val >= 0 && val <= 100) {
                                                Audio.setVolume(val / 100);
                                            }
                                        }
                                    }

                                    onEditingFinished: {
                                        const val = parseInt(text);
                                        if (isNaN(val) || val < 0 || val > 100) {
                                            text = Math.round(Audio.volume * 100).toString();
                                        }
                                    }

                                    Connections {
                                        function onVolumeChanged() {
                                            if (!outputVolumeInput.hasFocus) {
                                                outputVolumeInput.text = Math.round(Audio.volume * 100).toString();
                                            }
                                        }

                                        target: Audio
                                    }
                                }

                                StyledText {
                                    text: "%"
                                    color: Colours.palette.m3outline
                                    font: Tokens.font.body.medium
                                    opacity: Audio.muted ? 0.5 : 1
                                }

                                StyledRect {
                                    implicitWidth: implicitHeight
                                    implicitHeight: muteIcon.implicitHeight + Tokens.padding.medium * 2

                                    radius: Tokens.rounding.large
                                    color: Audio.muted ? Colours.palette.m3secondary : Colours.palette.m3secondaryContainer

                                    StateLayer {
                                        onClicked: {
                                            if (Audio.sink?.audio) {
                                                Audio.sink.audio.muted = !Audio.sink.audio.muted;
                                            }
                                        }
                                    }

                                    MaterialIcon {
                                        id: muteIcon

                                        anchors.centerIn: parent
                                        text: Audio.muted ? "volume_off" : "volume_up"
                                        color: Audio.muted ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer
                                    }
                                }
                            }

                            StyledSlider {
                                id: outputVolumeSlider

                                Layout.fillWidth: true
                                implicitHeight: Tokens.padding.medium * 3

                                value: Audio.volume
                                enabled: !Audio.muted
                                opacity: enabled ? 1 : 0.5
                                onMoved: {
                                    Audio.setVolume(value);
                                    if (!outputVolumeInput.hasFocus) {
                                        outputVolumeInput.text = Math.round(value * 100).toString();
                                    }
                                }
                            }
                        }
                    }

                    SectionHeader {
                        title: qsTr("Input volume")
                        description: qsTr("Control the volume of your input device")
                    }

                    SectionContainer {
                        contentSpacing: Tokens.spacing.medium

                        ColumnLayout {
                            Layout.fillWidth: true
                            spacing: Tokens.spacing.small

                            RowLayout {
                                Layout.fillWidth: true
                                spacing: Tokens.spacing.medium

                                StyledText {
                                    text: qsTr("Volume")
                                    font: Tokens.font.body.builders.medium.weight(Font.Medium).build()
                                }

                                Item {
                                    Layout.fillWidth: true
                                }

                                StyledInputField {
                                    id: inputVolumeInput

                                    Layout.preferredWidth: 70
                                    validator: IntValidator {
                                        bottom: 0
                                        top: 100
                                    }
                                    enabled: !Audio.sourceMuted

                                    Component.onCompleted: {
                                        text = Math.round(Audio.sourceVolume * 100).toString();
                                    }

                                    onTextEdited: text => {
                                        if (hasFocus) {
                                            const val = parseInt(text);
                                            if (!isNaN(val) && val >= 0 && val <= 100) {
                                                Audio.setSourceVolume(val / 100);
                                            }
                                        }
                                    }

                                    onEditingFinished: {
                                        const val = parseInt(text);
                                        if (isNaN(val) || val < 0 || val > 100) {
                                            text = Math.round(Audio.sourceVolume * 100).toString();
                                        }
                                    }

                                    Connections {
                                        function onSourceVolumeChanged() {
                                            if (!inputVolumeInput.hasFocus) {
                                                inputVolumeInput.text = Math.round(Audio.sourceVolume * 100).toString();
                                            }
                                        }

                                        target: Audio
                                    }
                                }

                                StyledText {
                                    text: "%"
                                    color: Colours.palette.m3outline
                                    font: Tokens.font.body.medium
                                    opacity: Audio.sourceMuted ? 0.5 : 1
                                }

                                StyledRect {
                                    implicitWidth: implicitHeight
                                    implicitHeight: muteInputIcon.implicitHeight + Tokens.padding.medium * 2

                                    radius: Tokens.rounding.large
                                    color: Audio.sourceMuted ? Colours.palette.m3secondary : Colours.palette.m3secondaryContainer

                                    StateLayer {
                                        onClicked: {
                                            if (Audio.source?.audio) {
                                                Audio.source.audio.muted = !Audio.source.audio.muted;
                                            }
                                        }
                                    }

                                    MaterialIcon {
                                        id: muteInputIcon

                                        anchors.centerIn: parent
                                        text: "mic_off"
                                        color: Audio.sourceMuted ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer
                                    }
                                }
                            }

                            StyledSlider {
                                id: inputVolumeSlider

                                Layout.fillWidth: true
                                implicitHeight: Tokens.padding.medium * 3

                                value: Audio.sourceVolume
                                enabled: !Audio.sourceMuted
                                opacity: enabled ? 1 : 0.5
                                onMoved: {
                                    Audio.setSourceVolume(value);
                                    if (!inputVolumeInput.hasFocus) {
                                        inputVolumeInput.text = Math.round(value * 100).toString();
                                    }
                                }
                            }
                        }
                    }

                    SectionHeader {
                        title: qsTr("Applications")
                        description: qsTr("Control volume for individual applications")
                    }

                    SectionContainer {
                        contentSpacing: Tokens.spacing.medium

                        ColumnLayout {
                            Layout.fillWidth: true
                            spacing: Tokens.spacing.small

                            Repeater {
                                model: Audio.streams
                                Layout.fillWidth: true

                                delegate: ColumnLayout {
                                    required property var modelData
                                    required property int index

                                    Layout.fillWidth: true
                                    spacing: Tokens.spacing.medium

                                    RowLayout {
                                        Layout.fillWidth: true
                                        spacing: Tokens.spacing.medium

                                        MaterialIcon {
                                            text: "apps"
                                            fontStyle: Tokens.font.icon.medium
                                            fill: 0
                                        }

                                        StyledText {
                                            Layout.fillWidth: true
                                            elide: Text.ElideRight
                                            maximumLineCount: 1
                                            text: Audio.getStreamName(modelData)
                                            font: Tokens.font.body.builders.medium.weight(Font.Medium).build()
                                        }

                                        StyledInputField {
                                            id: streamVolumeInput

                                            Layout.preferredWidth: 70
                                            validator: IntValidator {
                                                bottom: 0
                                                top: 100
                                            }
                                            enabled: !Audio.getStreamMuted(modelData)

                                            Component.onCompleted: {
                                                text = Math.round(Audio.getStreamVolume(modelData) * 100).toString();
                                            }

                                            onTextEdited: text => {
                                                if (hasFocus) {
                                                    const val = parseInt(text);
                                                    if (!isNaN(val) && val >= 0 && val <= 100) {
                                                        Audio.setStreamVolume(modelData, val / 100);
                                                    }
                                                }
                                            }

                                            onEditingFinished: {
                                                const val = parseInt(text);
                                                if (isNaN(val) || val < 0 || val > 100) {
                                                    text = Math.round(Audio.getStreamVolume(modelData) * 100).toString();
                                                }
                                            }

                                            Connections {
                                                function onAudioChanged() {
                                                    if (!streamVolumeInput.hasFocus && modelData?.audio) {
                                                        streamVolumeInput.text = Math.round(modelData.audio.volume * 100).toString();
                                                    }
                                                }

                                                target: modelData
                                            }
                                        }

                                        StyledText {
                                            text: "%"
                                            color: Colours.palette.m3outline
                                            font: Tokens.font.body.medium
                                            opacity: Audio.getStreamMuted(modelData) ? 0.5 : 1
                                        }

                                        StyledRect {
                                            implicitWidth: implicitHeight
                                            implicitHeight: streamMuteIcon.implicitHeight + Tokens.padding.medium * 2

                                            radius: Tokens.rounding.large
                                            color: Audio.getStreamMuted(modelData) ? Colours.palette.m3secondary : Colours.palette.m3secondaryContainer

                                            StateLayer {
                                                onClicked: {
                                                    Audio.setStreamMuted(modelData, !Audio.getStreamMuted(modelData));
                                                }
                                            }

                                            MaterialIcon {
                                                id: streamMuteIcon

                                                anchors.centerIn: parent
                                                text: Audio.getStreamMuted(modelData) ? "volume_off" : "volume_up"
                                                color: Audio.getStreamMuted(modelData) ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer
                                            }
                                        }
                                    }

                                    StyledSlider {
                                        Layout.fillWidth: true
                                        implicitHeight: Tokens.padding.medium * 3

                                        value: Audio.getStreamVolume(modelData)
                                        enabled: !Audio.getStreamMuted(modelData)
                                        opacity: enabled ? 1 : 0.5
                                        onMoved: {
                                            Audio.setStreamVolume(modelData, value);
                                            if (!streamVolumeInput.hasFocus) {
                                                streamVolumeInput.text = Math.round(value * 100).toString();
                                            }
                                        }

                                        Connections {
                                            function onAudioChanged() {
                                                if (modelData?.audio) {
                                                    value = modelData.audio.volume;
                                                }
                                            }

                                            target: modelData
                                        }
                                    }
                                }
                            }

                            StyledText {
                                Layout.fillWidth: true
                                visible: Audio.streams.length === 0
                                text: qsTr("No applications currently playing audio")
                                color: Colours.palette.m3outline
                                font: Tokens.font.body.small
                                horizontalAlignment: Text.AlignHCenter
                            }
                        }
                    }
                }
            }
        }
    }
}
