pragma ComponentBehavior: Bound

import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Llm
import ZShell.Config
import qs.Services
import qs.Components

Item {
	id: root

	property alias list: list
	property alias model: list.model
	property bool highlight: false
	property bool slim: false

	signal requestExpand
	signal deleteChatRequest(content: ChatSession)
	signal loadChatRequest(content: ChatSession, index: int)
	signal newChatRequest

	CustomText {
		id: header

		anchors.left: parent.left
		anchors.margins: Tokens.padding.extraSmall
		anchors.right: parent.right
		anchors.top: parent.top
		color: Colors.palette.m3outline
		font.family: "CaskaydiaCove NF"
		font.pointSize: 13
		font.weight: 500
		text: qsTr("%1 Chat%2").arg(list.count).arg(list.count > 1 ? "s" : "")
	}

	CustomListView {
		id: list

		anchors.bottom: modelsContainer.top
		anchors.left: parent.left
		anchors.right: parent.right
		anchors.top: header.bottom
		anchors.topMargin: Tokens.spacing.medium
		clip: true
		spacing: Tokens.spacing.medium

		add: Transition {
			Anim {
				from: list.width
				property: "x"
			}
		}
		remove: Transition {
			Anim {
				to: list.width
				property: "x"
			}

			Anim {
				to: 0
				property: "opacity"
			}
		}
		displaced: Transition {
			Anim {
				property: "y"
			}
		}
		move: Transition {
			Anim {
				property: "y"
			}
		}

		delegate: ChatDelegate {
			id: chat

			required property int index

			implicitWidth: ListView.view.width
			highlighted: root.highlight && ChatState.chatSession === modelData
			slim: root.slim

			onHighlightedChanged: if (highlighted)
				list.currentIndex = index
			onClicked: content => root.loadChatRequest(content, index)
			onRemove: content => root.deleteChatRequest(content)
		}

		TapHandler {
			onTapped: {
				root.focus = true;
				ChatState.fabExpanded = false;
				modelsContainer.expanded = false;
			}
		}
	}

	CustomClippingRect {
		id: modelsContainer

		property bool expanded: false

		anchors.bottom: parent.bottom
		anchors.left: parent.left
		anchors.right: fabRoot.left
		anchors.margins: Tokens.padding.small
		anchors.rightMargin: Tokens.spacing.small

		implicitHeight: expanded ? 400 : fabRoot.implicitHeight
		radius: modelLayer.pressed ? Tokens.rounding.small : modelName.implicitHeight / 2

		function prettyModelName(): string {
			if (modelsList.count < 1)
				return qsTr("No models found");

			const pathList = Chat.model.split("\/");
			const name = pathList[pathList.length - 1];

			if (!name)
				return qsTr("No model selected");

			return name;
		}

		Behavior on implicitHeight {
			Anim {}
		}

		Behavior on radius {
			Anim {}
		}

		Item {
			id: modelName
			anchors.left: parent.left
			anchors.right: parent.right
			anchors.top: parent.top
			implicitHeight: fabRoot.implicitHeight

			CustomText {
				id: label
				text: modelsContainer.prettyModelName()
				color: Colors.palette.m3onSurfaceVariant
				anchors.left: parent.left
				anchors.leftMargin: Tokens.padding.large
				anchors.verticalCenter: parent.verticalCenter
			}

			MaterialIcon {
				color: Colors.palette.m3onSurfaceVariant
				anchors.right: parent.right
				anchors.rightMargin: Tokens.padding.large
				anchors.verticalCenter: parent.verticalCenter
				text: modelsContainer.expanded ? "unfold_less" : "unfold_more"
				animate: true
				font.pointSize: Tokens.font.size.large
				visible: modelsList.count > 0
			}

			StateLayer {
				id: modelLayer
				enabled: modelsList.count > 0

				onClicked: {
					ChatState.fabExpanded = false;
					modelsContainer.expanded = !modelsContainer.expanded;
				}
				radius: modelsContainer.radius
			}
		}

		VerticalFadeListView {
			id: modelsList

			anchors.left: parent.left
			anchors.right: parent.right
			anchors.bottom: parent.bottom
			anchors.top: modelName.bottom
			anchors.margins: Tokens.padding.medium
			anchors.topMargin: Tokens.spacing.medium
			model: Chat.availableModels
			opacity: modelsContainer.expanded ? 1 : 0
			currentIndex: Chat.availableModels.indexOf(Chat.model)
			visible: opacity > 0

			Behavior on opacity {
				Anim {}
			}

			CustomScrollBar.vertical: CustomScrollBar {
				flickable: modelsList
			}

			delegate: CustomRect {
				id: model

				required property var modelData
				required property int index
				readonly property bool selected: model.ListView.view.currentIndex === model.index

				implicitWidth: ListView.view.width
				implicitHeight: layout.implicitHeight + Tokens.padding.small * 2
				radius: stateLayer.pressed ? Tokens.rounding.extraSmall : selected ? Tokens.rounding.largeIncreased : Tokens.rounding.medium
				color: Qt.alpha(Colors.palette.m3tertiaryContainer, selected ? 1 : 0)

				Behavior on radius {
					Anim {
						type: Anim.SlowEffects
					}
				}

				RowLayout {
					id: layout

					anchors.fill: parent
					anchors.margins: Tokens.padding.small
					anchors.leftMargin: Tokens.padding.large
					anchors.rightMargin: Tokens.padding.large

					CustomText {
						text: model.modelData
						color: model.selected ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface
					}

					MaterialIcon {
						Layout.alignment: Qt.AlignRight
						visible: model.selected
						color: Colors.palette.m3onTertiaryContainer
						font.pointSize: Tokens.font.size.normal
						opacity: model.selected ? 1 : 0
						text: "check"

						Behavior on opacity {
							Anim {
								type: Anim.SlowEffects
							}
						}
					}
				}

				StateLayer {
					id: stateLayer

					onClicked: {
						Chat.selectModel(model.modelData);
					}
				}
			}
		}
	}

	IconButton {
		id: fabRoot

		anchors.bottom: parent.bottom
		anchors.right: parent.right
		anchors.margins: Tokens.padding.small
		padding: 8
		font.pointSize: Math.round(18 * 1.2)
		icon: root.slim ? "left_panel_open" : "add"
		isRound: ChatState.fabExpanded
		// opacity: root.slim ? 0 : 1
		// visible: opacity > 0
		//
		// Behavior on opacity {
		// 	Anim {
		// 		type: Anim.DefaultEffects
		// 	}
		// }

		label.transform: Rotation {
			origin.y: fabRoot.label.height / 2
			origin.x: fabRoot.label.width / 2
			angle: ChatState.fabExpanded ? 135 : 0

			Behavior on angle {
				Anim {}
			}
		}

		onClicked: {
			if (root.slim && !ChatState.narrowSidebarExpanded) {
				root.requestExpand();
				return;
			}

			modelsContainer.expanded = false;
			ChatState.fabExpanded = !ChatState.fabExpanded;
		}

		Elevation {
			anchors.fill: parent
			level: fabRoot.stateLayer.containsMouse ? 4 : 3
			radius: parent.radius
			z: -1
		}
	}

	ColumnLayout {
		id: fabMenu

		anchors.bottom: fabRoot.top
		anchors.right: fabRoot.right
		anchors.bottomMargin: Tokens.padding.medium

		Repeater {
			id: fabRep

			model: ListModel {
				ListElement {
					name: "new chat"
					icon: "add"
				}
				ListElement {
					name: "pop out in window"
					icon: "open_in_new"
				}
			}

			CustomClippingRect {
				id: fabMenuItem

				required property var modelData
				required property int index

				Layout.alignment: Qt.AlignRight
				implicitHeight: fabMenuItemInner.implicitHeight + Tokens.padding.medium * 2

				radius: sLayer.pressed ? Tokens.rounding.small : implicitHeight / 2
				color: Colors.palette.m3primaryContainer
				visible: !(modelData.name === "pop out in window" && ChatState.isWindow)

				Behavior on radius {
					Anim {
						type: Anim.DefaultEffects
					}
				}

				opacity: 0

				states: State {
					name: "visible"
					when: ChatState.fabExpanded

					PropertyChanges {
						fabMenuItem.implicitWidth: fabMenuItemInner.implicitWidth + Tokens.padding.large * 2
						fabMenuItem.opacity: 1
						fabMenuItemInner.opacity: 1
					}
				}

				transitions: [
					Transition {
						to: "visible"

						SequentialAnimation {
							PauseAnimation {
								duration: (fabRep.count - 1 - fabMenuItem.index) * 50
							}
							ParallelAnimation {
								Anim {
									property: "implicitWidth"
									type: Anim.FastSpatial
								}
								Anim {
									property: "opacity"
									duration: Tokens.anim.durations.small
									easing: Tokens.anim.standard
								}
							}
						}
					},
					Transition {
						from: "visible"

						SequentialAnimation {
							PauseAnimation {
								duration: fabMenuItem.index * Tokens.anim.durations.small / 8
							}
							ParallelAnimation {
								Anim {
									property: "implicitWidth"
									type: Anim.FastSpatial
								}
								Anim {
									property: "opacity"
									duration: Tokens.anim.durations.small
									easing: Tokens.anim.standard
								}
							}
						}
					}
				]

				RowLayout {
					id: fabMenuItemInner

					anchors.centerIn: parent
					spacing: Tokens.spacing.medium
					opacity: 0

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

					CustomText {
						animate: true
						text: fabMenuItem.modelData.name
						font.capitalization: Font.Capitalize
						color: Colors.palette.m3onPrimaryContainer
						Layout.preferredWidth: implicitWidth

						Behavior on Layout.preferredWidth {
							Anim {}
						}
					}
				}

				StateLayer {
					id: sLayer
					onClicked: {
						const name = fabMenuItem.modelData.name;

						if (name === "new chat")
							root.newChatRequest();
						else if (name === "pop out in window")
							Detach.create();

						ChatState.fabExpanded = false;
					}
				}
			}
		}
	}
}
