<template>
	<el-scrollbar class="w-full box-border p-12px">
		<div class="knowledge-retrieval-setter">
			<section class="section-block">
				<div class="section-title-row">
					<label class="section-title">查询内容</label>
				</div>
				<VarInput
					v-model="formData.query"
					:rows="3"
					class="w-full"
					placeholder="请输入，输入/选择变量"
				/>
				<div class="field-hint">{{ texts.queryVariableTip }}</div>
			</section>

			<section class="section-block">
				<div class="section-title-row">
					<label class="section-title">{{ texts.knowledgeBases }}</label>
				</div>
				<el-select
					v-model="formData.knowledge_base_ids"
					multiple
					filterable
					allow-create
					default-first-option
					class="id-tag-input"
					:placeholder="texts.knowledgeBasesPlaceholder"
					:aria-label="texts.knowledgeBasesPlaceholder"
					:loading="knowledgeBaseLoading"
					clearable
				>
					<el-option
						v-for="item in knowledgeBaseOptions"
						:key="item.value"
						:label="item.label"
						:value="item.value"
					/>
				</el-select>
				<div class="field-hint">{{ texts.knowledgeBasesTip }}</div>
			</section>

			<section class="section-block">
				<div class="section-title-row">
					<label class="section-title">{{ texts.knowledgeIds }}</label>
				</div>
				<el-select
					v-model="formData.knowledge_ids"
					multiple
					filterable
					class="id-tag-input"
					:placeholder="texts.knowledgeIdsPlaceholder"
					:aria-label="texts.knowledgeIdsPlaceholder"
					:loading="knowledgeLoading"
					clearable
				>
					<el-option
						v-for="item in knowledgeOptions"
						:key="item.value"
						:label="item.label"
						:value="item.value"
					/>
				</el-select>
				<div class="field-hint">{{ texts.knowledgeIdsTip }}</div>
			</section>

			<section class="section-block">
				<div class="grid-two">
					<div class="field-block">
						<div class="section-title-row section-title-row--compact">
							<label class="section-title">{{ texts.topK }}</label>
						</div>
						<el-input-number v-model="formData.top_k" :min="1" :max="100" class="w-full" />
					</div>
					<div class="field-block">
						<div class="section-title-row section-title-row--compact">
							<label class="section-title">{{ texts.scoreThreshold }}</label>
							<el-switch v-model="formData.score_threshold_enable" />
						</div>
						<el-input-number
							v-model="formData.score_threshold"
							:min="0"
							:max="1"
							:step="0.05"
							:disabled="!formData.score_threshold_enable"
							:precision="2"
							class="w-full"
						/>
					</div>
				</div>
			</section>

			<section class="section-block">
				<el-collapse>
					<el-collapse-item title="" name="2">
						<template #title>
							<div class="flex items-center justify-between beautify">
								<label class="text-14px font-bold text-gray-700">输出变量</label>
							</div>
						</template>
						<ul>
							<li v-for="output in formData.outputs" :key="output.name">
								<div>
									<span class="text-#333">{{ output.name }}</span>
									<span class="text-#999 ml-8px">{{ output.type }}</span>
								</div>
								<div class="text-#666">{{ output.describe }}</div>
							</li>
						</ul>
					</el-collapse-item>
				</el-collapse>
			</section>

			<NodeRuntimeConfig v-model="formData" />
		</div>
	</el-scrollbar>
</template>

<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { knowledge } from '@repo/api-service'

import NodeRuntimeConfig from '@/nodes/_base/NodeRuntimeConfig.vue'
import VarInput from '@/nodes/_base/VarInput.vue'
import { useI18n } from '@/composables/useI18n'
import { useSetterModel } from '../_shared/useSetterModel'

import type { KnowledgeRetrievalData } from './index'

type SelectOption = {
	label: string
	value: string
	raw?: any
}

const props = defineProps<{
	data: KnowledgeRetrievalData
}>()

