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

Item {
	id: root

	required property int index
	required property var modelData
	required property var blocks
	readonly property var segments: modelData.segments
	required property ChatGeneration current
	readonly property bool isActive: index === blocks.length - 1
	property bool expanded: false
	readonly property LlmSegment lastSegment: root.segments[root.segments.length - 1]
	readonly property real totalElapsedMs: root.segments.reduce((sum, s) => sum + (s.elapsedMs ?? 0), 0)
	readonly property bool pendingApproval: current.toolApprovalPending && segments.filter(s => s.type === LlmSegment.Type.ToolCall).every(s => current.pendingToolCalls.includes(s))

	clip: true
	implicitHeight: {
		const expand = expandedRect.implicitHeight + layout.implicitHeight + expandedRect.anchors.topMargin;
		const collapsed = layout.implicitHeight;
		const approval = layout.implicitHeight + approvalPrompt.implicitHeight + approvalPrompt.anchors.topMargin;

		if (expanded)
			return expand;
		else if (pendingApproval)
			return approval;
		else
			return collapsed;
	}

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

	RowLayout {
		id: layout

		anchors.top: parent.top
		anchors.left: parent.left
		anchors.right: parent.right

		Item {
			implicitHeight: expandBtn.implicitHeight
			implicitWidth: expandBtn.implicitWidth

			LoadingIndicator {
				id: spinnerReasoning

				implicitSize: collapsedText.implicitHeight
				anchors.centerIn: parent
				opacity: root.isActive ? 1 : 0
				visible: opacity > 0

				Behavior on opacity {
					Anim {}
				}
			}

			IconButton {
				id: expandBtn

				font.pointSize: Tokens.font.size.large
				icon: "keyboard_arrow_down"
				inactiveOnColor: hovered ? Colors.palette.m3onSurface : Colors.palette.m3outline
				anchors.centerIn: parent
				opacity: root.isActive ? 0 : 1
				enabled: opacity > 0
				rotation: root.expanded ? 180 : 0
				type: IconButton.Text

				Behavior on rotation {
					Anim {}
				}

				onClicked: root.expanded = !root.expanded
			}
		}

		CustomText {
			id: collapsedText

			color: Colors.palette.m3outline
			font.pointSize: Tokens.font.size.small
			Layout.fillWidth: true
			Layout.leftMargin: Tokens.spacing.medium
			text: {
				if (root.isActive) {
					if (root.pendingApproval)
						return qsTr("Waiting for approval...");

					if (root.lastSegment.type === LlmSegment.Type.ToolCall)
						return qsTr("Using %1...").arg(root.lastSegment.name);
					return qsTr("Thinking...");
				}
				return qsTr("Worked for %1s").arg((root.totalElapsedMs / 1000).toFixed(1));
			}

			Behavior on opacity {
				Anim {}
			}
		}
	}

	Item {
		id: approvalPrompt
		anchors.top: layout.bottom
		anchors.topMargin: Tokens.spacing.small
		anchors.left: parent.left
		anchors.right: parent.right
		implicitHeight: approvalLayout.implicitHeight + approvalLayout.anchors.margins * 2
		visible: root.pendingApproval

		CustomRect {
			id: approvalBg

			anchors.fill: parent
			radius: Tokens.rounding.medium
			color: Colors.palette.m3surface
			border.width: 1
			border.color: Colors.palette.m3outlineVariant

			ColumnLayout {
				id: approvalLayout
				anchors.fill: parent
				anchors.margins: Tokens.padding.medium
				spacing: Tokens.spacing.small

				CustomText {
					id: requestHeader
					text: qsTr("Tool call request")
					font.pointSize: Tokens.font.size.large
					color: Colors.palette.m3onSurface
				}

				Item {
					id: toolsBg

					property bool open: false

					implicitHeight: toolList.implicitHeight + toolList.anchors.margins * 2
					Layout.fillWidth: true

					BlobGroup {
						id: blobGroup

						color: toolsBg.open ? Colors.palette.m3surfaceContainerHighest : Colors.tPalette.m3primaryContainer

						Behavior on color {
							CAnim {}
						}
					}

					Item {
						id: toolWrapper

						width: toolsBg.width
						height: toolList.implicitHeight + toolList.anchors.margins * 2

						BlobRect {
							id: dialogBg

							anchors.fill: parent
							bottomLeftRadius: toolsBg.open ? Tokens.rounding.largeIncreased : Tokens.rounding.small
							bottomRightRadius: toolsBg.open ? Tokens.rounding.largeIncreased : Tokens.rounding.small
							topRightRadius: toolsBg.open ? Tokens.rounding.largeIncreased : Tokens.rounding.small
							topLeftRadius: toolsBg.open ? Tokens.rounding.largeIncreased : Tokens.rounding.small
							deformScale: 0
							group: blobGroup
							opacity: blobGroup.color.a * (root.enabled ? 1 : 0.5)
						}

						CustomRect {
							id: toolBox

							anchors.fill: parent
							anchors.margins: Tokens.padding.medium

							ColumnLayout {
								id: toolList

								Repeater {
									model: root.current.pendingToolCalls ?? []
									delegate: RowLayout {
										id: toolText

										required property LlmSegment modelData
										required property int index

										spacing: Tokens.spacing.medium

										function toolTarget(seg: LlmSegment): string {
											var a = null;
											try {
												a = JSON.parse(seg.arguments);
											} catch (e) {}
											if (a && typeof a === "object") {
												const v = a.url ?? a.path;
												if (v !== undefined && v !== null)
													return String(v);
											}
											return String(seg.arguments);
										}

										CustomText {
											color: Colors.palette.m3onPrimaryContainer
											text: String(toolText.index + 1)
											font.pointSize: Tokens.font.size.large
										}

										CustomText {
											color: Colors.palette.m3onPrimaryContainer
											text: qsTr("%1").arg(toolText.modelData.name)
										}

										MaterialIcon {
											color: Colors.palette.m3onPrimaryContainer
											text: "arrow_right_alt"
										}

										CustomText {
											color: Colors.palette.m3onPrimaryContainer
											text: qsTr("%1").arg(toolText.toolTarget(toolText.modelData))
										}
									}
								}
							}
						}
					}
				}

				ButtonRow {
					Layout.alignment: Qt.AlignRight
					spacing: Tokens.spacing.medium

					IconTextButton {
						icon: "check_circle"
						text: qsTr("Allow")
						horizontalPadding: Tokens.padding.large
						verticalPadding: Tokens.padding.small
						isRound: true
						shapeMorph: true
						onClicked: root.current.approveTools()
					}

					IconTextButton {
						icon: "cancel"
						text: qsTr("Deny")
						isRound: true
						shapeMorph: true
						inactiveColor: Colors.palette.m3error
						inactiveOnColor: Colors.palette.m3onError
						horizontalPadding: Tokens.padding.large
						verticalPadding: Tokens.padding.small
						onClicked: root.current.denyTools()
					}
				}
			}
		}
	}

	CustomRect {
		id: expandedRect

		anchors.left: parent.left
		anchors.right: parent.right
		anchors.top: layout.bottom
		anchors.bottom: parent.bottom
		anchors.topMargin: Tokens.spacing.small
		color: Colors.palette.m3surfaceContainerLow
		implicitHeight: expandedContent.contentHeight + expandedContent.anchors.margins * 2
		opacity: root.expanded ? 1 : 0
		radius: Tokens.rounding.medium
		visible: opacity > 0

		Behavior on opacity {
			Anim {}
		}

		ListView {
			id: expandedContent

			anchors.fill: parent
			anchors.margins: Tokens.padding.medium
			model: root.segments
			spacing: Tokens.spacing.medium

			delegate: Item {
				id: segment

				required property LlmSegment modelData
				required property int index

				implicitWidth: ListView.view.width
				implicitHeight: header.implicitHeight + content.implicitHeight + content.anchors.topMargin

				RowLayout {
					id: header

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

					MaterialIcon {
						text: segment.modelData.type === LlmSegment.Type.Reasoning ? "cognition" : "build"
						fill: 1
					}

					CustomText {
						Layout.fillWidth: true
						text: segment.modelData.type === LlmSegment.Type.Reasoning ? qsTr("Thought for %1s").arg((segment.modelData.elapsedMs / 1000).toFixed(1)) : qsTr("Used %1 for %2s").arg(segment.modelData.name).arg((segment.modelData.elapsedMs / 1000).toFixed(1))
					}
				}

				CustomText {
					id: content

					function toolTarget(seg: LlmSegment): string {
						var a = null;
						try {
							a = JSON.parse(seg.arguments);
						} catch (e) {}
						if (a && typeof a === "object") {
							const v = a.url ?? a.path;
							if (v !== undefined && v !== null)
								return String(v);
						}
						return String(seg.arguments);
					}

					function prettyTool(seg: LlmSegment): string {
						if (seg.name === "webfetch") {
							switch (seg.status) {
							case LlmSegment.Status.Running:
								return qsTr("Fetching");
							case LlmSegment.Status.Pending:
								return qsTr("Pending fetch");
							case LlmSegment.Status.Success:
								return qsTr("Fetched");
							case LlmSegment.Status.Error:
								return qsTr("Failed to fetch");
							default:
								return qsTr("Fetched website");
							}
						} else if (seg.name === "readfile") {
							switch (seg.status) {
							case LlmSegment.Status.Running:
								return qsTr("Reading");
							case LlmSegment.Status.Pending:
								return qsTr("Pending read");
							case LlmSegment.Status.Success:
								return qsTr("Read");
							case LlmSegment.Status.Error:
								return qsTr("Failed to read");
							default:
								return qsTr("Read file");
							}
						}
					}

					anchors.left: parent.left
					anchors.leftMargin: Tokens.padding.small
					anchors.top: header.bottom
					anchors.topMargin: Tokens.spacing.small
					anchors.right: parent.right
					color: Colors.palette.m3outline
					font.pointSize: Tokens.font.size.small
					wrapMode: CustomText.WrapAtWordBoundaryOrAnywhere
					text: segment.modelData.type === LlmSegment.Type.Reasoning ? segment.modelData.text : qsTr("%1 %2").arg(content.prettyTool(segment.modelData)).arg(content.toolTarget(segment.modelData))
				}
			}
		}
	}
}
