pragma ComponentBehavior: Bound

import Quickshell
import Quickshell.Services.Pipewire
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import qs.Config
import qs.Components
import qs.Daemons
import qs.Helpers

Item {
	id: root

	readonly property int rounding: Appearance.rounding.small - Appearance.padding.small
	readonly property int topMargin: 0
	required property var wrapper

	implicitHeight: layout.implicitHeight + Appearance.padding.small * 2
	implicitWidth: layout.implicitWidth + Appearance.padding.small * 2

	CustomRect {
		anchors.left: parent.left
		anchors.right: parent.right
		color: DynamicColors.tPalette.m3surfaceContainer
		implicitHeight: parent.implicitHeight
		radius: Appearance.rounding.small
		y: parent.y

		Behavior on implicitHeight {
			Anim {
				duration: MaterialEasing.emphasizedDecelTime
				easing.bezierCurve: MaterialEasing.emphasized
			}
		}
	}

	ColumnLayout {
		id: layout

		anchors.centerIn: parent
		implicitWidth: stack.currentItem ? stack.currentItem.childrenRect.height : 0
		spacing: 12

		RowLayout {
			id: tabBar

			property int tabHeight: 36

			Layout.fillWidth: true
			spacing: 6

			CustomClippingRect {
				Layout.fillWidth: true
				Layout.preferredHeight: tabBar.tabHeight
				color: stack.currentIndex === 0 ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
				radius: root.rounding

				StateLayer {
					function onClicked(): void {
						stack.currentIndex = 0;
					}

					CustomText {
						anchors.centerIn: parent
						color: stack.currentIndex === 0 ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3primary
						text: qsTr("Volumes")
					}
				}
			}

			CustomClippingRect {
				Layout.fillWidth: true
				Layout.preferredHeight: tabBar.tabHeight
				color: stack.currentIndex === 1 ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
				radius: root.rounding

				StateLayer {
					function onClicked(): void {
						stack.currentIndex = 1;
					}

					CustomText {
						anchors.centerIn: parent
						color: stack.currentIndex === 1 ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3primary
						text: qsTr("Devices")
					}
				}
			}
		}

		StackLayout {
			id: stack

			Layout.fillWidth: true
			Layout.preferredHeight: currentIndex === 0 ? vol.childrenRect.height : dev.childrenRect.height
			currentIndex: 0

			Behavior on currentIndex {
				SequentialAnimation {
					ParallelAnimation {
						Anim {
							duration: MaterialEasing.expressiveEffectsTime
							property: "opacity"
							target: stack
							to: 0
						}

						Anim {
							duration: MaterialEasing.expressiveEffectsTime
							property: "scale"
							target: stack
							to: 0.9
						}
					}

					PropertyAction {
					}

					ParallelAnimation {
						Anim {
							duration: MaterialEasing.expressiveEffectsTime
							property: "opacity"
							target: stack
							to: 1
						}

						Anim {
							duration: MaterialEasing.expressiveEffectsTime
							property: "scale"
							target: stack
							to: 1
						}
					}
				}
			}

			VolumesTab {
				id: vol
			}

			DevicesTab {
				id: dev
			}
		}
	}

	component DevicesTab: Item {
		implicitHeight: deviceColumn.height + Appearance.padding.normal
		implicitWidth: deviceColumn.width + Appearance.padding.normal

		ColumnLayout {
			id: deviceColumn

			anchors.centerIn: parent
			spacing: 12

			ButtonGroup {
				id: sinks
			}

			ButtonGroup {
				id: sources
			}

			CustomText {
				font.weight: 500
				text: qsTr("Output device")
			}

			Repeater {
				model: Audio.sinks

				CustomRadioButton {
					required property PwNode modelData

					ButtonGroup.group: sinks
					checked: Audio.sink?.id === modelData.id
					text: modelData.description

					onClicked: Audio.setAudioSink(modelData)
				}
			}

			CustomText {
				Layout.topMargin: 10
				font.weight: 500
				text: qsTr("Input device")
			}

			Repeater {
				model: Audio.sources

				CustomRadioButton {
					required property PwNode modelData

					ButtonGroup.group: sources
					checked: Audio.source?.id === modelData.id
					text: modelData.description

					onClicked: Audio.setAudioSource(modelData)
				}
			}
		}
	}
	component VolumesTab: ColumnLayout {
		spacing: 12

		CustomRect {
			Layout.fillWidth: true
			Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2
			Layout.topMargin: root.topMargin
			color: DynamicColors.tPalette.m3surfaceContainer
			radius: root.rounding

			RowLayout {
				id: outputVolume

				anchors.left: parent.left
				anchors.margins: Appearance.spacing.smaller
				anchors.right: parent.right
				anchors.verticalCenter: parent.verticalCenter
				spacing: 15

				CustomRect {
					Layout.alignment: Qt.AlignVCenter
					Layout.preferredHeight: 40
					Layout.preferredWidth: 40
					color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
					radius: Appearance.rounding.full

					MaterialIcon {
						anchors.alignWhenCentered: false
						anchors.centerIn: parent
						animate: true
						color: Audio.muted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary
						font.pointSize: 22
						text: Audio.muted ? "volume_off" : "volume_up"
					}

					StateLayer {
						color: Audio.muted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary

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

				ColumnLayout {
					Layout.fillWidth: true

					RowLayout {
						Layout.fillWidth: true

						CustomText {
							Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
							Layout.fillWidth: true
							text: "Output Volume"
						}

						CustomText {
							Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
							font.bold: true
							text: qsTr("%1").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`)
						}
					}

					CustomMouseArea {
						Layout.bottomMargin: 5
						Layout.fillWidth: true
						Layout.preferredHeight: 10

						CustomSlider {
							anchors.left: parent.left
							anchors.right: parent.right
							color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
							implicitHeight: 10
							value: Audio.volume

							Behavior on value {
								Anim {
								}
							}

							onMoved: Audio.setVolume(value)
						}
					}
				}
			}
		}

		CustomRect {
			Layout.fillWidth: true
			Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2
			Layout.topMargin: root.topMargin
			color: DynamicColors.tPalette.m3surfaceContainer
			radius: root.rounding

			RowLayout {
				id: inputVolume

				anchors.left: parent.left
				anchors.margins: Appearance.spacing.smaller
				anchors.right: parent.right
				anchors.verticalCenter: parent.verticalCenter
				spacing: 15

				CustomRect {
					Layout.alignment: Qt.AlignVCenter
					Layout.preferredHeight: 40
					Layout.preferredWidth: 40
					color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
					radius: Appearance.rounding.full

					MaterialIcon {
						anchors.alignWhenCentered: false
						anchors.centerIn: parent
						animate: true
						color: Audio.sourceMuted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary
						font.pointSize: 22
						text: Audio.sourceMuted ? "mic_off" : "mic"
					}

					StateLayer {
						color: Audio.sourceMuted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary

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

				ColumnLayout {
					Layout.fillWidth: true

					RowLayout {
						Layout.fillHeight: true
						Layout.fillWidth: true

						CustomText {
							Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
							Layout.fillWidth: true
							text: "Input Volume"
						}

						CustomText {
							Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
							font.bold: true
							text: qsTr("%1").arg(Audio.sourceMuted ? qsTr("Muted") : `${Math.round(Audio.sourceVolume * 100)}%`)
						}
					}

					CustomMouseArea {
						Layout.bottomMargin: 5
						Layout.fillWidth: true
						implicitHeight: 10

						CustomSlider {
							anchors.left: parent.left
							anchors.right: parent.right
							color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
							implicitHeight: 10
							value: Audio.sourceVolume

							Behavior on value {
								Anim {
								}
							}

							onMoved: Audio.setSourceVolume(value)
						}
					}
				}
			}
		}

		Rectangle {
			Layout.fillWidth: true
			Layout.preferredHeight: 1
			Layout.topMargin: root.topMargin
			color: DynamicColors.tPalette.m3outline
			visible: appTracks.model.length > 0
		}

		Repeater {
			id: appTracks

			model: Audio.streams.filter(s => s.isSink)

			CustomClippingRect {
				id: appBox

				required property int index
				required property var modelData

				Layout.fillWidth: true
				Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2
				Layout.topMargin: root.topMargin
				color: DynamicColors.tPalette.m3surfaceContainer
				radius: root.rounding

				PwNodePeakMonitor {
					id: peak

					node: appBox.modelData
				}

				CustomRect {
					id: peakFill

					anchors.bottom: parent.bottom
					anchors.left: parent.left
					anchors.top: parent.top
					color: Qt.alpha(DynamicColors.palette.m3primary, 0.15)
					implicitWidth: parent.width * peak.peak

					Behavior on implicitWidth {
						Anim {
							duration: MaterialEasing.expressiveEffectsTime
						}
					}
				}

				RowLayout {
					id: layoutVolume

					anchors.fill: parent
					anchors.margins: Appearance.spacing.smaller
					spacing: 15

					CustomRect {
						Layout.alignment: Qt.AlignVCenter
						Layout.preferredHeight: 40
						Layout.preferredWidth: 40
						color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
						radius: Appearance.rounding.full

						MaterialIcon {
							id: icon

							anchors.centerIn: parent
							animate: true
							color: appBox.modelData.audio.muted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary
							font.pointSize: 22
							text: appBox.modelData.audio.muted ? "volume_off" : "volume_up"
						}

						StateLayer {
							color: appBox.modelData.audio.muted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary
							radius: Appearance.rounding.full

							onClicked: {
								appBox.modelData.audio.muted = !appBox.modelData.audio.muted;
							}
						}
					}

					ColumnLayout {
						Layout.alignment: Qt.AlignLeft | Qt.AlignTop
						Layout.fillHeight: true

						TextMetrics {
							id: metrics

							elide: Text.ElideRight
							elideWidth: root.width - 50
							text: Audio.getStreamName(appBox.modelData)
						}

						RowLayout {
							Layout.fillHeight: true
							Layout.fillWidth: true

							CustomText {
								Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
								Layout.fillHeight: true
								Layout.fillWidth: true
								elide: Text.ElideRight
								text: metrics.elidedText
							}

							CustomText {
								Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
								Layout.fillHeight: true
								font.bold: true
								text: qsTr("%1").arg(appBox.modelData.audio.muted ? qsTr("Muted") : `${Math.round(appBox.modelData.audio.volume * 100)}%`)
							}
						}

						CustomMouseArea {
							Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
							Layout.fillHeight: true
							Layout.fillWidth: true
							implicitHeight: 10

							CustomSlider {
								anchors.left: parent.left
								anchors.right: parent.right
								color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
								implicitHeight: 10
								value: appBox.modelData.audio.volume

								onMoved: {
									Audio.setStreamVolume(appBox.modelData, value);
								}
							}
						}
					}
				}
			}
		}
	}
}