const emit = defineEmits<{
	(e: 'update', value: KnowledgeRetrievalData): void
}>()

const { t } = useI18n()
const formData = useSetterModel<KnowledgeRetrievalData>(props, emit)
const knowledgeBaseLoading = ref(false)
const knowledgeLoading = ref(false)
const knowledgeBaseOptions = ref<SelectOption[]>([])
const knowledgeOptions = ref<SelectOption[]>([])
const knowledgePageSize = 20

const texts = computed(() => ({
	queryVariable: t('pages.knowledgeRetrievalSetter.queryVariable'),
	queryVariablePlaceholder: t('pages.knowledgeRetrievalSetter.queryVariablePlaceholder'),
	queryVariableTip: t('pages.knowledgeRetrievalSetter.queryVariableTip'),
	knowledgeBases: t('pages.knowledgeRetrievalSetter.knowledgeBases'),
	knowledgeBasesPlaceholder: t('pages.knowledgeRetrievalSetter.knowledgeBasesPlaceholder'),
	knowledgeBasesTip: t('pages.knowledgeRetrievalSetter.knowledgeBasesTip'),
	knowledgeIds: t('pages.knowledgeRetrievalSetter.knowledgeIds'),
	knowledgeIdsPlaceholder: t('pages.knowledgeRetrievalSetter.knowledgeIdsPlaceholder'),
	knowledgeIdsTip: t('pages.knowledgeRetrievalSetter.knowledgeIdsTip'),
	topK: t('pages.knowledgeRetrievalSetter.topK'),
	scoreThreshold: t('pages.knowledgeRetrievalSetter.scoreThreshold'),
	outputs: t('pages.knowledgeRetrievalSetter.outputs')
}))

const normalizeOptionLabel = (item: {
	id?: string
	knowledge_id?: string
	name?: string
	title?: string
	file_name?: string
	knowledge_filename?: string
	knowledge_title?: string
}) =>
	item.title ||
	item.name ||
	item.file_name ||
	item.knowledge_filename ||
	item.knowledge_title ||
	item.id ||
	item.knowledge_id ||
	''

const normalizeOptionValue = (item: { id?: string; knowledge_id?: string; file_id?: string }) =>
	item.id || item.knowledge_id || item.file_id || ''

const mergeSelectedOptions = (options: SelectOption[], selectedValues: string[]) => {
	const optionMap = new Map<string, SelectOption>()
	options.forEach((item) => {
		if (item.value) optionMap.set(item.value, item)
	})
	selectedValues.forEach((value) => {
		if (value && !optionMap.has(value)) {
			optionMap.set(value, {
				label: value,
				value
			})
		}
	})
	return Array.from(optionMap.values())
}

const fetchKnowledgeBaseOptions = async () => {
	knowledgeBaseLoading.value = true
	try {
		const res = await knowledge.postKnowledgeBasePageList({
			keyword: '',
			type: '',
			pageIndex: 1,
			pageSize: 20
		})
		if (!res?.isSuccess) return

		const list = (res.result?.model || []).map((item) => ({
			label: normalizeOptionLabel(item),
			value: normalizeOptionValue(item),
			raw: item
		}))
		knowledgeBaseOptions.value = mergeSelectedOptions(
			list.filter((item) => item.value),
			formData.value.knowledge_base_ids
		)

		if (!formData.value.knowledge_base_ids?.length && list[0]?.value) {
			formData.value.knowledge_base_ids = [list[0].value]
		}

		return list
	} finally {
		knowledgeBaseLoading.value = false
	}
}

