pragma ComponentBehavior: Bound

import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Components
import ZShell.Config
import qs.Modules.Settings
import qs.Services

VerticalFadeFlickable {
	id: root

	readonly property var groups: {
		const out = [];
		const byPage = ({});
		for (const e of results) {
			const key = e.pageIdx;
			if (byPage[key] === undefined) {
				byPage[key] = {
					"pageIdx": e.pageIdx,
					"page": e.crumbLabels[0],
					"icon": e.crumbIcons[0],
					"entries": []
				};
				out.push(byPage[key]);
			}
			byPage[key].entries.push(e);
		}
		return out;
	}
	readonly property var results: {
		if (!searching)
			return [];
		const all = SettingsSearcher.query(search);
		return all;
	}
	required property SettingsState sState
	readonly property string search: sState.searchText
	readonly property bool searching: search.length > 0

	bottomMargin: Tokens.padding.large
	contentHeight: content.implicitHeight
	fadeAmount: 0.1
	topMargin: Tokens.padding.large

	TapHandler {
		onTapped: root.focus = true
	}

	ColumnLayout {
		id: content

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

		Repeater {
			id: list

			model: root.searching ? [] : PageRegistry.pages

			CustomRect {
				id: item

				required property int index
				readonly property bool isCategoryEnd: index === list.model.length - 1 || PageRegistry.pages[index + 1]?.category !== modelData.category
				readonly property bool isCategoryStart: index === 0 || PageRegistry.pages[index - 1]?.category !== modelData.category
				readonly property bool isCurrentPage: index === root.sState.currentPageIdx
				required property var modelData

				Layout.fillWidth: true
				Layout.topMargin: index !== 0 && isCategoryStart ? Tokens.spacing.small : 0
				bottomLeftRadius: stateLayer.pressed ? Tokens.rounding.medium : isCurrentPage ? Tokens.rounding.extraLarge : isCategoryEnd ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
				bottomRightRadius: stateLayer.pressed ? Tokens.rounding.medium : isCurrentPage ? Tokens.rounding.extraLarge : isCategoryEnd ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
				color: isCurrentPage ? Colors.palette.m3secondaryContainer : Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
				implicitHeight: {
					const h = layout.implicitHeight + layout.anchors.margins * 2;
					return h % 2 === 0 ? h : h + 1;
				}
				topLeftRadius: stateLayer.pressed ? Tokens.rounding.medium : isCurrentPage ? Tokens.rounding.extraLarge : isCategoryStart ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
				topRightRadius: stateLayer.pressed ? Tokens.rounding.medium : isCurrentPage ? Tokens.rounding.extraLarge : isCategoryStart ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall

				RadiusBehavior on bottomLeftRadius {}
				RadiusBehavior on bottomRightRadius {}
				RadiusBehavior on topLeftRadius {}
				RadiusBehavior on topRightRadius {}

				StateLayer {
					id: stateLayer

					anchors.fill: parent
					bottomLeftRadius: parent.bottomLeftRadius
					bottomRightRadius: parent.bottomRightRadius
					topLeftRadius: parent.topLeftRadius
					topRightRadius: parent.topRightRadius

					onClicked: root.sState.currentPageIdx = item.index
				}

				RowLayout {
					id: layout

					anchors.fill: parent
					anchors.margins: Tokens.padding.large
					spacing: Tokens.spacing.small

					CustomRect {
						Layout.bottomMargin: -1
						Layout.fillHeight: true
						Layout.topMargin: -1
						color: item.isCurrentPage ? Colors.palette.m3primary : Colors.palette.m3secondaryContainer
						implicitWidth: height
						radius: Tokens.rounding.full

						MaterialIcon {
							anchors.centerIn: parent
							anchors.verticalCenterOffset: 1
							color: item.isCurrentPage ? Colors.palette.m3onPrimary : Colors.palette.m3onSecondaryContainer
							fill: item.modelData.noFill ? 0 : 1
							font.pointSize: Tokens.font.size.large
							grade: 25
							text: item.modelData.icon
						}
					}

					ColumnLayout {
						Layout.fillWidth: true
						spacing: 0

						CustomText {
							Layout.fillWidth: true
							elide: Text.ElideRight
							text: item.modelData.name
						}

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

		Column {
			id: resultList

			Layout.fillWidth: true
			spacing: Tokens.padding.large

			add: Transition {
				Anim {
					from: 0
					property: "opacity"
					to: 1
					type: Anim.DefaultEffects
				}
			}
			move: Transition {
				Anim {
					properties: "x,y"
				}

				Anim {
					property: "opacity"
					to: 1
					type: Anim.DefaultEffects
				}
			}

			Repeater {
				model: ScriptModel {
					objectProp: "pageIdx"
					values: root.groups
				}

				ColumnLayout {
					id: group

					required property int index
					required property var modelData

					spacing: Tokens.spacing.small
					width: resultList.width

					RowLayout {
						Layout.fillWidth: true
						Layout.leftMargin: Tokens.padding.extraSmall
						spacing: Tokens.spacing.small

						MaterialIcon {
							color: Colors.palette.m3primary
							fill: 1
							font.pointSize: Tokens.font.size.large
							text: group.modelData.icon
						}

						CustomText {
							Layout.fillWidth: true
							color: Colors.palette.m3secondary
							elide: Text.ElideRight
							font.pointSize: Tokens.font.size.large
							text: group.modelData.page
						}
					}

					Column {
						id: cardList

						Layout.fillWidth: true
						spacing: Tokens.spacing.extraSmall / 2

						add: Transition {
							Anim {
								from: 0
								property: "opacity"
								to: 1
								type: Anim.DefaultEffects
							}
						}
						move: Transition {
							Anim {
								properties: "x,y"
							}

							Anim {
								property: "opacity"
								to: 1
								type: Anim.DefaultEffects
							}
						}

						Repeater {
							model: ScriptModel {
								objectProp: "anchor"
								values: group.modelData.entries
							}

							CustomRect {
								id: result

								required property int index
								readonly property bool isFirst: index === 0
								readonly property bool isLast: index === group.modelData.entries.length - 1
								required property var modelData

								bottomLeftRadius: layer.pressed ? Tokens.rounding.largeIncreased : isLast ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
								bottomRightRadius: layer.pressed ? Tokens.rounding.largeIncreased : isLast ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
								color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
								implicitHeight: {
									const h = resultLayout.implicitHeight + resultLayout.anchors.margins * 2;
									return h % 2 === 0 ? h : h + 1;
								}
								topLeftRadius: layer.pressed ? Tokens.rounding.largeIncreased : isFirst ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
								topRightRadius: layer.pressed ? Tokens.rounding.largeIncreased : isFirst ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
								width: cardList.width

								RadiusBehavior on bottomLeftRadius {}
								RadiusBehavior on bottomRightRadius {}
								RadiusBehavior on topLeftRadius {}
								RadiusBehavior on topRightRadius {}

								ColumnLayout {
									id: resultLayout

									anchors.fill: parent
									anchors.margins: Tokens.padding.large
									anchors.rightMargin: result.modelData.togglePath ? toggle.width + Tokens.padding.large * 2 : Tokens.padding.large
									spacing: Tokens.spacing.small / 2

									CustomText {
										Layout.fillWidth: true
										color: Colors.palette.m3onSurfaceVariant
										elide: Text.ElideRight
										font.pointSize: Tokens.font.size.small
										text: {
											const labels = result.modelData.crumbLabels.slice(1);
											const section = result.modelData.section;
											const parts = section && section !== labels[labels.length - 1] ? labels.concat(section) : labels;
											return parts.join("  \u203a  ");
										}
										visible: text.length > 0
									}

									CustomText {
										Layout.fillWidth: true
										color: Colors.palette.m3onSurface
										elide: Text.ElideRight
										font.pointSize: Tokens.font.size.normal
										text: SettingsSearcher.highlight(result.modelData.title, root.search, Colors.palette.m3primary)
										textFormat: text.includes("<font") ? Text.StyledText : Text.PlainText
									}

									CustomText {
										Layout.fillWidth: true
										color: Colors.palette.m3outline
										elide: Text.ElideRight
										font.pointSize: Tokens.font.size.small
										text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colors.palette.m3primary)
										textFormat: text.includes("<font") ? Text.StyledText : Text.PlainText
										visible: result.modelData.subtext.length > 0
									}
								}

								StateLayer {
									id: layer

									z: 1

								onClicked: {
									const target = result.modelData.targetSubPath;
									root.sState.jumpToSetting(result.modelData.pageIdx, target.length > 0 ? target : result.modelData.subPath, target.length > 0 ? "" : result.modelData.anchor);
								}
								}

								CustomSwitch {
									id: toggle

									anchors.right: parent.right
									anchors.rightMargin: Tokens.padding.large
									anchors.verticalCenter: parent.verticalCenter
									cLayer: 3
									checked: result.modelData.toggleValue
									scale: 0.85
									transformOrigin: Item.Right
									visible: result.modelData.togglePath
									z: 2

									onToggled: result.modelData.setToggle(checked)
								}
							}
						}
					}
				}
			}
		}

		CustomText {
			Layout.fillWidth: true
			Layout.topMargin: Tokens.padding.large
			color: Colors.palette.m3onSurfaceVariant
			font.pointSize: Tokens.font.size.normal
			horizontalAlignment: Text.AlignHCenter
			text: qsTr("No matching settings")
			visible: root.searching && root.results.length === 0
		}
	}

	component RadiusBehavior: Behavior {
		Anim {
			type: Anim.DefaultEffects
		}
	}
}
