import Quickshell
import QtQuick
import qs.Components
import ZShell.Config
import qs.Helpers
import qs.Modules.Bar.Popouts

Item {
	id: root

	required property Item bar
	required property real borderThickness
	property bool dashboardShortcutActive
	required property Drawing drawing
	required property EdgeGeometry geometry
	property bool osdShortcutActive
	required property Panels panels
	required property Wrapper popouts
	required property ShellScreen screen
	property bool singleGestureTriggered: false
	property bool utilitiesShortcutActive
	required property PersistentProperties visibilities

	function inBottomPanel(panel: Item, x: real, y: real): bool {
		const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
		return y > root.height - (panelHeight + geometry.insetBottom(borderThickness)) && withinPanelWidth(panel, x, y);
	}

	function inLeftPanel(panel: Item, x: real, y: real): bool {
		return x < panel.x + panel.width + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
	}

	function inPopoutArea(x: real, y: real): bool {
		const panel = panels.popoutsWrapper;
		if (!geometry.horizontal)
			return inLeftPanel(panel, x, y);
		return withinPanelWidth(panel, x, y) && withinPanelHeight(panel, x, y);
	}

	function inRightPanel(panel: Item, x: real, y: real): bool {
		return x > panel.x + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
	}

	function inTopPanel(panel: Item, x: real, y: real): bool {
		const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
		return y < geometry.insetTop(borderThickness) + panelHeight && withinPanelWidth(panel, x, y);
	}

	function withinPanelHeight(panel: Item, x: real, y: real): bool {
		const panelY = panel.y + geometry.insetTop(borderThickness);
		return y >= panelY && y <= panelY + panel.height;
	}

	function withinPanelWidth(panel: Item, x: real, y: real): bool {
		const panelX = panel.x + geometry.insetLeft(borderThickness);
		return x >= panelX && x <= panelX + panel.width;
	}

	anchors.fill: parent

	DragHandler {
		id: singleHandler

		cursorShape: (active && centroid.pressPosition.y < root.bar.implicitHeight) ? Qt.ClosedHandCursor : undefined
		dragThreshold: 0
		enabled: !root.visibilities.isDrawing
		grabPermissions: PointerHandler.CanTakeOverFromHandlersOfSameType | PointerHandler.ApprovesTakeOverByAnything
		maximumPointCount: 1
		minimumPointCount: 1
		target: null

		onActiveChanged: {
			if (!active)
				root.singleGestureTriggered = false;
		}
		onCentroidChanged: {
			const x = centroid.position.x;
			const y = centroid.position.y;
			const dragX = x - centroid.pressPosition.x;
			const dragY = y - centroid.pressPosition.y;

			if (centroid.pressPosition.y >= root.screen.height - Config.bar.border && centroid.pressPosition.x > root.screen.width / 5 && dragY < -Config.launcher.dragThreshold)
				root.visibilities.launcher = true;

			if (root.singleGestureTriggered)
				return;

			if (root.geometry.insetTop(root.borderThickness) > centroid.pressPosition.y) {
				if (dragY > 20) {
					root.visibilities.settings = true;
					root.singleGestureTriggered = true;
				} else if (dragY < -20) {
					root.visibilities.settings = false;
					root.singleGestureTriggered = true;
				}
			}

			if (centroid.pressPosition.y > root.screen.height - root.geometry.insetBottom(root.borderThickness) && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50)
				root.visibilities.clipboard = true;

			if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.geometry.insetTop(root.borderThickness) && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher)
				if (dragY < -10) {
					root.visibilities.dock = true;
					root.singleGestureTriggered = true;
				}

			if (centroid.pressPosition.x > root.screen.width - Config.bar.border && centroid.pressPosition.y < (root.screen.height / 2) && dragX < -Config.sidebar.dragThreshold) {
				root.visibilities.sidebar = true;
				root.singleGestureTriggered = true;
			}

			if (centroid.pressPosition.x >= root.screen.width - Config.bar.border && centroid.pressPosition.y > (root.screen.height / 2) && dragX < -20) {
				Hypr.dispatch(`hl.dsp.focus({ workspace = 'r+1', on_current_monitor = true })`);
				root.singleGestureTriggered = true;
			}

			if (centroid.pressPosition.x <= Config.bar.border && dragX > 20) {
				Hypr.dispatch(`hl.dsp.focus({ workspace = 'r-1', on_current_monitor = true })`);
				root.singleGestureTriggered = true;
			}
		}
	}

	PointHandler {
		id: drawingHandler

		property bool setInitialPoint: false

		acceptedButtons: Qt.LeftButton | Qt.RightButton
		enabled: root.visibilities.isDrawing && (!root.inLeftPanel(root.panels.drawing, hoverHandler.point.position.x, hoverHandler.point.position.y) || !root.panels.drawing.expanded)

		onActiveChanged: {
			if (!active) {
				setInitialPoint = false;
				root.drawing.content.endStroke();
			} else {
				root.panels.drawing.collapse();
			}
		}
		onPointChanged: {
			if (!active)
				return;
			const x = point.position.x;
			const y = point.position.y;
			const origX = point.pressPosition.x;
			const origY = point.pressPosition.y;

			if (point.pressedButtons & Qt.RightButton) {
				root.drawing.content.clear();
				return;
			}
			if (x === 0 && y === 0 && origX === 0 && origY === 0)
				return;

			if (!setInitialPoint) {
				setInitialPoint = true;
				root.drawing.content.beginStroke(origX, origY);
				return;
			}

			root.drawing.content.appendPoint(x, y);
		}
	}

	Timer {
		id: unhideTimer

		interval: Config.bar.revealDelay
		repeat: false
		running: false

		onTriggered: {
			if (hoverHandler.hovered)
				root.bar.isHovered = true;
		}
	}

	HoverHandler {
		id: hoverHandler

		cursorShape: root.visibilities.isDrawing && !root.inLeftPanel(root.panels.drawing, point.position.x, point.position.y) ? Qt.BlankCursor : undefined

		onHoveredChanged: {
			if (!hovered) {
				if (!root.osdShortcutActive) {
					root.visibilities.osd = false;
					root.panels.osd.hovered = false;
				}

				if (!root.popouts.currentName.startsWith("traymenu") || Config.bar.tray.showOnHover) {
					root.popouts.hasCurrent = false;
				}

				if (Config.bar.autoHide || root.bar.fullscreen)
					root.bar.isHovered = false;
			}
		}
		onPointChanged: {
			const x = point.position.x;
			const y = point.position.y;

			if (root.visibilities.isDrawing) {
				if (root.inLeftPanel(root.panels.drawing, x, y) && !(drawingHandler.point.pressedButtons & Qt.LeftButton)) {
					root.panels.drawing.expand();
					root.drawing.content.hideHover();
					return;
				}

				root.drawing.content.showHover(x, y);
				return;
			}

			if (!root.visibilities.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true))
				root.bar.isHovered = true;

			if (root.bar.fullscreen && !root.bar.isHovered)
				unhideTimer.start();

			if (root.panels.sidebar.offsetScale === 1) {
				const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y);

				if (showOsd) {
					root.osdShortcutActive = false;
					root.panels.osd.hovered = true;
				}
			} else {
				const outOfSidebar = x < root.width - root.panels.sidebar.width * (1 - root.panels.sidebar.offsetScale);
				const showOsd = outOfSidebar && root.inRightPanel(root.panels.osdWrapper, x, y);

				if (!root.osdShortcutActive) {
					root.visibilities.osd = showOsd;
					root.panels.osd.hovered = showOsd;
				} else if (showOsd) {
					root.osdShortcutActive = false;
					root.panels.osd.hovered = true;
				}
			}

			if (Config.dock.enable && Config.dock.hoverToReveal && !root.visibilities.dock && !root.visibilities.launcher && root.inBottomPanel(root.panels.dock, x, y))
				root.visibilities.dock = true;

			if (root.geometry.barContains(x, y))
				root.bar.checkPopout(root.geometry.axisPos(x, y));
		}
	}

	Connections {
		function onDashboardChanged() {
			if (root.visibilities.dashboard) {
				const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
				if (!inDashboardArea) {
					root.dashboardShortcutActive = true;
				}
				if (root.panels.launcher.x + root.panels.launcher.width > root.panels.dashboardWrapper.x)
					root.visibilities.launcher = false;

				root.visibilities.settings = false;
				root.visibilities.sidebar = false;
				root.popouts.hasCurrent = false;
			} else {
				root.dashboardShortcutActive = false;
			}
		}

		function onIsDrawingChanged() {
			if (!root.visibilities.isDrawing)
				root.drawing.clear();
		}

		function onLauncherChanged() {
			if (!root.visibilities.launcher) {
				root.dashboardShortcutActive = false;
				root.osdShortcutActive = false;
				root.utilitiesShortcutActive = false;

				const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);

				if (!inOsdArea) {
					root.visibilities.osd = false;
					root.panels.osd.hovered = false;
				}
			}

			if (root.visibilities.launcher) {
				if (root.panels.dashboardWrapper.x < root.panels.launcher.x + root.panels.launcher.width) {
					root.visibilities.dashboard = false;
				}

				root.visibilities.dock = false;
				root.visibilities.settings = false;
			}
		}

		function onOsdChanged() {
			if (root.visibilities.osd) {
				const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
				if (!inOsdArea) {
					root.osdShortcutActive = true;
				}
			} else {
				root.osdShortcutActive = false;
			}
		}

		function onResourcesChanged() {
			if (root.visibilities.resources && (root.popouts.currentName.startsWith("audio") || root.popouts.currentName.startsWith("updates"))) {
				root.popouts.hasCurrent = false;
			}

			if (root.visibilities.resources)
				root.visibilities.settings = false;
		}

		function onSettingsChanged() {
			if (root.visibilities.settings) {
				root.visibilities.resources = false;
				root.visibilities.dashboard = false;
				root.visibilities.sidebar = false;
				root.panels.popouts.hasCurrent = false;
				root.visibilities.launcher = false;
			}
		}

		function onSidebarChanged() {
			if (root.visibilities.sidebar) {
				root.visibilities.dashboard = false;
				root.visibilities.settings = false;
				root.popouts.hasCurrent = false;
			}
		}

		target: root.visibilities
	}
}
