pragma ComponentBehavior: Bound

import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import ZShell.Blobs
import qs.Daemons
import qs.Components
import qs.Modules.Bar
import ZShell.Config
import qs.Helpers
import qs.Drawers
import qs.Services

CustomWindow {
	id: root

	readonly property alias bar: bar
	readonly property real borderLayoutThickness: hasFullscreen ? 0 : Config.bar.border
	readonly property real borderRounding: Config.bar.rounding * (1 - fsTransitionProg)
	readonly property real borderThickness: Config.bar.border * (1 - fsTransitionProg)
	readonly property int dragMaskPadding: {
		if (focusGrab.active)
			return 0;

		if (monitor?.lastIpcObject.specialWorkspace?.name || monitor?.activeWorkspace?.lastIpcObject.windows > 0)
			return 0;

		return 100;
	}
	property real fsTransitionProg: hasFullscreen ? 1 : 0
	readonly property alias geometry: geometry
	readonly property bool hasFullscreen: {
		if (hasSpecialWorkspace) {
			const specialName = monitor?.lastIpcObject.specialWorkspace?.name;
			if (!specialName)
				return false;
			const specialWs = Hypr.workspaces.values.find(ws => ws.name === specialName);
			return specialWs?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1) ?? false;
		}
		return hasFullscreenOnNormalWs;
	}
	readonly property bool hasFullscreenOnNormalWs: monitor?.activeWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1) ?? false
	readonly property bool hasSpecialWorkspace: (monitor?.lastIpcObject.specialWorkspace?.name.length ?? 0) > 0
	readonly property alias interactionWrapper: interactions
	readonly property alias menuRegion: regions.menuPopoutRegion
	readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen)
	property var root: Quickshell.shellDir
	readonly property real sdfBorderOffset: 2 * fsTransitionProg
	readonly property real shadowOpacity: 0.7 * (1 - (bar.isHovered ? 0 : fsTransitionProg))
	property color surfaceColor: Colors.tPalette.m3surface

	WlrLayershell.exclusionMode: ExclusionMode.Ignore
	WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.settings || visibilities.sidebar ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
	WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top
	color: "transparent"
	contentItem.focus: true
	mask: visibilities.isDrawing ? null : (hasFullscreen && !bar.isHovered ? emptyRegion : regions)
	name: "Bar"

	Behavior on fsTransitionProg {
		Anim {}
	}
	Behavior on surfaceColor {
		CAnim {}
	}

	contentItem.Keys.onEscapePressed: {
		if (Config.bar.autoHide)
			visibilities.bar = false;
		visibilities.launcher = false;
		visibilities.sidebar = false;
		visibilities.dashboard = false;
		visibilities.osd = false;
		visibilities.settings = false;
		visibilities.resources = false;
		visibilities.dock = false;
		visibilities.clipboard = false;
		panels.popouts.hasCurrent = false;
	}
	onHasFullscreenChanged: {
		visibilities.launcher = false;
		visibilities.sidebar = false;
		visibilities.dashboard = false;
		visibilities.osd = false;
		visibilities.settings = false;
		visibilities.resources = false;
		visibilities.clipboard = false;
		visibilities.dock = false;
		panels.popouts.hasCurrent = false;
	}

	EdgeGeometry {
		id: geometry

		bar: bar
		configPosition: Config.bar.position
		win: root
	}

	Region {
		id: emptyRegion

		height: panels.notifications.height
		width: panels.notifications.width
		x: panels.notifications.x + geometry.insetLeft(root.borderThickness)
		y: panels.notifications.y + geometry.insetTop(root.borderThickness)

		Region {
			height: panels.osd.height
			width: panels.osdWrapper.width * (1 - panels.osd.offsetScale) + root.borderThickness
			x: root.width - width
			y: panels.osdWrapper.y + bar.implicitHeight
		}

		Region {
			height: geometry.horizontal ? 1 : root.screen.height
			width: geometry.horizontal ? root.screen.width : 1
			y: geometry.position === "bottom" ? root.screen.height - 1 : 0
		}
	}

	Regions {
		id: regions

		geometry: geometry
		panels: panels
		win: root
	}

	anchors {
		bottom: true
		left: true
		right: true
		top: true
	}

	HyprlandFocusGrab {
		id: focusGrab

		active: visibilities.dock || visibilities.resources || visibilities.launcher || visibilities.sidebar || visibilities.dashboard || visibilities.settings || visibilities.clipboard || (panels.popouts.hasCurrent && panels.popouts.currentName.startsWith("traymenu") && (!Config.bar.tray.showOnHover || (panels.popouts.current as StackView)?.depth > 1))
		windows: [root]

		onCleared: {
			visibilities.launcher = false;
			visibilities.sidebar = false;
			visibilities.dashboard = false;
			visibilities.osd = false;
			visibilities.settings = false;
			visibilities.resources = false;
			visibilities.clipboard = false;
			visibilities.dock = false;
			panels.popouts.hasCurrent = false;
		}
	}

	PersistentProperties {
		id: visibilities

		property bool bar
		property bool clipboard
		property bool dashboard
		property bool dock
		property bool isDrawing
		property bool launcher
		property bool notif: NotifServer.popups.length > 0
		property bool osd
		property bool resources
		property bool settings
		property bool sidebar

		Component.onCompleted: Visibilities.load(root.screen, this)
	}

	Binding {
		property: "bar"
		target: visibilities
		value: visibilities.sidebar || visibilities.dashboard || visibilities.osd || (!Config.bar.hideWhenNotif && visibilities.notif) || visibilities.resources || visibilities.settings || bar.isHovered
		when: Config.bar.autoHide
	}

	Item {
		id: surface

		anchors.fill: parent
		layer.enabled: true
		opacity: root.surfaceColor.a

		layer.effect: MultiEffect {
			blurMax: 32
			shadowColor: Qt.alpha(Colors.palette.m3shadow, Math.max(0, root.shadowOpacity))
			shadowEnabled: true
		}

		BlobGroup {
			id: blobGroup

			color: root.surfaceColor
			smoothing: Config.bar.smoothing
		}

		BlobInvertedRect {
			anchors.fill: parent
			anchors.margins: -50
			borderBottom: geometry.insetBottom(root.borderThickness) - anchors.margins - root.sdfBorderOffset
			borderLeft: geometry.insetLeft(root.borderThickness) - anchors.margins - root.sdfBorderOffset
			borderRight: root.borderThickness - anchors.margins - root.sdfBorderOffset
			borderTop: geometry.insetTop(root.borderThickness) - anchors.margins - root.sdfBorderOffset
			group: blobGroup
			radius: root.borderRounding
		}

		PanelBg {
			id: dashBg

			property real extraExtent: 0.2

			deformAmount: 0.06
			implicitHeight: panels.dashboard.height * (geometry.horizontal ? 1 + extraExtent : 1)
			implicitWidth: panels.dashboard.width * (geometry.horizontal ? 1 : 1 + extraExtent)
			panel: panels.dashboardWrapper
			radius: Tokens.rounding.extraLarge
			x: panels.dashboardWrapper.x + panels.dashboard.x + geometry.insetLeft(root.borderThickness) - (geometry.horizontal ? 0 : panels.dashboard.width * extraExtent)
			y: panels.dashboardWrapper.y + panels.dashboard.y + geometry.insetTop(root.borderThickness) - (geometry.horizontal && geometry.position !== "bottom" ? panels.dashboard.height * extraExtent : 0)
		}

		PanelBg {
			id: launcherBg

			property real extraHeight: 0.2

			deformAmount: 0.06
			implicitHeight: panels.launcher.height * (1 + extraHeight)
			panel: panels.launcher
			radius: Tokens.rounding.medium + (Tokens.padding.largeIncreased / 4)
			y: panels.launcher.y + geometry.insetTop(root.borderThickness)
		}

		PanelBg {
			id: sidebarBg

			bottomLeftRadius: 0
			deformAmount: 0.04
			exclude: panels.sidebar.offsetScale > 0.08 ? [] : [utilsBg]
			implicitHeight: panel.height * (1 / rawDeformMatrix.m22) + 2
			panel: panels.sidebar
		}

		PanelBg {
			id: osdBg

			deformAmount: 0.1
			implicitHeight: panels.osd.height
			implicitWidth: panels.osd.width
			panel: panels.osdWrapper
			radius: 20
			x: panels.osdWrapper.x + panels.osd.x + geometry.insetLeft(root.borderThickness)
		}

		PanelBg {
			id: notifsBg

			panel: panels.notifications
			radius: Tokens.rounding.large
		}

		PanelBg {
			id: utilsBg

			deformAmount: 0.1
			exclude: panels.sidebar.offsetScale > 0.08 ? [] : [sidebarBg]
			panel: panels.utilities
			topLeftRadius: 0
		}

		PanelBg {
			id: popoutBg

			property real extraExtent: 0.2

			deformAmount: panels.popouts.currentName.startsWith("traymenu") ? 0.15 : 0.08
			implicitHeight: panels.popouts.height * (geometry.horizontal ? 1 + extraExtent : 1)
			implicitWidth: panels.popouts.width * (geometry.horizontal ? 1 : 1 + extraExtent)
			panel: panels.popoutsWrapper
			radius: panels.popouts.current?.panelRadius ?? Tokens.rounding.large
			x: panels.popoutsWrapper.x + panels.popouts.x + geometry.insetLeft(root.borderThickness) - (geometry.horizontal ? 0 : panels.popouts.width * extraExtent)
			y: panels.popoutsWrapper.y + panels.popouts.y + geometry.insetTop(root.borderThickness) - (geometry.barOnTop ? panels.popouts.height * extraExtent : 0)

			Behavior on extraExtent {
				Anim {}
			}
		}

		PanelBg {
			id: resourcesBg

			deformAmount: 0.05
			implicitHeight: panels.resources.height
			implicitWidth: panels.resources.width
			panel: panels.resourcesWrapper
			radius: Tokens.rounding.largeIncreased + Tokens.padding.small
			x: panels.resourcesWrapper.x + panels.resources.x + geometry.insetLeft(root.borderThickness)
			y: panels.resourcesWrapper.y + panels.resources.y + geometry.insetTop(root.borderThickness)
		}

		PanelBg {
			id: settingsBg

			deformAmount: 0.03
			panel: panels.settings
			radius: Tokens.rounding.largeIncreased + Tokens.padding.small
		}

		PanelBg {
			id: dockBg

			deformAmount: 0.08
			panel: panels.dock
			radius: Tokens.rounding.medium
		}

		PanelBg {
			id: drawingBg

			deformAmount: 0.08
			panel: panels.drawing
			radius: Tokens.rounding.medium
		}

		PanelBg {
			id: clipboardBg

			deformAmount: 0.03
			panel: panels.clipboard
			radius: 29
		}
	}

	Drawing {
		id: drawing

		anchors.fill: parent
		layer.enabled: true
		visibilities: visibilities
		z: 2

		layer.effect: MultiEffect {
			maskEnabled: true
			maskInverted: true
			maskSource: maskSource
		}
	}

	Item {
		id: maskSource

		anchors.fill: parent
		layer.enabled: true
		visible: false

		CustomRect {
			readonly property int extraWidth: radius

			color: "white"
			implicitHeight: panels.drawing.height
			implicitWidth: panels.drawing.width + extraWidth
			radius: drawingBg.radius
			x: -extraWidth + root.borderThickness + panels.drawing.x
			y: panels.drawing.y + bar.implicitHeight
		}
	}

	Interactions {
		id: interactions

		anchors.fill: parent
		bar: bar
		borderThickness: root.borderLayoutThickness
		drawing: drawing
		enabled: true
		geometry: geometry
		panels: panels
		popouts: panels.popouts
		screen: root.screen
		visibilities: visibilities

		Panels {
			id: panels

			bar: bar
			borderThickness: root.borderThickness
			drawingItem: drawing
			geometry: geometry
			screen: root.screen
			visibilities: visibilities

			clipboard.transform: Matrix4x4 {
				matrix: clipboardBg.deformMatrix
			}
			dashboard.transform: Matrix4x4 {
				matrix: dashBg.deformMatrix
			}
			dock.transform: Matrix4x4 {
				matrix: dockBg.deformMatrix
			}
			launcher.transform: Matrix4x4 {
				matrix: launcherBg.deformMatrix
			}
			notifications.transform: Matrix4x4 {
				matrix: notifsBg.deformMatrix
			}
			osd.transform: Matrix4x4 {
				matrix: osdBg.deformMatrix
			}
			popouts.transform: Matrix4x4 {
				matrix: popoutBg.deformMatrix
			}
			resources.transform: Matrix4x4 {
				matrix: resourcesBg.deformMatrix
			}
			settings.transform: Matrix4x4 {
				matrix: settingsBg.deformMatrix
			}
			sidebar.transform: Matrix4x4 {
				matrix: sidebarBg.deformMatrix
			}
			utilities.transform: Matrix4x4 {
				matrix: utilsBg.deformMatrix
			}
		}

		BarLoader {
			id: bar

			anchors.bottom: geometry.barOnBottom ? parent.bottom : undefined
			anchors.left: parent.left
			anchors.top: geometry.barOnBottom ? undefined : parent.top
			enabled: !visibilities.isDrawing
			fullscreen: root.hasFullscreen
			height: geometry.horizontal ? implicitHeight : parent.height
			popouts: panels.popouts
			popoutsWrapper: panels.popoutsWrapper
			position: geometry.position
			screen: root.screen
			visibilities: visibilities
			width: geometry.horizontal ? parent.width : implicitWidth
		}
	}

	component PanelBg: BlobRect {
		property real deformAmount: 0.15
		required property Item panel

		deformScale: (deformAmount * Config.appearance.deform.scale) / 10000
		group: blobGroup
		implicitHeight: panel.height
		implicitWidth: panel.width
		radius: Tokens.rounding.small
		x: panel.x + geometry.insetLeft(root.borderThickness)
		y: panel.y + geometry.insetTop(root.borderThickness)
	}
}
