<template>
	<div class="form-content">
		<cl-svg name="add" class="btn-icon is-rt" @click="add()" />

		<draggable class="list" tag="div" v-model="list" :animation="300" item-key="id">
			<template #item="{ element: item, index }">
				<div
					class="item textarea-item"
					:class="{
						error: !item.content
					}"
				>
					<div class="head">
						<el-select
							class="role"
							v-model="item.role"
							size="small"
							popper-class="cl-flow__popper"
							:disabled="item.role == 'system'"
						>
							<el-option
								v-for="t in getRoles(item)"
								:label="t.label"
								:value="t.value"
								:key="t.value"
							/>
						</el-select>

						<div class="op">
							<cl-svg
								name="delete"
								class="btn-icon"
								@click="remove(index)"
								v-if="item.role != 'system'"
							/>
						</div>
					</div>

					<div
						:ref="setRefs(`input-${index}`)"
						class="content"
						:class="{
							'is-empty': !item.content
						}"
						contenteditable="true"
						@input="(e) => onContentInput(e, item)"
						@focus="(e) => onContentInput(e, item)"
						@keydown="(e) => onContentKeydown(e)"
						v-html="item.text"
					></div>
				</div>
			</template>
		</draggable>

		<!-- 选择变量 -->
		<tools-var
			:ref="setRefs('toolsVar')"
			only-select
			position="absolute"
			:show-picker="false"
			:autofocus="false"
			use-input-params
		/>
	</div>
</template>

<script setup lang="ts" name="node-llm-form-content">
import { type PropType, onMounted, onUnmounted, useModel } from "vue";
import { useCool } from "/@/cool";
import { last } from "lodash-es";
import { sleep } from "/@/cool/utils";
import { useFlow } from "/$/flow/hooks";
import ToolsVar from "/$/flow/components/tools/var.vue";
import Draggable from "vuedraggable";

const props = defineProps({
	modelValue: {
		type: Array as PropType<LLMMessage[]>,
		default: () => []
	}
});

const { refs, setRefs } = useCool();
const flow = useFlow();

// 绑定值
const list = useModel(props, "modelValue");

// 获取类型
function getRoles(item: LLMMessage) {
	return [
		{
			label: "SYSTEM",
			value: "system"
		},
		{
			label: "USER",
			value: "user"
		},
		{
			label: "ASSISTANT",
			value: "assistant"
		}
	].filter((e) => {
		return item.role == "system" ? true : e.value != "system";
	});
}

// 添加
function add() {
	const item = last(list.value);

	list.value.push({
		role: item?.role == "user" ? "assistant" : "user",
		content: ""
	});
}

// 删除
function remove(index: number) {
	list.value.splice(index, 1);
}

// 设置内容
function setContent(el: HTMLElement, item: LLMMessage) {
	let val = "";

	function deep(e: Node) {
		if (e.nodeType == 1) {
			const node = e as HTMLElement;
			const field = node.getAttribute("data-field");

			if (field) {
				val += `{${field}}`;
			} else {
				if (val) {
					val += "\n";
				}

				if (e.textContent) {
					e.childNodes.forEach(deep);
				}
			}
		} else {
			val += e.textContent;
		}
	}

	deep(el);

	item.content = val;
}

