import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import ZShell.Llm
import qs.Modules.Notifications.Sidebar.Chat.Content
import qs.Components
import qs.Services

Item {
	id: root

	property ChatSession chatData
	property bool following: true
	// qmlformat off
	readonly property var keys: [
		Qt.Key_A,
		Qt.Key_B,
		Qt.Key_C,
		Qt.Key_D,
		Qt.Key_E,
		Qt.Key_F,
		Qt.Key_G,
		Qt.Key_H,
		Qt.Key_I,
		Qt.Key_J,
		Qt.Key_K,
		Qt.Key_L,
		Qt.Key_M,
		Qt.Key_N,
		Qt.Key_O,
		Qt.Key_P,
		Qt.Key_Q,
		Qt.Key_R,
		Qt.Key_S,
		Qt.Key_T,
		Qt.Key_U,
		Qt.Key_V,
		Qt.Key_W,
		Qt.Key_X,
		Qt.Key_Y,
		Qt.Key_Z,

		Qt.Key_Agrave,
		Qt.Key_Aacute,
		Qt.Key_Acircumflex,
		Qt.Key_Atilde,
		Qt.Key_Adiaeresis,
		Qt.Key_Aring,
		Qt.Key_AE,

		Qt.Key_Ccedilla,

		Qt.Key_Egrave,
		Qt.Key_Eacute,
		Qt.Key_Ecircumflex,
		Qt.Key_Ediaeresis,

		Qt.Key_Igrave,
		Qt.Key_Iacute,
		Qt.Key_Icircumflex,
		Qt.Key_Idiaeresis,

		Qt.Key_ETH,

		Qt.Key_Ntilde,

		Qt.Key_Ograve,
		Qt.Key_Oacute,
		Qt.Key_Ocircumflex,
		Qt.Key_Otilde,
		Qt.Key_Odiaeresis,
		Qt.Key_Ooblique,

		Qt.Key_Ugrave,
		Qt.Key_Uacute,
		Qt.Key_Ucircumflex,
		Qt.Key_Udiaeresis,

		Qt.Key_Yacute,
		Qt.Key_ydiaeresis,

		Qt.Key_THORN,
		Qt.Key_ssharp
	]
	// qmlformat on

	signal requestClose

	function send(text: string): void {
		if (text.trim() === "")
			return;
		following = true;
		chatData.sendMessage(text);
		input.text = "";
	}

	function focusInput(): void {
		Qt.callLater(() => input.forceActiveFocus());
	}

	onChatDataChanged: {
		if (chatData)
			focusInput();
	}
	Keys.onPressed: e => {
		if (root.keys.includes(e.key)) {
			input.insert(input.length, e.text);
			focusInput();
		}
	}

	RowLayout {
		id: header

		anchors.left: parent.left
		anchors.right: parent.right
		anchors.top: parent.top
		spacing: Tokens.spacing.large

		IconButton {
			icon: "arrow_back"
			inactiveColor: Colors.tPalette.m3surfaceContainerHigh
			inactiveOnColor: Colors.palette.m3onSurfaceVariant
			isRound: true
			type: IconButton.Tonal

			enabled: !ChatState.isWindow
			visible: enabled

			onClicked: root.requestClose()
		}

		CustomText {
			Layout.fillWidth: ChatState.isWindow ? false : true
			Layout.alignment: ChatState.isWindow ? Qt.AlignCenter : Qt.AlignLeft | Qt.AlignVCenter
			elide: Text.ElideRight
			font.pointSize: Tokens.font.size.larger
			text: qsTr(root.chatData.title)
		}
	}

	Loader {
		id: listLoader

		anchors.bottom: input.top
		anchors.bottomMargin: Tokens.spacing.medium
		anchors.left: parent.left
		anchors.right: parent.right
		anchors.top: header.bottom
		anchors.topMargin: Tokens.spacing.medium
		active: root.chatData && root.chatData.loaded

		sourceComponent: VerticalFadeListView {
			id: list

			property bool userScrolledUp: false
			property real lastCHeight: 0.0

			function scrollToBottom(): void {
				scrollAnim.start();
			}

			cacheBuffer: Math.max(height * 20, 0)
			clip: true
			fadeAmount: 0.05
			fadeThreshold: Tokens.padding.medium
			model: root.chatData.messagesModel
			spacing: 0
			rotation: 180
			add: Transition {
				Anim {
					from: -100
					property: "y"
				}
			}

			CustomScrollBar.vertical: CustomScrollBar {
				id: scrollBar

				flickable: list
				parent: list.parent
				anchors.top: list.top
				anchors.right: list.right
				anchors.bottom: list.bottom

				transform: Rotation {
					origin.y: list.height / 2
					origin.x: scrollBar.width / 2
					angle: 180

					axis {
						y: 0
						x: 1
						z: 0
					}
				}
			}
			delegate: MessageDelegate {
				rotation: 180
			}

			displaced: Transition {
				Anim {
					property: "y"
				}
			}
			move: Transition {
				Anim {
					property: "y"
				}
			}

			Component.onCompleted: {
				positionViewAtBeginning();
			}
			onAtYBeginningChanged: {
				if (atYBeginning)
					userScrolledUp = false;
			}
			onContentHeightChanged: {
				if (userScrolledUp && Chat.busy) {
					const delta = contentHeight - lastCHeight;
					contentY += delta;
				}

				lastCHeight = contentHeight;
			}
			onMovingChanged: {
				if (moving)
					userScrolledUp = !atYBeginning;
			}

			Anim {
				id: scrollAnim

				property: "contentY"
				target: list
				type: Anim.DefaultEffects
				to: list.originY
			}

			WheelInverter {
				target: list
			}
		}

		// Trigger the load even before we're ready to show the list.
		Component.onCompleted: if (root.chatData)
			root.chatData.messagesModel
	}

	EmptyBackground {
		id: emptyState

		anchors.fill: parent
		spacing: Tokens.spacing.small
		visible: root.chatData.messageCount < 1
	}

	Item {
		anchors.bottom: input.top
		anchors.bottomMargin: Tokens.spacing.extraLarge
		anchors.horizontalCenter: parent.horizontalCenter
		implicitHeight: scrollToBottom.implicitHeight
		implicitWidth: scrollToBottom.implicitWidth
		scale: !listLoader.item.atYBeginning && listLoader.item.contentHeight > listLoader.item.height ? 1 : 0
		visible: scale > 0

		Behavior on scale {
			Anim {}
		}

		Elevation {
			anchors.fill: parent
			level: 2
			radius: scrollToBottom.radius
		}

		IconButton {
			id: scrollToBottom

			anchors.centerIn: parent
			font.pointSize: Tokens.font.size.large
			icon: "arrow_downward"
			isRound: true
			padding: Tokens.padding.extraSmall
			type: IconButton.Tonal

			onClicked: {
				listLoader.item.scrollToBottom();
			}
		}
	}

	ChatInput {
		id: input

		anchors.bottom: parent.bottom
		anchors.left: parent.left
		anchors.right: parent.right
		bg.border.color: Colors.palette.m3outlineVariant
		bg.color: Colors.tPalette.m3surfaceContainerLowest
		font.pointSize: Tokens.font.size.normal
		implicitHeight: Math.min(root.height / 5, contentHeight + topPadding + bottomPadding)
		focus: true
		placeholderText: qsTr("Send a message")
		sendIcon.font.pointSize: Tokens.font.size.large
		sendIcon.icon: "arrow_upward"
		sendIcon.padding: Tokens.padding.extraSmall

		Component.onCompleted: root.focusInput()
		Keys.onPressed: e => {
			if (e.key == Qt.Key_Return) {
				if (!(e.modifiers & Qt.ShiftModifier)) {
					root.send(text);
					e.accepted = true;
				}
			}
		}
		onSendPressed: root.send(text)
	}
}