const fetchKnowledgeOptions = async (baseIdsInput?: string[]) => {
	const baseIds = Array.from(
		new Set((baseIdsInput || formData.value.knowledge_base_ids || []).filter(Boolean))
	)
	if (!baseIds.length) {
		knowledgeOptions.value = mergeSelectedOptions([], formData.value.knowledge_ids)
		return
	}

	knowledgeLoading.value = true
	try {
		const results = await Promise.all(
			baseIds.map((knowledgeBaseId) =>
				knowledge.postKnowledgePageList({
					knowledge_base_id: knowledgeBaseId,
					title: '',
					file_type: '',
					pageIndex: 1,
					pageSize: knowledgePageSize
				})
			)
		)

		const optionMap = new Map<string, SelectOption>()
		results.forEach((res) => {
			if (!res?.isSuccess) return
			console.log(res.result)
			;(res.result?.model || []).forEach((item) => {
				if (!item.id) return
				optionMap.set(item.id, {
					label: normalizeOptionLabel(item),
					value: item.id,
					raw: item
				})
			})
		})

		knowledgeOptions.value = mergeSelectedOptions(
			Array.from(optionMap.values()),
			formData.value.knowledge_ids
		)
	} finally {
		knowledgeLoading.value = false
	}
}

const ensureDefaults = () => {
	formData.value.title ||= t('nodes.meta.knowledge-retrieval.displayName')
	formData.value.type ||= 'knowledge-retrieval'
	formData.value.query ||= ''
	formData.value.top_k = typeof formData.value.top_k === 'number' ? formData.value.top_k : 10
	formData.value.knowledge_base_ids ||= []
	formData.value.knowledge_ids ||= []
	formData.value.score_threshold_enable =
		typeof formData.value.score_threshold_enable === 'boolean'
			? formData.value.score_threshold_enable
			: false
	formData.value.score_threshold =
		typeof formData.value.score_threshold === 'number' ? formData.value.score_threshold : 0.8
	if (!formData.value.outputs?.length) {
		formData.value.outputs = [
			{
				name: 'result',
				describe: t('nodes.outputs.knowledge-retrieval.result'),
				type: 'array[object]'
			},
			{
				name: 'content',
				describe: t('nodes.outputs.knowledge-retrieval.content'),
				type: 'string'
			}
		]
	}
}

const syncSelectableLists = async () => {
	const baseList = await fetchKnowledgeBaseOptions()
	const baseIds = formData.value.knowledge_base_ids?.length
		? [...formData.value.knowledge_base_ids]
		: baseList?.[0]?.value
			? [baseList[0].value]
			: []

	if (!formData.value.knowledge_base_ids?.length && baseIds.length) {
		formData.value.knowledge_base_ids = [...baseIds]
	}

	await fetchKnowledgeOptions(baseIds)
}

watch(
	formData,
	() => {
		ensureDefaults()
	},
	{ deep: true, immediate: true }
)

watch(
	() => [...formData.value.knowledge_base_ids],
	(baseIds) => {
		void fetchKnowledgeOptions(baseIds)
	},
	{ deep: true }
)

onMounted(() => {
	void syncSelectableLists()
})
</script>

<style scoped lang="less">
.knowledge-retrieval-setter {
	display: flex;
	flex-direction: column;
	gap: 16px;
}

.section-block {
	padding-bottom: 16px;
	border-bottom: 1px solid #eef2f7;
}

.section-title-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	margin-bottom: 10px;
}

.section-title {
	font-size: 14px;
	font-weight: 700;
	color: #344054;
}

.field-hint {
	margin-top: 8px;
	font-size: 12px;
	line-height: 1.5;
	color: #667085;
}

.grid-two {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: 16px;
}

.field-block {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.section-title-row--compact {
	min-height: 32px;
	margin-bottom: 0;
}

.id-tag-input {
	width: 100%;
}

.output-list {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.output-item {
	padding: 10px 12px;
	border: 1px solid #eaecf0;
	border-radius: 10px;
	background: #f9fafb;
}

.output-item__main {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
}

.output-item__name {
	font-size: 13px;
	font-weight: 700;
	color: #344054;
}

.output-item__type {
	font-size: 12px;
	color: #667085;
}

.output-item__desc {
	margin-top: 4px;
	font-size: 12px;
	line-height: 1.5;
	color: #667085;
}
</style>