// 监听内容输入
async function onContentInput(e: any, item: LLMMessage) {
	setContent(e.target, item);

	const sel = window.getSelection();

	if (!sel || sel.rangeCount == 0) {
		return;
	}

	await sleep(10);

	const range = sel.getRangeAt(0);

	// 获取光标位置
	const startContainer: any = range.startContainer;
	const startOffset = range.startOffset;

	// 如果光标在文本节点中，检查前一个字符
	if (startOffset > 0 && startContainer.textContent?.[startOffset - 1] === "/") {
		range.setStart(sel.anchorNode!, sel.anchorOffset);
		range.collapse(true);

		// 获取选中的位置
		const rect = range.getBoundingClientRect();

		// 获取选中父级的位置
		const container = startContainer.parentElement.closest(".form-content");
		const containerRect = container.getBoundingClientRect();

		// 计算相对位置
		const relativeReact = {
			top: rect.top - containerRect.top + 8,
			left: rect.left - containerRect.left,
			width: rect.width,
			height: rect.height
		};

		// 自定义变量节点
		refs.toolsVar.open({
			rect: relativeReact,
			onSelect(item: any) {
				const pos = range.startOffset;

				if (pos > 0) {
					// 删除 / 符号
					range.setStart(range.startContainer, pos - 1);
					range.deleteContents();

					// 创建自定义元素
					const node = document.createElement("div");
					node.setAttribute("contenteditable", "false");
					node.setAttribute("data-field", item.field);
					node.className = "field";
					node.innerText = item.field;

					// 选中当前元素
					node.addEventListener("click", () => {
						const sel = window.getSelection();
						sel?.removeAllRanges();
						sel?.addRange(range);
					});

					// 插入元素
					range.insertNode(node);

					// 设置光标
					range.setStartAfter(node);
					range.setEndAfter(node);

					// 让新的range生效
					const sel2 = window.getSelection();
					sel2?.removeAllRanges();
					sel2?.addRange(range);
				}
			}
		});
	} else {
		refs.toolsVar.close();
	}
}

// 方向键控制
function onContentKeydown(e: KeyboardEvent) {
	if (e.key == "ArrowUp" || e.key == "ArrowDown") {
		refs.toolsVar.focus(e);
	}
}

// 监听选择
function onSelectionChange() {
	function isRangeInsideElement(range: Range, element: Element) {
		const elementRange = document.createRange();
		elementRange.selectNodeContents(element);
		return range.intersectsNode(element);
	}

	const selection = document.getSelection();

	if (selection && selection.rangeCount != 0) {
		const selectedRange = selection.getRangeAt(0);

		for (let i in refs) {
			// 所有输入框
			if (i.includes("input-")) {
				if (refs[i]?.contains(selectedRange.commonAncestorContainer)) {
					const list = refs[i].querySelectorAll(".field") as HTMLElement[];

					// 判断是选中
					list.forEach((e) => {
						if (isRangeInsideElement(selectedRange, e)) {
							e.className = "field active";
						} else {
							e.className = "field";
						}
					});

					return;
				}
			}
		}
	}
}

onMounted(() => {
	list.value.forEach((e) => {
		let start = -1;
		let arr: any[] = [];

		for (let i = 0; i < e.content.length; i++) {
			let v = e.content[i];

			if (v == "{") {
				start = i;
			} else if (v == "}") {
				const field = e.content.substring(start + 1, i);
				const param = flow.node?.data?.inputParams?.find((e) => e.field == field);

				if (param) {
					arr.push(
						`<div class="field" contenteditable="false" data-field="${field}">${field}</div>`
					);
				}

				start = -1;
			} else {
				if (start == -1) {
					arr.push(v);
				}
			}
		}

		e.text = arr.join("");
	});

	document.addEventListener("selectionchange", onSelectionChange);
});

onUnmounted(() => {
	document.removeEventListener("selectionchange", onSelectionChange);
});
</script>

<style lang="scss" scoped>
.form-content {
	// pointer-events: all;
	position: relative;

	.list {
		.item {
			.head {
				padding: 5px 10px !important;

				.role {
					width: 100px;
				}
			}

			.content {
				outline: none;
				line-height: 1.5;
				padding: 0 10px;
				min-height: 50px;
				user-select: text;
				white-space: pre-wrap;
				word-break: break-word;
				cursor: text;

				:deep(.field) {
					display: inline-block;
					border-radius: 4px;
					padding: 0 4px;
					margin: 0 2px;
					font-size: 12px;
					cursor: pointer;
					border: 1px solid var(--el-border-color);
					box-sizing: border-box;
					user-select: none;
					color: var(--el-color-primary);

					&:hover,
					&.active {
						border-color: var(--el-color-primary);
					}
				}

				&.is-empty {
					color: var(--el-text-color-placeholder);
					cursor: text;

					&::before {
						content: "在这里写你的提示词，输入 “/” 插入变量";
					}
				}
			}

			&.error {
				border-color: var(--el-color-danger) !important;
			}
		}
	}
}
</style>
