pragma ComponentBehavior: Bound

import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Notifications
import ZShell.Config
import qs.Components
import qs.Services
import qs.Helpers
import qs.Daemons

CustomRect {
	id: root

	readonly property list<var> activeNotifs: notifs.filter(n => !n.closed)
	readonly property string appIcon: activeNotifs.find(n => n.appIcon.length > 0)?.appIcon ?? ""
	required property Flickable container
	readonly property bool expanded: props.expandedNotifs.includes(modelData)
	readonly property string image: activeNotifs.find(n => n.image.length > 0)?.image ?? ""
	required property string modelData
	readonly property int nonAnimHeight: {
		const headerHeight = header.implicitHeight + (root.expanded ? Math.round(Tokens.spacing.extraSmall) : 0);
		const columnHeight = headerHeight + notifList.layoutHeight;
		return Math.round(Math.max(Config.notifs.sizes.image, columnHeight) + Tokens.padding.small * 2);
	}
	readonly property int notifCount: activeNotifs.length
	readonly property list<var> notifs: NotifServer.list.filter(n => n.appName === modelData)
	required property Props props
	readonly property int urgency: {
		if (activeNotifs.find(n => n.urgency === NotificationUrgency.Critical))
			return NotificationUrgency.Critical;
		if (activeNotifs.find(n => n.urgency === NotificationUrgency.Normal))
			return NotificationUrgency.Normal;
		return NotificationUrgency.Low;
	}
	required property PersistentProperties visibilities

	function toggleExpand(expand: bool): void {
		if (expand) {
			if (!expanded)
				props.expandedNotifs.push(modelData);
		} else if (expanded) {
			props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1);
		}
	}

	anchors.left: parent?.left
	anchors.right: parent?.right
	clip: true
	color: Colors.layer(Colors.palette.m3surfaceContainer, 2)
	implicitHeight: nonAnimHeight
	radius: Tokens.rounding.large

	Behavior on implicitHeight {
		Anim {
		}
	}

	Component.onDestruction: {
		if (notifCount === 0 && expanded)
			props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1);
	}

	RowLayout {
		id: content

		anchors.left: parent.left
		anchors.margins: Tokens.padding.small
		anchors.right: parent.right
		anchors.top: parent.top
		spacing: Tokens.spacing.medium

		Item {
			Layout.alignment: Qt.AlignLeft | Qt.AlignTop
			implicitHeight: Config.notifs.sizes.image
			implicitWidth: Config.notifs.sizes.image

			Component {
				id: imageComp

				Image {
					asynchronous: true
					cache: false
					fillMode: Image.PreserveAspectCrop
					height: Config.notifs.sizes.image
					source: Qt.resolvedUrl(root.image)
					sourceSize: {
						const size = Config.notifs.sizes.image * ((QsWindow.window as QsWindow)?.devicePixelRatio ?? 1);
						return Qt.size(size, size);
					}
					width: Config.notifs.sizes.image
				}
			}

			Component {
				id: appIconComp

				ColoredIcon {
					color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3onError : root.urgency === NotificationUrgency.Low ? Colors.palette.m3onSurface : Colors.palette.m3onSecondaryContainer
					implicitSize: Math.round(Config.notifs.sizes.image * 0.6)
					layer.enabled: root.appIcon.endsWith("symbolic")
					source: Quickshell.iconPath(root.appIcon)
				}
			}

			Component {
				id: materialIconComp

				MaterialIcon {
					color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3onError : root.urgency === NotificationUrgency.Low ? Colors.palette.m3onSurface : Colors.palette.m3onSecondaryContainer
					text: Icons.getNotifIcon(root.activeNotifs[0]?.summary, root.urgency)
				}
			}

			CustomClippingRect {
				anchors.fill: parent
				color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3error : root.urgency === NotificationUrgency.Low ? Colors.layer(Colors.palette.m3surfaceContainerHigh, 3) : Colors.palette.m3secondaryContainer
				radius: Tokens.rounding.full

				Loader {
					anchors.centerIn: parent
					anchors.verticalCenterOffset: sourceComponent === materialIconComp ? 1 : 0
					asynchronous: true
					sourceComponent: root.image ? imageComp : root.appIcon ? appIconComp : materialIconComp
				}
			}

			Loader {
				active: root.appIcon && root.image
				anchors.bottom: parent.bottom
				anchors.right: parent.right
				asynchronous: true

				sourceComponent: CustomRect {
					color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3error : root.urgency === NotificationUrgency.Low ? Colors.palette.m3surfaceContainerHigh : Colors.palette.m3secondaryContainer
					implicitHeight: Config.notifs.sizes.badge
					implicitWidth: Config.notifs.sizes.badge
					radius: Tokens.rounding.full

					ColoredIcon {
						anchors.centerIn: parent
						color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3onError : root.urgency === NotificationUrgency.Low ? Colors.palette.m3onSurface : Colors.palette.m3onSecondaryContainer
						implicitSize: Math.round(Config.notifs.sizes.badge * 0.6)
						layer.enabled: root.appIcon.endsWith("symbolic")
						source: Quickshell.iconPath(root.appIcon)
					}
				}
			}
		}

		Column {
			id: column

			Layout.fillWidth: true
			spacing: root.expanded ? Math.round(Tokens.spacing.extraSmall) : 0

			Behavior on spacing {
				Anim {
				}
			}

			RowLayout {
				id: header

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

				CustomText {
					Layout.fillWidth: true
					color: Colors.palette.m3onSurfaceVariant
					elide: Text.ElideRight
					text: root.modelData
				}

				CustomText {
					animate: true
					color: Colors.palette.m3outline
					text: root.activeNotifs[0]?.timeStr ?? ""
				}

				CustomRect {
					color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3error : Colors.layer(Colors.palette.m3surfaceContainerHigh, 3)
					implicitHeight: groupCount.implicitHeight + Tokens.padding.extraSmall
					implicitWidth: expandBtn.implicitWidth + Tokens.padding.large
					radius: Tokens.rounding.full

					StateLayer {
						color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3onError : Colors.palette.m3onSurface

						onClicked: root.toggleExpand(!root.expanded)
					}

					RowLayout {
						id: expandBtn

						anchors.centerIn: parent
						spacing: Tokens.spacing.extraSmall

						CustomText {
							id: groupCount

							Layout.leftMargin: Tokens.padding.extraSmall / 2
							animate: true
							color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3onError : Colors.palette.m3onSurfaceVariant
							text: root.notifCount
						}

						MaterialIcon {
							Layout.rightMargin: -Tokens.padding.extraSmall / 2
							Layout.topMargin: root.expanded ? -Math.floor(Tokens.padding.extraSmall) : 0
							color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3onError : Colors.palette.m3onSurfaceVariant
							rotation: root.expanded ? 180 : 0
							text: "expand_more"

							Behavior on Layout.topMargin {
								Anim {
								}
							}
							Behavior on rotation {
								Anim {
								}
							}
						}
					}
				}
			}

			NotifGroupList {
				id: notifList

				container: root.container
				expanded: root.expanded
				notifs: root.notifs
				props: root.props
				visibilities: root.visibilities

				onRequestToggleExpand: expand => root.toggleExpand(expand)
			}
		}
	}
}
