import Quickshell
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Services.UPower
import ZShell.Internal
import qs.Components
import qs.Helpers
import qs.Config

Item {
	id: root

	readonly property int minWidth: 400 + 400 + Appearance.spacing.normal + 120 + Appearance.padding.large * 2
	readonly property real nonAnimHeight: content.implicitHeight + Appearance.padding.normal * 2
	readonly property real nonAnimWidth: Math.max(minWidth, content.implicitWidth) + Appearance.padding.normal * 2
	required property real padding
	required property PersistentProperties visibilities

	function displayTemp(temp: real): string {
		return `${Math.ceil(temp)}°C`;
	}

	implicitHeight: nonAnimHeight
	implicitWidth: nonAnimWidth

	RowLayout {
		id: content

		anchors.left: parent.left
		anchors.leftMargin: root.padding
		anchors.right: parent.right
		anchors.rightMargin: root.padding
		anchors.verticalCenter: parent.verticalCenter
		spacing: Appearance.spacing.normal

		Ref {
			service: SystemUsage
		}

		ColumnLayout {
			id: mainColumn

			Layout.fillWidth: true
			spacing: Appearance.spacing.normal

			RowLayout {
				Layout.fillWidth: true
				spacing: Appearance.spacing.normal
				visible: Config.dashboard.performance.showCpu || (Config.dashboard.performance.showGpu && SystemUsage.gpuType !== "NONE")

				HeroCard {
					Layout.fillWidth: true
					Layout.minimumWidth: 400
					Layout.preferredHeight: 150
					accentColor: DynamicColors.palette.m3primary
					icon: "memory"
					mainLabel: qsTr("Usage")
					mainValue: `${Math.round(SystemUsage.cpuPerc * 100)}%`
					secondaryLabel: qsTr("Temp")
					secondaryValue: root.displayTemp(SystemUsage.cpuTemp)
					temperature: SystemUsage.cpuTemp
					title: SystemUsage.cpuName ? `CPU - ${SystemUsage.cpuName}` : qsTr("CPU")
					usage: SystemUsage.cpuPerc
					visible: Config.dashboard.performance.showCpu
				}

				HeroCard {
					Layout.fillWidth: true
					Layout.minimumWidth: 400
					Layout.preferredHeight: 150
					accentColor: DynamicColors.palette.m3secondary
					icon: "desktop_windows"
					mainLabel: qsTr("Usage")
					mainValue: `${Math.round(SystemUsage.gpuPerc * 100)}%`
					secondaryLabel: qsTr("Temp")
					secondaryValue: root.displayTemp(SystemUsage.gpuTemp)
					temperature: SystemUsage.gpuTemp
					title: SystemUsage.gpuName ? `GPU - ${SystemUsage.gpuName}` : qsTr("GPU")
					usage: SystemUsage.gpuPerc
					visible: Config.dashboard.performance.showGpu && SystemUsage.gpuType !== "NONE"
				}
			}

			RowLayout {
				Layout.fillWidth: true
				spacing: Appearance.spacing.normal
				visible: Config.dashboard.performance.showMemory || Config.dashboard.performance.showStorage || Config.dashboard.performance.showNetwork

				GaugeCard {
					Layout.fillWidth: !Config.dashboard.performance.showStorage && !Config.dashboard.performance.showNetwork
					Layout.minimumWidth: 250
					Layout.preferredHeight: 220
					accentColor: DynamicColors.palette.m3tertiary
					icon: "memory_alt"
					percentage: SystemUsage.memPerc
					subtitle: {
						const usedFmt = SystemUsage.formatKib(SystemUsage.memUsed);
						const totalFmt = SystemUsage.formatKib(SystemUsage.memTotal);
						return `${usedFmt.value.toFixed(1)} / ${Math.floor(totalFmt.value)} ${totalFmt.unit}`;
					}
					title: qsTr("Memory")
					visible: Config.dashboard.performance.showMemory
				}

				StorageGaugeCard {
					Layout.fillWidth: !Config.dashboard.performance.showNetwork
					Layout.minimumWidth: 250
					Layout.preferredHeight: 220
					visible: Config.dashboard.performance.showStorage
				}

				NetworkCard {
					Layout.fillWidth: true
					Layout.minimumWidth: 200
					Layout.preferredHeight: 220
					visible: Config.dashboard.performance.showNetwork
				}
			}
		}

		BatteryTank {
			Layout.preferredHeight: mainColumn.implicitHeight
			Layout.preferredWidth: 120
			visible: UPower.displayDevice.isLaptopBattery && Config.dashboard.performance.showBattery
		}
	}

	component BatteryTank: CustomClippingRect {
		id: batteryTank

		property color accentColor: DynamicColors.palette.m3primary
		property real animatedPercentage: 0
		property bool isCharging: UPower.displayDevice.state === UPowerDeviceState.Charging
		property real percentage: UPower.displayDevice.percentage

		color: DynamicColors.tPalette.m3surfaceContainer
		radius: Appearance.rounding.large - Appearance.padding.normal

		Behavior on animatedPercentage {
			Anim {
				duration: Appearance.anim.durations.large
			}
		}

		Component.onCompleted: animatedPercentage = percentage
		onPercentageChanged: animatedPercentage = percentage

		// Background Fill
		CustomRect {
			anchors.bottom: parent.bottom
			anchors.left: parent.left
			anchors.right: parent.right
			color: Qt.alpha(batteryTank.accentColor, 0.15)
			height: parent.height * batteryTank.animatedPercentage
		}

		ColumnLayout {
			anchors.fill: parent
			anchors.margins: Appearance.padding.large
			spacing: Appearance.spacing.small

			// Header Section
			ColumnLayout {
				Layout.fillWidth: true
				spacing: Appearance.spacing.small

				MaterialIcon {
					color: batteryTank.accentColor
					font.pointSize: Appearance.font.size.large
					text: {
						if (!UPower.displayDevice.isLaptopBattery) {
							if (PowerProfiles.profile === PowerProfile.PowerSaver)
								return "energy_savings_leaf";

							if (PowerProfiles.profile === PowerProfile.Performance)
								return "rocket_launch";

							return "balance";
						}
						if (UPower.displayDevice.state === UPowerDeviceState.FullyCharged)
							return "battery_full";

						const perc = UPower.displayDevice.percentage;
						const charging = [UPowerDeviceState.Charging, UPowerDeviceState.PendingCharge].includes(UPower.displayDevice.state);
						if (perc >= 0.99)
							return "battery_full";

						let level = Math.floor(perc * 7);
						if (charging && (level === 4 || level === 1))
							level--;

						return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`;
					}
				}

				CustomText {
					Layout.fillWidth: true
					color: DynamicColors.palette.m3onSurface
					font.pointSize: Appearance.font.size.normal
					text: qsTr("Battery")
				}
			}

			Item {
				Layout.fillHeight: true
			}

			// Bottom Info Section
			ColumnLayout {
				Layout.fillWidth: true
				spacing: -4

				CustomText {
					Layout.alignment: Qt.AlignRight
					color: batteryTank.accentColor
					font.pointSize: Appearance.font.size.extraLarge
					font.weight: Font.Medium
					text: `${Math.round(batteryTank.percentage * 100)}%`
				}

				CustomText {
					Layout.alignment: Qt.AlignRight
					color: DynamicColors.palette.m3onSurfaceVariant
					font.pointSize: Appearance.font.size.smaller
					text: {
						if (UPower.displayDevice.state === UPowerDeviceState.FullyCharged)
							return qsTr("Full");

						if (batteryTank.isCharging)
							return qsTr("Charging");

						const s = UPower.displayDevice.timeToEmpty;
						if (s === 0)
							return qsTr("...");

						const hr = Math.floor(s / 3600);
						const min = Math.floor((s % 3600) / 60);
						if (hr > 0)
							return `${hr}h ${min}m`;

						return `${min}m`;
					}
				}
			}
		}
	}
	component CardHeader: RowLayout {
		property color accentColor: DynamicColors.palette.m3primary
		property string icon
		property string title

		Layout.fillWidth: true
		spacing: Appearance.spacing.small

		MaterialIcon {
			color: parent.accentColor
			fill: 1
			font.pointSize: Appearance.spacing.large
			text: parent.icon
		}

		CustomText {
			Layout.fillWidth: true
			elide: Text.ElideRight
			font.pointSize: Appearance.font.size.normal
			text: parent.title
		}
	}
	component GaugeCard: CustomRect {
		id: gaugeCard

		property color accentColor: DynamicColors.palette.m3primary
		property real animatedPercentage: 0
		readonly property real arcStartAngle: 0.75 * Math.PI
		readonly property real arcSweep: 1.5 * Math.PI
		property string icon
		property real percentage: 0
		property string subtitle
		property string title

		clip: true
		color: DynamicColors.tPalette.m3surfaceContainer
		radius: Appearance.rounding.large - Appearance.padding.normal

		Behavior on animatedPercentage {
			Anim {
				duration: Appearance.anim.durations.large
			}
		}

		Component.onCompleted: animatedPercentage = percentage
		onPercentageChanged: animatedPercentage = percentage

		ColumnLayout {
			anchors.fill: parent
			anchors.margins: Appearance.padding.large
			spacing: Appearance.spacing.smaller

			CardHeader {
				accentColor: gaugeCard.accentColor
				icon: gaugeCard.icon
				title: gaugeCard.title
			}

			Item {
				Layout.fillHeight: true
				Layout.fillWidth: true

				ArcGauge {
					accentColor: gaugeCard.accentColor
					anchors.centerIn: parent
					height: width
					percentage: gaugeCard.animatedPercentage
					startAngle: gaugeCard.arcStartAngle
					sweepAngle: gaugeCard.arcSweep
					trackColor: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
					width: Math.min(parent.width, parent.height)
				}

				CustomText {
					anchors.centerIn: parent
					color: gaugeCard.accentColor
					font.pointSize: Appearance.font.size.extraLarge
					font.weight: Font.Medium
					text: `${Math.round(gaugeCard.percentage * 100)}%`
				}
			}

			CustomText {
				Layout.alignment: Qt.AlignHCenter
				color: DynamicColors.palette.m3onSurfaceVariant
				font.pointSize: Appearance.font.size.smaller
				text: gaugeCard.subtitle
			}
		}
	}
	component HeroCard: CustomClippingRect {
		id: heroCard

		property color accentColor: DynamicColors.palette.m3primary
		property real animatedTemp: 0
		property real animatedUsage: 0
		property string icon
		property string mainLabel
		property string mainValue
		readonly property real maxTemp: 100
		property string secondaryLabel
		property string secondaryValue
		readonly property real tempProgress: Math.min(1, Math.max(0, temperature / maxTemp))
		property real temperature: 0
		property string title
		property real usage: 0

		color: DynamicColors.tPalette.m3surfaceContainer
		radius: Appearance.rounding.large - Appearance.padding.normal

		Behavior on animatedTemp {
			Anim {
				duration: Appearance.anim.durations.large
			}
		}
		Behavior on animatedUsage {
			Anim {
				duration: Appearance.anim.durations.large
			}
		}

		Component.onCompleted: {
			animatedUsage = usage;
			animatedTemp = tempProgress;
		}
		onTempProgressChanged: animatedTemp = tempProgress
		onUsageChanged: animatedUsage = usage

		CustomRect {
			anchors.bottom: parent.bottom
			anchors.left: parent.left
			anchors.top: parent.top
			color: Qt.alpha(heroCard.accentColor, 0.15)
			implicitWidth: parent.width * heroCard.animatedUsage
		}

		CardHeader {
			accentColor: heroCard.accentColor
			anchors.left: parent.left
			anchors.leftMargin: Appearance.padding.large
			anchors.top: parent.top
			anchors.topMargin: Math.round(Appearance.padding.large * 1.2)
			icon: heroCard.icon
			title: heroCard.title
			width: parent.width - anchors.leftMargin - usageColumn.anchors.rightMargin - usageLabel.width - Appearance.spacing.normal
		}

		Column {
			anchors.bottom: parent.bottom
			anchors.bottomMargin: Math.round(Appearance.padding.large * 1.3)
			anchors.left: parent.left
			anchors.margins: Math.round(Appearance.padding.large * 1.2)
			anchors.right: parent.right
			spacing: Appearance.spacing.small

			Row {
				spacing: Appearance.spacing.small

				CustomText {
					font.pointSize: Appearance.font.size.normal
					font.weight: Font.Medium
					text: heroCard.secondaryValue
				}

				CustomText {
					anchors.baseline: parent.children[0].baseline
					color: DynamicColors.palette.m3onSurfaceVariant
					font.pointSize: Appearance.font.size.small
					text: heroCard.secondaryLabel
				}
			}

			ProgressBar {
				bgColor: Qt.alpha(heroCard.accentColor, 0.2)
				fgColor: heroCard.accentColor
				implicitHeight: 6
				implicitWidth: parent.width * 0.5
				value: heroCard.tempProgress
			}
		}

		Column {
			id: usageColumn

			anchors.margins: Appearance.padding.large
			anchors.right: parent.right
			anchors.rightMargin: 32
			anchors.verticalCenter: parent.verticalCenter
			spacing: 0

			CustomText {
				id: usageLabel

				anchors.right: parent.right
				color: DynamicColors.palette.m3onSurfaceVariant
				font.pointSize: Appearance.font.size.normal
				text: heroCard.mainLabel
			}

			CustomText {
				anchors.right: parent.right
				color: heroCard.accentColor
				font.pointSize: Appearance.font.size.extraLarge
				font.weight: Font.Medium
				text: heroCard.mainValue
			}
		}
	}
	component NetworkCard: CustomRect {
		id: networkCard

		property color accentColor: DynamicColors.palette.m3primary

		clip: true
		color: DynamicColors.tPalette.m3surfaceContainer
		radius: Appearance.rounding.large - Appearance.padding.normal

		Ref {
			service: NetworkUsage
		}

		ColumnLayout {
			anchors.fill: parent
			anchors.margins: Appearance.padding.large
			spacing: Appearance.spacing.small

			CardHeader {
				accentColor: networkCard.accentColor
				icon: "swap_vert"
				title: qsTr("Network")
			}

			// Sparkline graph
			Item {
				Layout.fillHeight: true
				Layout.fillWidth: true

				SparklineItem {
					id: sparkline

					property real smoothMax: targetMax
					property real targetMax: 1024

					anchors.fill: parent
					historyLength: NetworkUsage.historyLength
					line1: NetworkUsage.uploadBuffer // qmllint disable missing-type
					line1Color: DynamicColors.palette.m3secondary
					line1FillAlpha: 0.15
					line2: NetworkUsage.downloadBuffer // qmllint disable missing-type
					line2Color: DynamicColors.palette.m3tertiary
					line2FillAlpha: 0.2
					maxValue: smoothMax

					Behavior on smoothMax {
						Anim {
							duration: Appearance.anim.durations.large
						}
					}

					Connections {
						function onValuesChanged(): void {
							sparkline.targetMax = Math.max(NetworkUsage.downloadBuffer.maximum, NetworkUsage.uploadBuffer.maximum, 1024);
							slideAnim.restart();
						}

						target: NetworkUsage.downloadBuffer
					}

					NumberAnimation {
						id: slideAnim

						duration: Config.dashboard.resourceUpdateInterval
						from: 0
						property: "slideProgress"
						target: sparkline
						to: 1
					}
				}

				// "No data" placeholder
				CustomText {
					anchors.centerIn: parent
					color: DynamicColors.palette.m3onSurfaceVariant
					font.pointSize: Appearance.font.size.small
					opacity: 0.6
					text: qsTr("Collecting data...")
					visible: NetworkUsage.downloadBuffer.count < 2
				}
			}

			// Download row
			RowLayout {
				Layout.fillWidth: true
				spacing: Appearance.spacing.normal

				MaterialIcon {
					color: DynamicColors.palette.m3tertiary
					font.pointSize: Appearance.font.size.normal
					text: "download"
				}

				CustomText {
					color: DynamicColors.palette.m3onSurfaceVariant
					font.pointSize: Appearance.font.size.small
					text: qsTr("Download")
				}

				Item {
					Layout.fillWidth: true
				}

				CustomText {
					color: DynamicColors.palette.m3tertiary
					font.pointSize: Appearance.font.size.normal
					font.weight: Font.Medium
					text: {
						const fmt = NetworkUsage.formatBytes(NetworkUsage.downloadSpeed ?? 0);
						return fmt ? `${fmt.value.toFixed(1)} ${fmt.unit}` : "0.0 B/s";
					}
				}
			}

			// Upload row
			RowLayout {
				Layout.fillWidth: true
				spacing: Appearance.spacing.normal

				MaterialIcon {
					color: DynamicColors.palette.m3secondary
					font.pointSize: Appearance.font.size.normal
					text: "upload"
				}

				CustomText {
					color: DynamicColors.palette.m3onSurfaceVariant
					font.pointSize: Appearance.font.size.small
					text: qsTr("Upload")
				}

				Item {
					Layout.fillWidth: true
				}

				CustomText {
					color: DynamicColors.palette.m3secondary
					font.pointSize: Appearance.font.size.normal
					font.weight: Font.Medium
					text: {
						const fmt = NetworkUsage.formatBytes(NetworkUsage.uploadSpeed ?? 0);
						return fmt ? `${fmt.value.toFixed(1)} ${fmt.unit}` : "0.0 B/s";
					}
				}
			}

			// Session totals
			RowLayout {
				Layout.fillWidth: true
				spacing: Appearance.spacing.normal

				MaterialIcon {
					color: DynamicColors.palette.m3onSurfaceVariant
					font.pointSize: Appearance.font.size.normal
					text: "history"
				}

				CustomText {
					color: DynamicColors.palette.m3onSurfaceVariant
					font.pointSize: Appearance.font.size.small
					text: qsTr("Total")
				}

				Item {
					Layout.fillWidth: true
				}

				CustomText {
					color: DynamicColors.palette.m3onSurfaceVariant
					font.pointSize: Appearance.font.size.small
					text: {
						const down = NetworkUsage.formatBytesTotal(NetworkUsage.downloadTotal ?? 0);
						const up = NetworkUsage.formatBytesTotal(NetworkUsage.uploadTotal ?? 0);
						return (down && up) ? `↓${down.value.toFixed(1)}${down.unit} ↑${up.value.toFixed(1)}${up.unit}` : "↓0.0B ↑0.0B";
					}
				}
			}
		}
	}
	component ProgressBar: CustomRect {
		id: progressBar

		property real animatedValue: 0
		property color bgColor: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
		property color fgColor: DynamicColors.palette.m3primary
		property real value: 0

		color: bgColor
		radius: Appearance.rounding.full

		Behavior on animatedValue {
			Anim {
				duration: Appearance.anim.durations.large
			}
		}

		Component.onCompleted: animatedValue = value
		onValueChanged: animatedValue = value

		CustomRect {
			anchors.bottom: parent.bottom
			anchors.left: parent.left
			anchors.top: parent.top
			color: progressBar.fgColor
			radius: Appearance.rounding.full
			width: parent.width * progressBar.animatedValue
		}
	}
	component StorageGaugeCard: CustomRect {
		id: storageGaugeCard

		property color accentColor: DynamicColors.palette.m3secondary
		property real animatedPercentage: 0
		readonly property real arcStartAngle: 0.75 * Math.PI
		readonly property real arcSweep: 1.5 * Math.PI
		readonly property var currentDisk: SystemUsage.disks.length > 0 ? SystemUsage.disks[currentDiskIndex] : null
		property int currentDiskIndex: 0
		property int diskCount: 0

		clip: true
		color: DynamicColors.tPalette.m3surfaceContainer
		radius: Appearance.rounding.large - Appearance.padding.normal

		Behavior on animatedPercentage {
			Anim {
				duration: Appearance.anim.durations.large
			}
		}

		Component.onCompleted: {
			diskCount = SystemUsage.disks.length;
			if (currentDisk)
				animatedPercentage = currentDisk.perc;
		}
		onCurrentDiskChanged: {
			if (currentDisk)
				animatedPercentage = currentDisk.perc;
		}

		// Update diskCount and animatedPercentage when disks data changes
		Connections {
			function onDisksChanged() {
				if (SystemUsage.disks.length !== storageGaugeCard.diskCount)
					storageGaugeCard.diskCount = SystemUsage.disks.length;

				// Update animated percentage when disk data refreshes
				if (storageGaugeCard.currentDisk)
					storageGaugeCard.animatedPercentage = storageGaugeCard.currentDisk.perc;
			}

			target: SystemUsage
		}

		MouseArea {
			anchors.fill: parent

			onWheel: wheel => {
				if (wheel.angleDelta.y > 0)
					storageGaugeCard.currentDiskIndex = (storageGaugeCard.currentDiskIndex - 1 + storageGaugeCard.diskCount) % storageGaugeCard.diskCount;
				else if (wheel.angleDelta.y < 0)
					storageGaugeCard.currentDiskIndex = (storageGaugeCard.currentDiskIndex + 1) % storageGaugeCard.diskCount;
			}
		}

		ColumnLayout {
			anchors.fill: parent
			anchors.margins: Appearance.padding.large
			spacing: Appearance.spacing.smaller

			CardHeader {
				accentColor: storageGaugeCard.accentColor
				icon: "hard_disk"
				title: {
					const base = qsTr("Storage");
					if (!storageGaugeCard.currentDisk)
						return base;

					return `${base} - ${storageGaugeCard.currentDisk.mount}`;
				}

				// Scroll hint icon
				MaterialIcon {
					ToolTip.delay: 500
					ToolTip.text: qsTr("Scroll to switch disks")
					ToolTip.visible: hintHover.hovered
					color: DynamicColors.palette.m3onSurfaceVariant
					font.pointSize: Appearance.font.size.normal
					opacity: 0.7
					text: "unfold_more"
					visible: storageGaugeCard.diskCount > 1

					HoverHandler {
						id: hintHover
					}
				}
			}

			Item {
				Layout.fillHeight: true
				Layout.fillWidth: true

				ArcGauge {
					accentColor: storageGaugeCard.accentColor
					anchors.centerIn: parent
					height: width
					percentage: storageGaugeCard.animatedPercentage
					startAngle: storageGaugeCard.arcStartAngle
					sweepAngle: storageGaugeCard.arcSweep
					trackColor: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
					width: Math.min(parent.width, parent.height)
				}

				CustomText {
					anchors.centerIn: parent
					color: storageGaugeCard.accentColor
					font.pointSize: Appearance.font.size.extraLarge
					font.weight: Font.Medium
					text: storageGaugeCard.currentDisk ? `${Math.round(storageGaugeCard.currentDisk.perc * 100)}%` : "—"
				}
			}

			CustomText {
				Layout.alignment: Qt.AlignHCenter
				color: DynamicColors.palette.m3onSurfaceVariant
				font.pointSize: Appearance.font.size.smaller
				text: {
					if (!storageGaugeCard.currentDisk)
						return "—";

					const usedFmt = SystemUsage.formatKib(storageGaugeCard.currentDisk.used);
					const totalFmt = SystemUsage.formatKib(storageGaugeCard.currentDisk.total);
					return `${usedFmt.value.toFixed(1)} / ${Math.floor(totalFmt.value)} ${totalFmt.unit}`;
				}
			}
		}
	}
}
