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

Item {
	id: root

	required property bool isUser
	required property LlmSegment segment
	required property bool hovered
	required property Repeater repeater
	required property int index
	required property ChatMessage message
	required property ChatGeneration current

	readonly property real contentMaxWidth: width - Tokens.spacing.extraSmall - Tokens.spacing.extraLarge

	signal edit(text: string)

	implicitHeight: bubble.implicitHeight + (actionsRow.shouldBeActive ? actionsRow.implicitHeight + actionsRow.anchors.topMargin : 0)

	CustomClippingRect {
		id: bubble

		property real liveTargetWidth: root.isUser ? Math.min(msgText.implicitWidth + Tokens.padding.medium * 2, root.contentMaxWidth) : root.contentMaxWidth
		property real frozenWidth: 0.0
		property bool layoutFrozen: false
		property real layoutWidth: root.isUser ? Math.min(msgText.implicitWidth + Tokens.padding.medium * 2, root.contentMaxWidth) : root.contentMaxWidth

		radius: Tokens.rounding.medium
		color: root.isUser ? Colors.palette.m3primary : Colors.palette.m3surfaceContainer
		implicitWidth: layoutFrozen ? frozenWidth : layoutWidth
		implicitHeight: root.isUser ? msgText.contentHeight + Tokens.padding.medium * 2 : blocks.implicitHeight + blocks.anchors.topMargin * 2
		anchors.right: root.isUser ? parent.right : undefined
		layer.enabled: false
		layer.smooth: true

		transform: Scale {
			id: stretchScale
			origin.x: root.isUser ? bubble.width : 0
			xScale: bubble.layoutFrozen && bubble.frozenWidth > 0 ? bubble.liveTargetWidth / bubble.frozenWidth : 1.0
		}

		states: [
			State {
				name: "toSlim"
				when: ChatState.isWindow && !ChatState.isWide && !ChatState.settledSlim

				PropertyChanges {
					bubble.layer.enabled: true
					bubble.layoutFrozen: true
				}
			},
			State {
				name: "toWide"
				when: ChatState.isWindow && ChatState.isWide && !ChatState.settledWide

				PropertyChanges {
					bubble.layer.enabled: true
					bubble.layoutFrozen: true
				}
			}
		]

		onLayoutFrozenChanged: {
			if (layoutFrozen)
				frozenWidth = width;
		}

		TextEditBase {
			id: msgText

			property string cachedText: root.segment.text
			property bool cancelled: false

			visible: root.isUser
			anchors.left: parent.left
			anchors.margins: Tokens.padding.medium
			anchors.right: parent.right
			anchors.top: parent.top
			animateCursor: false
			color: root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
			cursor.color: root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3primary
			font.pointSize: Tokens.font.size.smaller
			readOnly: true
			selectionColor: Qt.alpha((root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3primary), 0.4)
			text: root.isUser ? root.segment.text : ""
			textFormat: CustomText.MarkdownText
			wrapMode: Text.WordWrap

			Keys.onPressed: event => {
				if (event.key == Qt.Key_Return) {
					if (!(event.modifiers & Qt.ShiftModifier)) {
						readOnly = true;
						event.accepted = true;
					}
				} else if (event.key == Qt.Key_Escape) {
					cancelled = true;
					readOnly = true;
					event.accepted = true;
				}
			}
			onEditingFinished: {
				readOnly = true;
			}
			onReadOnlyChanged: {
				if (readOnly) {
					animateCursor = false;
					textFormat = CustomText.MarkdownText;

					if (cancelled) {
						text = cachedText;
						cancelled = false;
						return;
					}

					root.edit(text);
				} else {
					textFormat = CustomText.PlainText;
					text = cachedText;
					forceActiveFocus();
					cursorPosition = text.length;
					animateCursor = true;
				}
			}
		}

		// Assistant content: parsed markdown blocks.
		MarkdownBlocks {
			id: blocks

			visible: !root.isUser
			anchors.topMargin: Tokens.padding.medium
			anchors.top: parent.top
			anchors.left: parent.left
			anchors.right: parent.right
			blocks: root.segment.markdown
		}
	}

	Actions {
		id: actionsRow

		readonly property bool shouldBeActive: (root.segment.type === LlmSegment.Type.Content) && !root.segment.running && root.repeater.count === (root.index + 1)

		anchors.left: parent.left
		anchors.right: (implicitWidth > bubble.implicitWidth) ? undefined : bubble.right
		anchors.top: bubble.bottom
		opacity: shouldBeActive ? 1 : 0
		visible: opacity > 0
		anchors.topMargin: Tokens.spacing.medium
		edit: msgText
		hovered: root.hovered
		isUser: root.isUser
		segment: root.segment
		current: root.current
		message: root.message

		Behavior on opacity {
			Anim {}
		}
	}
}
