<template>
	<el-dialog
		v-model="visible"
		:title="formId ? '编辑智能体' : '新建智能体'"
		class="agent-modal"
		fullscreen
	>
		<div class="modal-wrap">
			<el-form
				ref="formRef"
				:model="form"
				:rules="rules"
				label-position="left"
				class="agent-form"
				label-width="120px"
			>
				<el-tabs v-model="activeTab" tab-position="left" class="settings-tabs">
					<el-tab-pane label="基础信息" name="basic">
						<div class="tab-intro">配置智能体的基本信息</div>
						<div class="collapse-body">
							<el-form-item label="运行模式" prop="mode">
								<div class="switch-wrap flex items-center gap-2">
									<el-segmented
										v-model="form.mode"
										class="selection-segmented"
										:options="[
											{ label: '快速问答', value: 'quick-answer' },
											{ label: '智能推理', value: 'smart-reasoning' }
										]"
									/>
									<div class="field-tip">多步思考，深度分析复杂问题。</div>
								</div>
							</el-form-item>
							<div class="mode-tip ml-120px">
								<div class="mode-tip__label">当前说明</div>
								<p v-if="form.mode === 'quick-answer'">
									适合问答与知识检索场景，可继续完善上下文模板、查询扩展和多轮对话。
								</p>
								<p v-else>适合工具调用与多步推理场景，可继续配置工具、MCP 服务和 Skills。</p>
							</div>
							<el-form-item label="名称" prop="name">
								<el-input v-model="form.name" placeholder="请输入智能体名称" />
								<div class="field-tip">为智能体设置一个易于识别的名称。</div>
							</el-form-item>
							<el-form-item label="图标" prop="avatar">
								<div class="emoji-field">
									<el-button class="emoji-trigger" @click="emojiDialogVisible = true">
										<span class="emoji-preview">{{ selectedEmoji }}</span>
										<span>{{ form.avatar ? '更换 Emoji' : '选择 Emoji' }}</span>
									</el-button>
									<el-button v-if="form.avatar" text @click="clearEmoji">清空</el-button>
								</div>
							</el-form-item>
							<el-form-item label="描述" prop="description">
								<el-input
									v-model="form.description"
									type="textarea"
									:rows="3"
									placeholder="请输入智能体描述"
								/>
								<div class="field-tip">简要描述智能体的用途和特点。</div>
							</el-form-item>
							<el-form-item label="系统提示词" prop="config.basic_config.system_prompt">
								<div class="prompt-field">
									<div class="prompt-toolbar">
										<div class="prompt-variable-row">
											<span class="prompt-variable-label">支持变量</span>
											<el-tag
												v-for="variable in systemPromptVariables"
												:key="variable"
												class="prompt-variable-tag"
												type="info"
												effect="plain"
												@click="insertPromptVariable('systemPrompt', variable)"
											>
												{{ formatPromptVariable(variable) }}
											</el-tag>
										</div>
										<el-button
											class="prompt-template-trigger"
											text
											:icon="DocumentCopy"
											@click="openPromptTemplatePicker('systemPrompt')"
										>
											模板选择
										</el-button>
									</div>
									<el-input
										ref="systemPromptInputRef"
										v-model="form.config.basic_config.system_prompt"
										mode="prompt"
										type="textarea"
										:rows="8"
										placeholder="请输入系统提示词，可直接编写角色、目标、约束和回答风格"
									/>
								</div>
								<div class="field-tip">自定义系统提示词，定义智能体的行为和角色。</div>
							</el-form-item>
							<el-form-item
								v-if="form.mode === 'quick-answer'"
								label="上下文模板"
								prop="config.basic_config.context_template"
							>
								<div class="prompt-field">
									<div class="prompt-toolbar">
										<div class="prompt-variable-row">
											<span class="prompt-variable-label">支持变量</span>
											<el-tag
												v-for="variable in quickAnswerVariables"
												:key="variable"
												class="prompt-variable-tag"
												type="info"
												effect="plain"
												@click="insertPromptVariable('contextTemplate', variable)"
											>
												{{ formatPromptVariable(variable) }}
											</el-tag>
										</div>
										<el-button
											class="prompt-template-trigger"
											text
											:icon="DocumentCopy"
											@click="openPromptTemplatePicker('contextTemplate')"
										>
											模板选择
										</el-button>
									</div>
									<el-input
										ref="contextTemplateInputRef"
										v-model="form.config.basic_config.context_template"
										mode="prompt"
										type="textarea"
										:rows="5"
										placeholder="请输入上下文模板，用于约束问答模式下的上下文组织方式"
									/>
								</div>
								<div class="field-tip">定义如何将检索到的内容格式化后传递给模型。</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane label="模型配置" name="model">
						<div class="tab-intro">配置智能体的模型参数</div>
						<div class="collapse-body">
							<el-form-item label="模型" prop="config.model_config.model_id">
								<el-select
									v-model="form.config.model_config.model_id"
									filterable
									remote
									reserve-keyword
									:remote-method="searchChatModels"
									:loading="chatModelsLoading"
									style="width: 100%"
								>
									<el-option
										v-for="model in chatModels"
										:key="model.id"
										:label="modelLabel(model)"
										:value="model.id"
									/>
								</el-select>
								<div class="field-tip">选择智能体使用的大语言模型。</div>
							</el-form-item>
							<el-form-item label="温度" prop="config.model_config.temperature">
								<div class="switch-wrap w-full flex items-center gap-2">
									<el-slider
										v-model="form.config.model_config.temperature"
										:min="0"
										:max="1"
										:step="0.1"
										style="width: 50%"
									/>
									<div class="field-tip">控制输出的随机性，0 最确定，1 最随机。</div>
								</div>
							</el-form-item>
							<el-form-item label="最大 Token 数" prop="config.model_config.max_completion_tokens">
								<el-input-number
									v-model="form.config.model_config.max_completion_tokens"
									:min="1"
									style="width: 100%"
								/>
								<div class="field-tip">限制模型单次回复可生成的最大 Token 数。</div>
							</el-form-item>
							<el-form-item label="思考模式" prop="config.model_config.thinking">
								<div class="switch-wrap flex items-center gap-2">
									<el-switch v-model="form.config.model_config.thinking" />
									<div class="field-tip">启用模型的扩展思考能力，需要模型本身支持。</div>
								</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane label="知识库" name="knowledge">
						<div class="tab-intro">配置智能体可访问的知识库</div>
						<div class="collapse-body">
							<el-form-item label="关联知识库" prop="config.kb_config.knowledge_bases">
								<div class="selection-panel">
									<el-segmented
										v-model="form.config.kb_config.kb_selection_mode"
										class="selection-segmented"
										:options="selectionModeOptions"
									/>
									<el-checkbox-group
										v-if="form.config.kb_config.kb_selection_mode === 'selected'"
										v-model="form.config.kb_config.knowledge_bases"
										class="checkbox-grid"
									>
										<el-checkbox
											v-for="item in knowledgeCheckboxOptions"
											:key="item.value"
											:label="item.value"
										>
											{{ item.label }}
										</el-checkbox>
									</el-checkbox-group>
								</div>
								<div class="field-tip">选择智能体可访问的知识库范围。</div>
								<div
									v-if="form.config.kb_config.kb_selection_mode === 'selected'"
									class="field-tip"
								>
									选择要关联的知识库，包括协作知识库。
								</div>
							</el-form-item>
							<el-form-item label="知识的文件类型" prop="config.kb_config.supported_file_types">
								<el-select
									v-model="form.config.kb_config.supported_file_types"
									multiple
									allow-create
									filterable
									style="width: 100%"
								>
									<el-option
										v-for="item in supportedFileTypes"
										:key="item"
										:label="item"
										:value="item"
									/>
								</el-select>
								<div class="field-tip">限制可选择的文件类型，留空表示支持所有类型。</div>
							</el-form-item>
							<el-form-item label="ReRank 模型" prop="config.model_config.rerank_model_id">
								<el-select
									v-model="form.config.model_config.rerank_model_id"
									filterable
									remote
									reserve-keyword
									:remote-method="searchRerankModels"
									:loading="rerankModelsLoading"
									style="width: 100%"
								>
									<el-option
										v-for="model in rerankModels"
										:key="model.id"
										:label="modelLabel(model)"
										:value="model.id"
									/>
								</el-select>
								<div class="field-tip">用于对知识库检索结果进行重排序，提高回答准确性。</div>
							</el-form-item>
							<div class="subsection ml-120px">
								<div class="subsection-title">FAQ 优化策略</div>
								<div class="subsection-tip">
									当知识库中包含 FAQ（问答对）时，可以启用此策略让 FAQ 答案优先于普通文档。
								</div>
								<el-form-item label="启动 FAQ 优先" prop="config.faq_config.faq_priority_enabled">
									<div class="switch-wrap flex items-center gap-2">
										<el-switch v-model="form.config.faq_config.faq_priority_enabled" />
										<div class="field-tip">FAQ 答案将优先于普通文档被引用，提高回答准确性。</div>
									</div>
								</el-form-item>
								<el-form-item
									label="直接问答阈值"
									prop="config.faq_config.faq_direct_answer_threshold"
								>
									<div class="switch-wrap w-full flex items-center gap-3">
										<el-slider
											v-model="form.config.faq_config.faq_direct_answer_threshold"
											:min="0.7"
											:max="1"
											:step="0.1"
											style="width: 50%"
										/>
										<div class="field-tip">当问题与 FAQ 相似度超过此值时，直接使用 FAQ 答案。</div>
									</div>
								</el-form-item>
								<el-form-item label="FAQ 分数加权" prop="config.faq_config.faq_score_boost">
									<div class="switch-wrap w-full flex items-center gap-3">
										<el-slider
											v-model="form.config.faq_config.faq_score_boost"
											:min="1"
											:max="2"
											:step="0.1"
											style="width: 50%"
										/>
										<div class="field-tip">FAQ 结果的相关性分数乘以此系数，使其排序更靠前。</div>
									</div>
								</el-form-item>
							</div>
						</div>
					</el-tab-pane>

					<el-tab-pane v-if="form.mode === 'smart-reasoning'" label="工具配置" name="tools">
						<div class="tab-intro">配置 Agent 可以使用的工具</div>
						<div class="collapse-body">
							<el-form-item label="允许的工具" prop="config.setting_config.allowed_tools">
								<div class="selection-panel">
									<el-checkbox-group
										v-model="form.config.setting_config.allowed_tools"
										class="tool-group-list"
									>
										<div v-for="group in toolList" :key="group.name" class="tool-group-section">
											<div class="tool-group-title">{{ group.name }}</div>
											<div class="tool-group-card">
												<div class="tool-group-card__items">
													<el-checkbox
														v-for="tool in group.tools"
														:key="tool.name"
														:label="tool.name"
													>
														<div class="tool-option">
															<div class="tool-option__label">{{ tool.label }}</div>
															<div v-if="tool.description" class="tool-option__desc">
																{{ tool.description }}
															</div>
														</div>
													</el-checkbox>
												</div>
											</div>
										</div>
									</el-checkbox-group>
								</div>
								<div class="field-tip">选择 Agent 可以使用的工具。</div>
							</el-form-item>
							<el-form-item label="最大迭代次数" prop="config.setting_config.max_iterations">
								<el-input-number
									v-model="form.config.setting_config.max_iterations"
									:min="1"
									:max="50"
									style="width: 100%"
								/>
								<div class="field-tip">Agent 执行任务时的最大推理步骤数。</div>
							</el-form-item>
							<el-form-item label="LLM 调用超时" prop="config.setting_config.llm_call_timeout">
								<el-input-number
									v-model="form.config.setting_config.llm_call_timeout"
									:min="0"
									style="width: 100%"
								/>
								<div class="field-tip">
									单次 LLM 调用的最大等待时间（秒），超过此时间后调用将被中止。
								</div>
							</el-form-item>
							<el-form-item label="MCP 服务" prop="config.setting_config.mcp_services">
								<div class="selection-panel">
									<el-segmented
										v-model="form.config.setting_config.mcp_selection_mode"
										class="selection-segmented"
										:options="selectionMCPOptions"
									/>
									<el-checkbox-group
										v-if="form.config.setting_config.mcp_selection_mode === 'selected'"
										v-model="form.config.setting_config.mcp_services"
										class="checkbox-grid"
									>
										<el-checkbox
											v-for="item in mcpCheckboxOptions"
											:key="item.value"
											:label="item.value"
										>
											{{ item.label }}
										</el-checkbox>
									</el-checkbox-group>
								</div>
								<div class="field-tip">选择 Agent 可以调用的 MCP 服务。</div>
								<div
									v-if="form.config.setting_config.mcp_selection_mode === 'selected'"
									class="field-tip"
								>
									选择要启用的 MCP 服务。
								</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane v-if="form.mode === 'smart-reasoning'" label="技能 Skills" name="skills">
						<div class="tab-intro">
							配置 Agent 可以使用的预装 Skills，提供专业领域知识和工作流程
						</div>
						<div class="collapse-body">
							<el-form-item label="Skills 选择" prop="config.setting_config.selected_skills">
								<div class="selection-panel">
									<el-segmented
										v-model="form.config.setting_config.skills_selection_mode"
										class="selection-segmented"
										:options="selectionMCPOptions"
									/>
									<el-checkbox-group
										v-if="form.config.setting_config.skills_selection_mode === 'selected'"
										v-model="form.config.setting_config.selected_skills"
										class="skill-checkbox-list"
									>
										<el-checkbox
											v-for="item in skillCheckboxOptions"
											:key="item.value"
											:label="item.value"
										>
											<div class="skill-option">
												<div class="skill-option__label">{{ item.label }}</div>
												<div v-if="item.description" class="skill-option__desc">
													{{ item.description }}
												</div>
											</div>
										</el-checkbox>
									</el-checkbox-group>
								</div>
								<div class="field-tip">选择 Agent 可以使用的 Skills 范围。</div>
								<div
									v-if="form.config.setting_config.skills_selection_mode === 'selected'"
									class="field-tip"
								>
									选择要启用的 Skills。
								</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane label="搜索策略" name="search">
						<div class="tab-intro">配置知识库检索和排序的参数</div>
						<div class="collapse-body">
							<el-form-item label="向量召回数量" prop="config.search_config.embedding_top_k">
								<el-input-number
									v-model="form.config.search_config.embedding_top_k"
									:min="1"
									:max="50"
									style="width: 100%"
								/>
								<div class="field-tip">向量检索返回的最大结果数量。</div>
							</el-form-item>
							<el-form-item label="关键词阈值" prop="config.search_config.keyword_threshold">
								<div class="switch-wrap w-full flex items-center gap-3">
									<el-slider
										v-model="form.config.search_config.keyword_threshold"
										:min="0"
										:max="1"
										:step="0.1"
										style="width: 50%"
									/>
									<div class="field-tip">关键词检索的最低相关性分数。</div>
								</div>
							</el-form-item>
							<el-form-item label="向量阈值" prop="config.search_config.vector_threshold">
								<div class="switch-wrap w-full flex items-center gap-3">
									<el-slider
										v-model="form.config.search_config.vector_threshold"
										:min="0"
										:max="1"
										:step="0.1"
										style="width: 50%"
									/>
									<div class="field-tip">向量检索的最低相似度分数。</div>
								</div>
							</el-form-item>
							<el-form-item label="重排数量" prop="config.search_config.rerank_top_k">
								<el-input-number
									v-model="form.config.search_config.rerank_top_k"
									:min="1"
									:max="20"
									style="width: 100%"
								/>
								<div class="field-tip">重排序后保留的最大结果数量。</div>
							</el-form-item>
							<el-form-item label="重排阈值" prop="config.search_config.rerank_threshold">
								<div class="switch-wrap w-full flex items-center gap-3">
									<el-slider
										v-model="form.config.search_config.rerank_threshold"
										:min="-10"
										:max="10"
										:step="0.1"
										style="width: 50%"
									/>
									<div class="field-tip">重排序的最低相关性分数。</div>
								</div>
							</el-form-item>
							<div v-if="form.mode === 'quick-answer'" class="subsection">
								<div class="subsection-title">问答</div>
								<el-form-item label="查询扩展" prop="config.advanced_config.enable_query_expansion">
									<div class="switch-wrap flex items-center gap-2">
										<el-switch v-model="form.config.advanced_config.enable_query_expansion" />
										<div class="field-tip">自动扩展查询词以提高召回率。</div>
									</div>
								</el-form-item>
								<el-form-item label="兜底策略" prop="config.advanced_config.fallback_strategy">
									<el-segmented
										v-model="form.config.advanced_config.fallback_strategy"
										class="selection-segmented"
										:options="fallbackStrategyOptions"
									/>
									<div class="field-tip">当无法从知识库找到相关内容时的处理方式。</div>
								</el-form-item>
								<el-form-item
									v-if="form.config.advanced_config.fallback_strategy === 'model'"
									label="兜底提示词"
									prop="config.advanced_config.fallback_prompt"
								>
									<div class="prompt-field">
										<div class="prompt-toolbar prompt-toolbar--end">
											<el-button
												class="prompt-template-trigger"
												text
												:icon="DocumentCopy"
												@click="openPromptTemplatePicker('fallbackPrompt')"
											>
												模板选择
											</el-button>
										</div>
										<el-input
											v-model="form.config.advanced_config.fallback_prompt"
											type="textarea"
											:rows="3"
											placeholder="请输入模型兜底时使用的提示词"
										/>
									</div>
									<div class="field-tip">
										当无法从知识库找到相关内容时，用于引导模型生成兜底回复。
									</div>
								</el-form-item>
								<el-form-item
									v-else
									label="固定提示词"
									prop="config.advanced_config.fallback_response"
								>
									<el-input
										v-model="form.config.advanced_config.fallback_response"
										type="textarea"
										:rows="3"
										placeholder="请输入固定兜底内容"
									/>
									<div class="field-tip">当无法回答时返回的固定文本。</div>
								</el-form-item>
							</div>
						</div>
					</el-tab-pane>

					<el-tab-pane label="网络搜索" name="web-search">
						<div class="tab-intro">配置智能体的网络搜索能力</div>
						<div class="collapse-body">
							<el-form-item label="网络搜索开启" prop="config.web_search_config.web_search_enabled">
								<div class="switch-wrap flex items-center gap-2">
									<el-switch v-model="form.config.web_search_config.web_search_enabled" />
									<div class="field-tip">启用后智能体可以搜索互联网获取信息。</div>
								</div>
							</el-form-item>
							<el-form-item
								v-if="form.config.web_search_config.web_search_enabled"
								label="选择搜索引擎"
								prop="config.web_search_config.web_search_provider_id"
							>
								<el-select
									v-model="form.config.web_search_config.web_search_provider_id"
									filterable
									remote
									reserve-keyword
									:remote-method="searchWebSearchProviders"
									:loading="webSearchProviderLoading"
									clearable
									placeholder="请输入关键词搜索"
									style="width: 100%"
								>
									<el-option
										v-for="item in webSearchProviderOptions"
										:key="item.value"
										:label="item.label"
										:value="item.value"
									/>
								</el-select>
								<div class="field-tip">为此智能体指定搜索引擎，留空则使用默认搜索引擎。</div>
							</el-form-item>
							<el-form-item
								v-if="form.config.web_search_config.web_search_enabled"
								label="最大搜索结果数"
								prop="config.web_search_config.web_search_max_results"
							>
								<div class="switch-wrap w-full flex items-center gap-3">
									<el-slider
										v-model="form.config.web_search_config.web_search_max_results"
										:min="1"
										:max="10"
										style="width: 50%"
									/>
									<div class="field-tip">每次搜索返回的最大结果数量。</div>
								</div>
							</el-form-item>
							<el-form-item
								v-if="form.config.web_search_config.web_search_enabled"
								label-width="130px"
								label="自动抓取页面内容"
								prop="config.web_search_config.web_fetch_enabled"
							>
								<div class="switch-wrap flex items-center gap-2">
									<el-switch v-model="form.config.web_search_config.web_fetch_enabled" />
									<div class="field-tip">
										ReRank 后自动抓取排名靠前的网页完整内容，提升回答质量。
									</div>
								</div>
							</el-form-item>
							<el-form-item
								v-if="form.config.web_search_config.web_fetch_enabled"
								label="抓取页面数"
								prop="config.web_search_config.web_fetch_top_n"
							>
								<div class="switch-wrap w-full flex items-center gap-3">
									<el-slider
										v-model="form.config.web_search_config.web_fetch_top_n"
										:min="1"
										:max="10"
										style="width: 50%"
									/>
									<div class="field-tip">Rerank 后最多抓取几个网页的完整内容。</div>
								</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane label="多模态" name="multimodal">
						<div class="tab-intro">配置图片上传和视觉语言模型，启用后用户可在对话中上传图片</div>
						<div class="collapse-body">
							<el-form-item label="图片上传" prop="config.img_vlm_config.image_upload_enabled">
								<div class="switch-wrap flex items-center gap-2">
									<el-switch v-model="form.config.img_vlm_config.image_upload_enabled" />
									<div class="field-tip">启用后用户可在对话中上传图片进行多模态问答。</div>
								</div>
							</el-form-item>
							<el-form-item
								v-if="form.config.img_vlm_config.image_upload_enabled"
								label="VLM 模型设置"
								prop="config.img_vlm_config.vlm_model_id"
							>
								<el-select
									v-model="form.config.img_vlm_config.vlm_model_id"
									filterable
									remote
									reserve-keyword
									:remote-method="searchVlmModels"
									:loading="vlmModelsLoading"
									style="width: 100%"
								>
									<el-option
										v-for="model in vlmModels"
										:key="model.id"
										:label="modelLabel(model)"
										:value="model.id"
									/>
								</el-select>
								<div class="field-tip">用于图片分析的视觉语言模型。</div>
							</el-form-item>
							<el-form-item label="语音上传" prop="config.img_vlm_config.audio_upload_enabled">
								<div class="switch-wrap flex items-center gap-2">
									<el-switch v-model="form.config.img_vlm_config.audio_upload_enabled" />
									<div class="field-tip">
										启用后用户可在对话中上传音频文件，系统将使用 ASR 模型自动转录为文字。
									</div>
								</div>
							</el-form-item>
							<el-form-item
								v-if="form.config.img_vlm_config.audio_upload_enabled"
								label="ASR 模型设置"
								prop="config.img_vlm_config.asr_model_id"
							>
								<el-select
									v-model="form.config.img_vlm_config.asr_model_id"
									filterable
									remote
									reserve-keyword
									:remote-method="searchAsrModels"
									:loading="asrModelsLoading"
									clearable
									style="width: 100%"
								>
									<el-option
										v-for="model in asrModels"
										:key="model.id"
										:label="modelLabel(model)"
										:value="model.id"
									/>
								</el-select>
								<div class="field-tip">
									用于音频转录的语音识别模型，未配置时音频文件将以占位符形式传递。
								</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane v-if="form.mode === 'quick-answer'" label="多轮对话" name="multi-turn">
						<div class="tab-intro">配置多轮对话和问题改写相关参数</div>
						<div class="collapse-body">
							<el-form-item label="多轮对话" prop="config.multiple_config.multi_turn_enabled">
								<div class="switch-wrap flex items-center gap-2">
									<el-switch v-model="form.config.multiple_config.multi_turn_enabled" />
									<div class="field-tip">开启后将保留历史对话上下文。</div>
								</div>
							</el-form-item>
							<el-form-item
								v-if="form.config.multiple_config.multi_turn_enabled"
								label="保留轮数"
								prop="config.multiple_config.history_turns"
							>
								<el-input-number
									v-model="form.config.multiple_config.history_turns"
									:min="1"
									:max="20"
									style="width: 100%"
								/>
								<div class="field-tip">保留最近几轮对话作为上下文。</div>
							</el-form-item>
							<div v-if="form.mode === 'quick-answer'">
								<el-form-item label="问题改写" prop="config.advanced_config.enable_rewrite">
									<div class="switch-wrap flex items-center gap-2">
										<el-switch v-model="form.config.advanced_config.enable_rewrite" />
										<div class="field-tip">多轮对话时自动改写用户问题，消解指代和补全省略。</div>
									</div>
								</el-form-item>
								<el-form-item
									v-if="form.config.advanced_config.enable_rewrite"
									label="改写系统提示词"
									prop="config.advanced_config.rewrite_prompt_system"
								>
									<div class="prompt-field">
										<div class="prompt-toolbar">
											<div class="prompt-variable-row">
												<span class="prompt-variable-label">可用变量</span>
												<el-tag
													v-for="variable in rewriteVariables"
													:key="variable"
													class="prompt-variable-tag"
													type="info"
													effect="plain"
													@click="insertPromptVariable('rewritePromptSystem', variable)"
												>
													{{ formatPromptVariable(variable) }}
												</el-tag>
											</div>
											<el-button
												class="prompt-template-trigger"
												text
												:icon="DocumentCopy"
												@click="openPromptTemplatePicker('rewritePromptSystem')"
											>
												模板选择
											</el-button>
										</div>
										<el-input
											ref="rewritePromptSystemInputRef"
											v-model="form.config.advanced_config.rewrite_prompt_system"
											type="textarea"
											:rows="3"
											placeholder="请输入问题改写时的系统提示词"
										/>
									</div>
									<div class="field-tip">用于问题改写的系统提示词。</div>
								</el-form-item>
								<el-form-item
									v-if="form.config.advanced_config.enable_rewrite"
									label="改写用户提示词"
									prop="config.advanced_config.rewrite_prompt_user"
								>
									<div class="prompt-field">
										<div class="prompt-toolbar">
											<div class="prompt-variable-row">
												<span class="prompt-variable-label">可用变量</span>
												<el-tag
													v-for="variable in rewriteVariables"
													:key="variable"
													class="prompt-variable-tag"
													type="info"
													effect="plain"
													@click="insertPromptVariable('rewritePromptUser', variable)"
												>
													{{ formatPromptVariable(variable) }}
												</el-tag>
											</div>
											<el-button
												class="prompt-template-trigger"
												text
												:icon="DocumentCopy"
												@click="openPromptTemplatePicker('rewritePromptUser')"
											>
												模板选择
											</el-button>
										</div>
										<el-input
											ref="rewritePromptUserInputRef"
											v-model="form.config.advanced_config.rewrite_prompt_user"
											type="textarea"
											:rows="3"
											placeholder="请输入问题改写时的用户提示词"
										/>
									</div>
									<div class="field-tip">用于问题改写的用户提示词模板。</div>
								</el-form-item>
							</div>
						</div>
					</el-tab-pane>
				</el-tabs>
			</el-form>
		</div>

		<el-dialog v-model="emojiDialogVisible" title="选择 Emoji 图标" width="520px" append-to-body>
			<div class="emoji-picker-wrap">
				<EmojiPicker
					:native="true"
					:hide-search="false"
					:disable-skin-tones="false"
					:display-recent="true"
					:static-texts="{ placeholder: '搜索 Emoji' }"
					@select="handleEmojiSelect"
				/>
			</div>
		</el-dialog>

		<PromptModal
			v-model="promptTemplateDialogVisible"
			:field="currentPromptField"
			:mode="form.mode"
			@confirm="handlePromptTemplateConfirm"
		/>

		<template #footer>
			<div class="drawer-footer">
				<el-button @click="visible = false">取消</el-button>
				<el-button type="primary" :loading="submitLoading" @click="handleSubmit">保存</el-button>
			</div>
		</template>
	</el-dialog>
</template>

<script setup lang="ts">
import { computed, nextTick, reactive, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { DocumentCopy } from '@element-plus/icons-vue'
import { agentApplication, aiModel, knowledge, resource } from '@repo/api-service'
import EmojiPicker from 'vue3-emoji-picker'
import 'vue3-emoji-picker/css'
import PromptModal, { type PromptFieldKey } from '@/features/PromptModal.vue'
import type {
	AgentFormData,
	AgentItem,
	AgentSelectOption,
	KnowledgeItem,
	McpItem,
	ModelItem,
	SkillItem
} from '../type'

const visible = defineModel<boolean>({ required: true })

const props = defineProps<{
	agentId?: string
}>()

const emit = defineEmits<{
	saved: []
}>()

const activeTab = ref('basic')
const formRef = ref()
const formId = ref('')
const submitLoading = ref(false)
// 统一缓存各类模型选项，按 type 在计算属性中拆分使用。
const modelOptions = ref<ModelItem[]>([])
const chatModelsLoading = ref(false)
const rerankModelsLoading = ref(false)
const vlmModelsLoading = ref(false)
const asrModelsLoading = ref(false)
const kbOptions = ref<KnowledgeItem[]>([])
const kbLoading = ref(false)
const toolList = ref<
	Array<{
		name: string
		tools: {
			description: string
			label: string
			name: string
		}[]
	}>
>([])
const webSearchProviderOptions = ref<AgentSelectOption[]>([])
const webSearchProviderLoading = ref(false)
const mcpServiceOptions = ref<AgentSelectOption[]>([])
const mcpLoading = ref(false)
const skillOptions = ref<AgentSelectOption[]>([])
const skillLoading = ref(false)
const allSkillOptions = ref<AgentSelectOption[]>([])
const emojiDialogVisible = ref(false)
const systemPromptInputRef = ref()
const contextTemplateInputRef = ref()
const rewritePromptSystemInputRef = ref()
const rewritePromptUserInputRef = ref()
const promptTemplateDialogVisible = ref(false)
const currentPromptField = ref<PromptFieldKey>('systemPrompt')
const supportedFileTypes = ['pdf', 'docx', 'txt', 'md', 'csv', 'xlsx', 'jpg']
const selectionModeOptions = [
	{ label: '全部知识库', value: 'all' },
	{ label: '指定知识库', value: 'selected' },
	{ label: '不适用知识库', value: 'none' }
]
const selectionMCPOptions = [
	{ label: '全部', value: 'all' },
	{ label: '指定', value: 'selected' },
	{ label: '禁用', value: 'none' }
]
const fallbackStrategyOptions = [
	{ label: '模型生成', value: 'model' },
	{ label: '固定回复', value: 'fixed' }
]
const smartReasoningSystemPromptVariables = [
	'knowledge_bases',
	'web_search_status',
	'current_time',
	'language'
]
const quickAnswerVariables = ['query', 'contexts', 'current_time', 'current_week', 'language']
const rewriteVariables = ['query', 'conversation', 'current_time', 'yesterday', 'language']

const form = reactive<AgentFormData>({
	name: '',
	description: '',
	avatar: '',
	mode: 'smart-reasoning',
	config: {
		basic_config: {
			system_prompt: '',
			context_template: ''
		},
		model_config: {
			model_id: '',
			rerank_model_id: '',
			temperature: 0.7,
			max_completion_tokens: 2048,
			thinking: false
		},
		setting_config: {
			max_iterations: 10,
			llm_call_timeout: 120,
			allowed_tools: [],
			mcp_selection_mode: 'none',
			mcp_services: [],
			skills_selection_mode: 'none',
			selected_skills: []
		},
		kb_config: {
			kb_selection_mode: 'none',
			knowledge_bases: [],
			retrieve_kb_only_when_mentioned: false,
			supported_file_types: []
		},
		img_vlm_config: {
			image_upload_enabled: false,
			vlm_model_id: '',
			image_storage_provider: '',
			audio_upload_enabled: false,
			asr_model_id: ''
		},
		faq_config: {
			faq_priority_enabled: true,
			faq_direct_answer_threshold: 0.9,
			faq_score_boost: 1.2
		},
		web_search_config: {
			web_search_enabled: true,
			web_search_max_results: 5,
			web_search_provider_id: '',
			web_fetch_enabled: false,
			web_fetch_top_n: 3
		},
		multiple_config: {
			multi_turn_enabled: true,
			history_turns: 5
		},
		search_config: {
			embedding_top_k: 10,
			keyword_threshold: 0.3,
			vector_threshold: 0.5,
			rerank_top_k: 5,
			rerank_threshold: 0.5
		},
		advanced_config: {
			enable_query_expansion: true,
			enable_rewrite: true,
			rewrite_prompt_system: '',
			rewrite_prompt_user: '',
			fallback_strategy: 'model',
			fallback_response: '',
			fallback_prompt: ''
		}
	}
})

const rules = {
	name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
	mode: [{ required: true, message: '请选择模式', trigger: 'change' }],
	'config.basic_config.system_prompt': [
		{ required: true, message: '请输入系统提示词', trigger: 'blur' }
	],
	'config.model_config.model_id': [
		{ required: true, message: '请选择对话模型', trigger: 'change' }
	],
	'config.model_config.rerank_model_id': [
		{ required: true, message: '请选择重排序模型', trigger: 'change' }
	]
}

const chatModels = computed(() => modelOptions.value.filter((item) => item.type === 'KnowledgeQA'))
const rerankModels = computed(() => modelOptions.value.filter((item) => item.type === 'Rerank'))
const vlmModels = computed(() => modelOptions.value.filter((item) => item.type === 'VLLM'))
const asrModels = computed(() =>
	modelOptions.value.filter((item) => ['ASR', 'Asr', 'asr'].includes(item.type || ''))
)
const modelPageSize = 20
const remoteOptionPageSize = 20
const checkboxOptionPageSize = 200
const modelRequestKeyPrefix = 'agent-edit-models'
const selectedEmoji = computed(() => form.avatar || '🙂')
const knowledgeCheckboxOptions = computed<AgentSelectOption[]>(() => {
	const map = new Map<string, AgentSelectOption>()
	kbOptions.value.forEach((item) => {
		if (item.id) {
			map.set(item.id, {
				label: item.name || item.id,
				value: item.id
			})
		}
	})
	form.config.kb_config.knowledge_bases.forEach((value) => {
		if (value && !map.has(value)) {
			map.set(value, {
				label: value,
				value
			})
		}
	})
	return Array.from(map.values())
})
const mcpCheckboxOptions = computed(() =>
	mergeOptions(mcpServiceOptions.value, [], form.config.setting_config.mcp_services)
)
const skillCheckboxOptions = computed(() =>
	mergeOptions(
		allSkillOptions.value.length ? allSkillOptions.value : skillOptions.value,
		[],
		form.config.setting_config.selected_skills
	)
)
const systemPromptVariables = computed(() =>
	form.mode === 'quick-answer' ? quickAnswerVariables : smartReasoningSystemPromptVariables
)
const fieldTabMap: Array<{ match: string | RegExp; tab: string }> = [
	{ match: 'mode', tab: 'basic' },
	{ match: 'name', tab: 'basic' },
	{ match: 'avatar', tab: 'basic' },
	{ match: 'description', tab: 'basic' },
	{ match: /^config\.basic_config\./, tab: 'basic' },
	{ match: 'config.model_config.model_id', tab: 'model' },
	{ match: 'config.model_config.temperature', tab: 'model' },
	{ match: 'config.model_config.thinking', tab: 'model' },
	{ match: 'config.kb_config.knowledge_bases', tab: 'knowledge' },
	{ match: 'config.kb_config.supported_file_types', tab: 'knowledge' },
	{ match: 'config.model_config.rerank_model_id', tab: 'knowledge' },
	{ match: /^config\.faq_config\./, tab: 'knowledge' },
	{ match: 'config.setting_config.allowed_tools', tab: 'tools' },
	{ match: 'config.setting_config.max_iterations', tab: 'tools' },
	{ match: 'config.setting_config.llm_call_timeout', tab: 'tools' },
	{ match: 'config.setting_config.mcp_services', tab: 'tools' },
	{ match: 'config.setting_config.selected_skills', tab: 'skills' },
	{ match: /^config\.search_config\./, tab: 'search' },
	{ match: 'config.advanced_config.enable_query_expansion', tab: 'search' },
	{ match: 'config.advanced_config.fallback_strategy', tab: 'search' },
	{ match: 'config.advanced_config.fallback_prompt', tab: 'search' },
	{ match: 'config.advanced_config.fallback_response', tab: 'search' },
	{ match: /^config\.web_search_config\./, tab: 'web-search' },
	{ match: /^config\.img_vlm_config\./, tab: 'multimodal' },
	{ match: /^config\.multiple_config\./, tab: 'multi-turn' },
	{ match: 'config.advanced_config.enable_rewrite', tab: 'multi-turn' },
	{ match: 'config.advanced_config.rewrite_prompt_system', tab: 'multi-turn' },
	{ match: 'config.advanced_config.rewrite_prompt_user', tab: 'multi-turn' }
]

function modelLabel(item: ModelItem) {
	return item.title ? `${item.title} (${item.name})` : item.name
}

function resolveFieldTab(prop: string) {
	for (const item of fieldTabMap) {
		if (typeof item.match === 'string' && item.match === prop) return item.tab
		if (item.match instanceof RegExp && item.match.test(prop)) return item.tab
	}
	return 'basic'
}

async function revealFirstInvalidField(invalidFields?: Record<string, unknown>) {
	const firstProp = Object.keys(invalidFields || {})[0]
	if (!firstProp) return
	activeTab.value = resolveFieldTab(firstProp)
	await nextTick()
	formRef.value?.scrollToField?.(firstProp, {
		behavior: 'smooth',
		block: 'center'
	})
}

function handleEmojiSelect(emoji: { i?: string }) {
	form.avatar = emoji.i || ''
	emojiDialogVisible.value = false
}

function clearEmoji() {
	form.avatar = ''
}

async function openPromptTemplatePicker(field: PromptFieldKey) {
	currentPromptField.value = field
	promptTemplateDialogVisible.value = true
}

function handlePromptTemplateConfirm(content: string) {
	switch (currentPromptField.value) {
		case 'systemPrompt':
			form.config.basic_config.system_prompt = content
			break
		case 'contextTemplate':
			form.config.basic_config.context_template = content
			break
		case 'rewritePromptSystem':
			form.config.advanced_config.rewrite_prompt_system = content
			break
		case 'rewritePromptUser':
			form.config.advanced_config.rewrite_prompt_user = content
			break
		case 'fallbackPrompt':
			form.config.advanced_config.fallback_prompt = content
			break
	}
}

function formatPromptVariable(variable: string) {
	return `{{${variable}}}`
}

async function insertPromptVariable(
	field: 'systemPrompt' | 'contextTemplate' | 'rewritePromptSystem' | 'rewritePromptUser',
	variable: string
) {
	const variableText = formatPromptVariable(variable)
	const fieldMap = {
		systemPrompt: {
			get value() {
				return form.config.basic_config.system_prompt
			},
			set value(value: string) {
				form.config.basic_config.system_prompt = value
			},
			ref: systemPromptInputRef
		},
		contextTemplate: {
			get value() {
				return form.config.basic_config.context_template
			},
			set value(value: string) {
				form.config.basic_config.context_template = value
			},
			ref: contextTemplateInputRef
		},
		rewritePromptSystem: {
			get value() {
				return form.config.advanced_config.rewrite_prompt_system
			},
			set value(value: string) {
				form.config.advanced_config.rewrite_prompt_system = value
			},
			ref: rewritePromptSystemInputRef
		},
		rewritePromptUser: {
			get value() {
				return form.config.advanced_config.rewrite_prompt_user
			},
			set value(value: string) {
				form.config.advanced_config.rewrite_prompt_user = value
			},
			ref: rewritePromptUserInputRef
		}
	}[field]
	const textarea = fieldMap.ref.value?.textarea as HTMLTextAreaElement | undefined
	if (!textarea || typeof textarea.selectionStart !== 'number') {
		fieldMap.value = `${fieldMap.value || ''}${variableText}`
		await nextTick()
		fieldMap.ref.value?.focus?.()
		return
	}
	const currentValue = fieldMap.value || ''
	const start = textarea.selectionStart
	const end = textarea.selectionEnd
	fieldMap.value = `${currentValue.slice(0, start)}${variableText}${currentValue.slice(end)}`
	await nextTick()
	fieldMap.ref.value?.focus?.()
	const cursorPosition = start + variableText.length
	textarea.setSelectionRange(cursorPosition, cursorPosition)
}

function mergeOptions(
	current: AgentSelectOption[],
	items: AgentSelectOption[],
	selectedValues: string[] = []
) {
	const map = new Map<string, AgentSelectOption>()
	current.forEach((item) => {
		if (item.value) {
			map.set(item.value, item)
		}
	})
	items.forEach((item) => {
		if (item.value) {
			map.set(item.value, item)
		}
	})
	selectedValues.forEach((value) => {
		if (value && !map.has(value)) {
			map.set(value, {
				label: value,
				value
			})
		}
	})
	return Array.from(map.values())
}

function mergeModelOptions(items: ModelItem[]) {
	const map = new Map<string, ModelItem>()
	modelOptions.value.forEach((item) => {
		if (item.id) {
			map.set(item.id, item)
		}
	})
	items.forEach((item) => {
		if (item.id) {
			map.set(item.id, item)
		}
	})
	return Array.from(map.values())
}

function filterLocalOptions(source: AgentSelectOption[], keyword: string) {
	const normalizedKeyword = keyword.trim().toLowerCase()
	if (!normalizedKeyword) {
		return source.slice(0, remoteOptionPageSize)
	}
	return source
		.filter((item) => {
			const label = item.label?.toLowerCase() || ''
			const value = item.value?.toLowerCase() || ''
			const description = item.description?.toLowerCase() || ''
			return (
				label.includes(normalizedKeyword) ||
				value.includes(normalizedKeyword) ||
				description.includes(normalizedKeyword)
			)
		})
		.slice(0, remoteOptionPageSize)
}

function normalizeSelectionMode(mode?: string, selectedValues: string[] = []) {
	if (mode === 'all' || mode === 'none' || mode === 'selected') return mode
	if (mode === 'select') return 'selected'
	return selectedValues.length ? 'selected' : 'none'
}

function normalizeFallbackStrategy(strategy?: string) {
	return strategy === 'fixed' ? 'fixed' : 'model'
}

function syncSelectionValues(mode: string, allValues: string[], currentValues: string[]) {
	if (mode === 'all') {
		return Array.from(new Set(allValues))
	}
	if (mode === 'none') {
		return []
	}
	return currentValues
}

function buildSubmitConfig() {
	return {
		...form.config,
		setting_config: {
			...form.config.setting_config,
			mcp_services:
				form.config.setting_config.mcp_selection_mode === 'selected'
					? [...form.config.setting_config.mcp_services]
					: [],
			selected_skills:
				form.config.setting_config.skills_selection_mode === 'selected'
					? [...form.config.setting_config.selected_skills]
					: []
		},
		kb_config: {
			...form.config.kb_config,
			knowledge_bases:
				form.config.kb_config.kb_selection_mode === 'selected'
					? [...form.config.kb_config.knowledge_bases]
					: []
		}
	}
}

async function fetchModels(keyword = '', type = '') {
	const res = await aiModel.postModelPageList(
		{
			keyword: keyword.trim(),
			type,
			source: '',
			pageIndex: 1,
			pageSize: modelPageSize
		},
		{
			requestKey: `${modelRequestKeyPrefix}-${type || 'all'}`
		}
	)
	if (res.isSuccess) {
		modelOptions.value = mergeModelOptions((res.result?.model || []) as ModelItem[])
	}
}

async function loadModels() {
	await Promise.all([
		fetchModels('', 'KnowledgeQA'),
		fetchModels('', 'Rerank'),
		fetchModels('', 'VLLM'),
		fetchModels('', 'ASR')
	])
}

async function searchChatModels(keyword: string) {
	chatModelsLoading.value = true
	try {
		await fetchModels(keyword, 'KnowledgeQA')
	} finally {
		chatModelsLoading.value = false
	}
}

async function searchRerankModels(keyword: string) {
	rerankModelsLoading.value = true
	try {
		await fetchModels(keyword, 'Rerank')
	} finally {
		rerankModelsLoading.value = false
	}
}

async function searchVlmModels(keyword: string) {
	vlmModelsLoading.value = true
	try {
		await fetchModels(keyword, 'VLLM')
	} finally {
		vlmModelsLoading.value = false
	}
}

async function searchAsrModels(keyword: string) {
	asrModelsLoading.value = true
	try {
		await fetchModels(keyword, 'ASR')
	} finally {
		asrModelsLoading.value = false
	}
}

async function loadTools() {
	const res = await agentApplication.postAiAgentGroupTools({})
	if (res.isSuccess) {
		toolList.value = res?.result || []
	}
}

function resetForm() {
	// 新建和切换编辑对象时，统一回到默认表单状态。
	formId.value = ''
	form.name = ''
	form.description = ''
	form.avatar = ''
	form.mode = 'smart-reasoning'
	form.config.basic_config.system_prompt = ''
	form.config.basic_config.context_template = ''
	form.config.model_config.model_id = ''
	form.config.model_config.rerank_model_id = ''
	form.config.model_config.temperature = 0.7
	form.config.model_config.max_completion_tokens = 2048
	form.config.model_config.thinking = false
	form.config.setting_config.max_iterations = 10
	form.config.setting_config.llm_call_timeout = 120
	form.config.setting_config.allowed_tools = []
	form.config.setting_config.mcp_selection_mode = 'none'
	form.config.setting_config.mcp_services = []
	form.config.setting_config.skills_selection_mode = 'none'
	form.config.setting_config.selected_skills = []
	form.config.kb_config.kb_selection_mode = 'none'
	form.config.kb_config.knowledge_bases = []
	form.config.kb_config.retrieve_kb_only_when_mentioned = false
	form.config.kb_config.supported_file_types = []
	form.config.img_vlm_config.image_upload_enabled = false
	form.config.img_vlm_config.vlm_model_id = ''
	form.config.img_vlm_config.image_storage_provider = ''
	form.config.img_vlm_config.audio_upload_enabled = false
	form.config.img_vlm_config.asr_model_id = ''
	form.config.faq_config.faq_priority_enabled = true
	form.config.faq_config.faq_direct_answer_threshold = 0.9
	form.config.faq_config.faq_score_boost = 1.2
	form.config.web_search_config.web_search_enabled = true
	form.config.web_search_config.web_search_max_results = 5
	form.config.web_search_config.web_search_provider_id = ''
	form.config.web_search_config.web_fetch_enabled = false
	form.config.web_search_config.web_fetch_top_n = 3
	form.config.multiple_config.multi_turn_enabled = true
	form.config.multiple_config.history_turns = 5
	form.config.search_config.embedding_top_k = 10
	form.config.search_config.keyword_threshold = 0.3
	form.config.search_config.vector_threshold = 0.5
	form.config.search_config.rerank_top_k = 5
	form.config.search_config.rerank_threshold = 0.5
	form.config.advanced_config.enable_query_expansion = true
	form.config.advanced_config.enable_rewrite = true
	form.config.advanced_config.rewrite_prompt_system = ''
	form.config.advanced_config.rewrite_prompt_user = ''
	form.config.advanced_config.fallback_strategy = 'model'
	form.config.advanced_config.fallback_response = ''
	form.config.advanced_config.fallback_prompt = ''
}

function applyDetail(item: AgentItem) {
	// 详情回填前先清空，避免上一个智能体的配置残留。
	resetForm()
	formId.value = item.id!
	form.name = item.name || ''
	form.description = item.description || ''
	form.avatar = item.avatar || ''
	form.mode = item.mode || 'smart-reasoning'
	form.config.basic_config.system_prompt = item.config?.basic_config?.system_prompt || ''
	form.config.basic_config.context_template = item.config?.basic_config?.context_template || ''
	form.config.model_config.model_id = item.config?.model_config?.model_id || ''
	form.config.model_config.rerank_model_id = item.config?.model_config?.rerank_model_id || ''
	form.config.model_config.temperature = item.config?.model_config?.temperature ?? 0.7
	form.config.model_config.max_completion_tokens =
		item.config?.model_config?.max_completion_tokens ?? 2048
	form.config.model_config.thinking = !!item.config?.model_config?.thinking
	form.config.setting_config.max_iterations = item.config?.setting_config?.max_iterations ?? 10
	form.config.setting_config.llm_call_timeout = item.config?.setting_config?.llm_call_timeout ?? 120
	form.config.setting_config.allowed_tools = item.config?.setting_config?.allowed_tools || []
	form.config.setting_config.mcp_selection_mode = normalizeSelectionMode(
		item.config?.setting_config?.mcp_selection_mode,
		item.config?.setting_config?.mcp_services || []
	)
	form.config.setting_config.mcp_services = item.config?.setting_config?.mcp_services || []
	form.config.setting_config.skills_selection_mode = normalizeSelectionMode(
		item.config?.setting_config?.skills_selection_mode,
		item.config?.setting_config?.selected_skills || []
	)
	form.config.setting_config.selected_skills = item.config?.setting_config?.selected_skills || []
	form.config.kb_config.kb_selection_mode = normalizeSelectionMode(
		item.config?.kb_config?.kb_selection_mode,
		item.config?.kb_config?.knowledge_bases || []
	)
	form.config.kb_config.knowledge_bases = item.config?.kb_config?.knowledge_bases || []
	form.config.kb_config.retrieve_kb_only_when_mentioned =
		!!item.config?.kb_config?.retrieve_kb_only_when_mentioned
	form.config.kb_config.supported_file_types = item.config?.kb_config?.supported_file_types || []
	form.config.img_vlm_config.image_upload_enabled =
		!!item.config?.img_vlm_config?.image_upload_enabled
	form.config.img_vlm_config.vlm_model_id = item.config?.img_vlm_config?.vlm_model_id || ''
	form.config.img_vlm_config.image_storage_provider =
		item.config?.img_vlm_config?.image_storage_provider || ''
	form.config.img_vlm_config.audio_upload_enabled =
		!!item.config?.img_vlm_config?.audio_upload_enabled
	form.config.img_vlm_config.asr_model_id = item.config?.img_vlm_config?.asr_model_id || ''
	form.config.faq_config.faq_priority_enabled =
		item.config?.faq_config?.faq_priority_enabled ?? true
	form.config.faq_config.faq_direct_answer_threshold =
		item.config?.faq_config?.faq_direct_answer_threshold ?? 0.9
	form.config.faq_config.faq_score_boost = item.config?.faq_config?.faq_score_boost ?? 1.2
	form.config.web_search_config.web_search_enabled =
		item.config?.web_search_config?.web_search_enabled ?? true
	form.config.web_search_config.web_search_max_results =
		item.config?.web_search_config?.web_search_max_results ?? 5
	form.config.web_search_config.web_search_provider_id =
		item.config?.web_search_config?.web_search_provider_id || ''
	form.config.web_search_config.web_fetch_enabled =
		!!item.config?.web_search_config?.web_fetch_enabled
	form.config.web_search_config.web_fetch_top_n =
		item.config?.web_search_config?.web_fetch_top_n ?? 3
	form.config.multiple_config.multi_turn_enabled =
		item.config?.multiple_config?.multi_turn_enabled ?? true
	form.config.multiple_config.history_turns = item.config?.multiple_config?.history_turns ?? 5
	form.config.search_config.embedding_top_k = item.config?.search_config?.embedding_top_k ?? 10
	form.config.search_config.keyword_threshold = item.config?.search_config?.keyword_threshold ?? 0.3
	form.config.search_config.vector_threshold = item.config?.search_config?.vector_threshold ?? 0.5
	form.config.search_config.rerank_top_k = item.config?.search_config?.rerank_top_k ?? 5
	form.config.search_config.rerank_threshold = item.config?.search_config?.rerank_threshold ?? 0.5
	form.config.advanced_config.enable_query_expansion =
		item.config?.advanced_config?.enable_query_expansion ?? true
	form.config.advanced_config.enable_rewrite = item.config?.advanced_config?.enable_rewrite ?? true
	form.config.advanced_config.rewrite_prompt_system =
		item.config?.advanced_config?.rewrite_prompt_system || ''
	form.config.advanced_config.rewrite_prompt_user =
		item.config?.advanced_config?.rewrite_prompt_user || ''
	form.config.advanced_config.fallback_strategy = normalizeFallbackStrategy(
		item.config?.advanced_config?.fallback_strategy
	)
	form.config.advanced_config.fallback_response =
		item.config?.advanced_config?.fallback_response || ''
	form.config.advanced_config.fallback_prompt = item.config?.advanced_config?.fallback_prompt || ''

	console.log('applyDetail', item, form)
}

async function loadKnowledgeBases() {
	kbLoading.value = true
	try {
		const res = await knowledge.postKnowledgeBasePageList({
			keyword: '',
			type: '',
			pageIndex: 1,
			pageSize: checkboxOptionPageSize
		})
		if (res.isSuccess) {
			kbOptions.value = mergeKnowledgeOptions((res.result?.model || []) as KnowledgeItem[])
		}
	} finally {
		kbLoading.value = false
	}
}

function mergeKnowledgeOptions(items: KnowledgeItem[]) {
	const map = new Map<string, KnowledgeItem>()
	kbOptions.value.forEach((item) => {
		if (item.id) {
			map.set(item.id, item)
		}
	})
	items.forEach((item) => {
		if (item.id) {
			map.set(item.id, item)
		}
	})
	return Array.from(map.values())
}

async function loadWebSearchProviders() {
	await searchWebSearchProviders('')
}

async function searchWebSearchProviders(keyword: string) {
	webSearchProviderLoading.value = true
	try {
		const res = await resource.postWebSearchPageList({
			keyword: keyword.trim(),
			provider: '',
			pageIndex: 1,
			pageSize: remoteOptionPageSize
		})
		if (res?.isSuccess) {
			webSearchProviderOptions.value = mergeOptions(
				webSearchProviderOptions.value,
				(res.result?.model || []).map((provider) => ({
					label: provider,
					value: provider
				})),
				form.config.web_search_config.web_search_provider_id
					? [form.config.web_search_config.web_search_provider_id]
					: []
			)
		}
	} finally {
		webSearchProviderLoading.value = false
	}
}

async function loadMcpServices() {
	await searchMcpServices('')
}

async function searchMcpServices(keyword: string) {
	mcpLoading.value = true
	try {
		const res = await resource.postMcpPageList({
			keyword: keyword.trim(),
			transport_type: '',
			pageIndex: 1,
			pageSize: keyword.trim() ? remoteOptionPageSize : checkboxOptionPageSize
		})
		if (res?.isSuccess) {
			mcpServiceOptions.value = mergeOptions(
				mcpServiceOptions.value,
				((res.result?.model || []) as McpItem[])
					.filter((item): item is McpItem & { id: string } => !!item.id)
					.map((item) => ({
						label: item.name || item.id,
						value: item.id
					})),
				form.config.setting_config.mcp_services
			)
		}
	} finally {
		mcpLoading.value = false
	}
}

async function loadSkills() {
	skillLoading.value = true
	try {
		const res = await resource.postSkillsList({})
		if (res?.isSuccess) {
			allSkillOptions.value = ((res.result || []) as SkillItem[]).map((item) => ({
				label: item.name,
				value: item.name,
				description: item.description
			}))
			skillOptions.value = mergeOptions(
				skillOptions.value,
				filterLocalOptions(allSkillOptions.value, ''),
				form.config.setting_config.selected_skills
			)
		}
	} finally {
		skillLoading.value = false
	}
}

async function loadDetail(id: string) {
	const res = await agentApplication.postAiAgentInfo({ id })
	if (!res.isSuccess || !res.result) {
		ElMessage.error(res?.error || '详情加载失败')
		return
	}
	applyDetail(res.result as AgentItem)
}

async function handleOpen() {
	console.log('handleOpen', props.agentId)
	loadTools()
	if (props.agentId) {
		await loadDetail(props.agentId)
	} else {
		resetForm()
	}
	await Promise.all([
		loadModels(),
		loadKnowledgeBases(),
		loadWebSearchProviders(),
		loadMcpServices(),
		loadSkills()
	])
}

async function handleSubmit() {
	if (submitLoading.value) return
	submitLoading.value = true
	try {
		await formRef.value?.validate()
	} catch (error: any) {
		await revealFirstInvalidField(error)
		submitLoading.value = false
		return
	}

	try {
		const payload = {
			name: form.name,
			description: form.description,
			avatar: form.avatar,
			mode: form.mode,
			config: buildSubmitConfig()
		}
		if (formId.value) {
			const res = await agentApplication.postAiAgentUpdate({
				id: formId.value,
				...(payload as any)
			})

			if (!res.isSuccess) {
				ElMessage.error(res?.error || '更新失败')
				return
			}
			ElMessage.success('更新成功')
		} else {
			const res = await agentApplication.postAiAgentCreate(payload as any)
			if (!res.isSuccess) {
				ElMessage.error(res?.error || '创建失败')
				return
			}
			ElMessage.success('创建成功')
		}
		visible.value = false
		emit('saved')
	} catch {
		ElMessage.error('Save failed')
	} finally {
		submitLoading.value = false
	}
}

watch(
	() => visible.value,
	(value) => {
		if (!value) {
			formId.value = ''
		}
	}
)

watch(
	() => visible.value,
	() => {
		if (visible.value) {
			handleOpen()
		}
	}
)

watch(
	() => form.mode,
	() => {
		// 模式切换后回到基础信息，避免停留在已被隐藏的分区上。
		activeTab.value = 'basic'
	}
)

watch(
	[
		() => form.config.kb_config.kb_selection_mode,
		() => knowledgeCheckboxOptions.value.map((item) => item.value).join('|')
	],
	([mode]) => {
		form.config.kb_config.knowledge_bases = syncSelectionValues(
			mode as string,
			knowledgeCheckboxOptions.value.map((item) => item.value),
			form.config.kb_config.knowledge_bases
		)
	},
	{ immediate: true }
)

watch(
	[
		() => form.config.setting_config.mcp_selection_mode,
		() => mcpCheckboxOptions.value.map((item) => item.value).join('|')
	],
	([mode]) => {
		form.config.setting_config.mcp_services = syncSelectionValues(
			mode as string,
			mcpCheckboxOptions.value.map((item) => item.value),
			form.config.setting_config.mcp_services
		)
	},
	{ immediate: true }
)

watch(
	[
		() => form.config.setting_config.skills_selection_mode,
		() => skillCheckboxOptions.value.map((item) => item.value).join('|')
	],
	([mode]) => {
		form.config.setting_config.selected_skills = syncSelectionValues(
			mode as string,
			skillCheckboxOptions.value.map((item) => item.value),
			form.config.setting_config.selected_skills
		)
	},
	{ immediate: true }
)
</script>

<style>
.agent-modal {
	--agent-surface: #ffffff;
	--agent-surface-soft: #f7f8fc;
	--agent-border: rgba(148, 163, 184, 0.22);
	--agent-border-strong: rgba(148, 163, 184, 0.38);
	--agent-text: #0f172a;
	--agent-text-soft: #475569;
	--agent-accent: #14532d;
	--agent-shadow: 0 20px 45px rgba(15, 23, 42, 0.08);
	height: 100vh;
	display: flex;
	flex-direction: column;
	background:
		radial-gradient(circle at top left, rgba(20, 83, 45, 0.08), transparent 30%),
		radial-gradient(circle at top right, rgba(15, 23, 42, 0.05), transparent 24%), #eff3f8;

	.el-dialog__body {
		flex: 1;
		overflow: auto;
		padding: 24px;
	}

	.el-dialog__header {
		padding: 20px 24px 0;
	}

	.el-dialog__title {
		font-size: 22px;
		font-weight: 700;
		color: var(--agent-text);
		letter-spacing: -0.02em;
	}

	.el-dialog__footer {
		padding: 0 24px 24px;
	}

	.modal-wrap {
		margin: 0 auto;
		width: min(1360px, 100%);
	}

	.mode-tip p {
		margin: 0;
		max-width: 65ch;
		color: var(--agent-text-soft);
		line-height: 1.7;
		text-wrap: pretty;
	}

	.agent-form {
		max-width: 100%;
	}

	.switch-wrap {
		.field-tip {
			margin-top: 0;
		}
	}

	:deep(.settings-tabs > .el-tabs__header) {
		margin-right: 20px;
	}

	:deep(.settings-tabs > .el-tabs__content) {
		overflow: visible;
	}

	:deep(.settings-tabs .el-tabs__item) {
		height: auto;
		padding: 14px 18px;
		line-height: 1.4;
		border-radius: 12px;
	}

	:deep(.settings-tabs .el-tabs__item.is-active) {
		background: rgba(20, 83, 45, 0.1);
		color: var(--agent-accent);
	}

	:deep(.settings-tabs .el-tab-pane) {
		min-height: calc(100vh - 220px);
		border-radius: 20px;
		border: 1px solid rgba(255, 255, 255, 0.65);
		background:
			linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(248, 250, 252, 0.92)),
			var(--agent-surface);
		box-shadow: var(--agent-shadow);
	}

	.tab-intro {
		padding: 0 20px;
		font-size: 16px;
		color: rgba(0, 0, 0, 0.9);
	}

	.mode-tip {
		margin-bottom: 18px;
		padding: 16px;
		border: 1px solid var(--agent-border);
		border-radius: 12px;
		background: var(--agent-surface-soft);
	}

	.emoji-field {
		display: flex;
		align-items: center;
		gap: 12px;
		flex-wrap: wrap;
	}

	.emoji-trigger {
		min-width: 180px;
		justify-content: flex-start;
	}

	.emoji-preview {
		font-size: 24px;
		line-height: 1;
	}

	.emoji-picker-wrap {
		display: flex;
		justify-content: center;
		padding: 4px 0;
	}

	.emoji-picker-wrap :deep(.v3-emoji-picker) {
		width: 100%;
	}

	.mode-tip__label {
		margin-bottom: 8px;
		font-size: 12px;
		font-weight: 600;
		letter-spacing: 0.04em;
		text-transform: uppercase;
		color: #64748b;
	}

	.subsection {
		margin-top: 12px;
		padding: 16px;
		border: 1px solid var(--agent-border);
		border-radius: 14px;
		background: rgba(247, 248, 252, 0.8);
	}

	.subsection-title {
		margin-bottom: 14px;
		font-size: 14px;
		font-weight: 600;
		color: var(--agent-text);
	}

	.subsection-tip {
		margin: -4px 0 14px;
		font-size: 13px;
		line-height: 1.7;
		color: var(--agent-text-soft);
	}

	.selection-panel {
		display: flex;
		flex-direction: column;
		gap: 14px;
		width: 100%;
	}

	.selection-segmented {
		align-self: flex-start;
		width: fit-content;
		max-width: 100%;
	}

	.selection-segmented :deep(.el-segmented) {
		width: fit-content;
		max-width: 100%;
	}

	.selection-segmented :deep(.el-segmented__group) {
		width: auto;
	}

	.checkbox-grid {
		display: flex;
		flex-wrap: wrap;
		gap: 10px 18px;
		padding: 14px 16px;
		border: 1px solid var(--agent-border);
		border-radius: 14px;
		background: rgba(247, 248, 252, 0.8);
	}

	.checkbox-grid .el-checkbox {
		margin-right: 0;
	}

	.tool-group-list {
		display: flex;
		flex-direction: column;
		gap: 10px;
		width: 100%;
	}

	.tool-group-section {
		display: flex;
		flex-direction: column;
		gap: 8px;
	}

	.tool-group-title {
		padding-left: 2px;
		font-size: 13px;
		font-weight: 600;
		color: #334155;
		margin: 12px 0;
	}

	.tool-group-card {
		padding: 12px 14px;
		border: 1px solid rgba(148, 163, 184, 0.16);
		border-radius: 14px;
		background: rgba(248, 250, 252, 0.52);
	}

	.tool-group-card__items {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 8px 16px;
		margin-bottom: 12px;
	}

	.tool-group-card__items .el-checkbox {
		margin-right: 0;
		align-items: flex-start;
		margin-bottom: 12px;
	}

	.tool-option {
		display: flex;
		flex-direction: column;
		gap: 2px;
		margin-bottom: 12px;
	}

	.tool-option__label {
		font-size: 13px;
		font-weight: 500;
		line-height: 1.5;
		color: var(--agent-text);
	}

	.tool-option__desc {
		font-size: 12px;
		line-height: 1.6;
		color: var(--agent-text-soft);
	}

	.skill-checkbox-list {
		display: flex;
		flex-direction: column;
		gap: 10px;
		padding: 14px 16px;
		border: 1px solid var(--agent-border);
		border-radius: 14px;
		background: rgba(247, 248, 252, 0.8);
	}

	.skill-checkbox-list .el-checkbox {
		margin-right: 0;
		align-items: flex-start;
		margin-bottom: 12px;
		height: auto;
		white-space: normal;
	}

	.skill-checkbox-list :deep(.el-checkbox__label) {
		min-width: 0;
		white-space: normal;
	}

	.skill-option {
		display: flex;
		flex-direction: column;
		gap: 2px;
		min-width: 0;
	}

	.skill-option__label {
		font-size: 13px;
		font-weight: 500;
		line-height: 1.5;
		color: var(--agent-text);
	}

	.skill-option__desc {
		font-size: 12px;
		line-height: 1.6;
		color: var(--agent-text-soft);
		overflow-wrap: anywhere;
		white-space: pre-line;
	}

	.field-tip {
		margin-top: 8px;
		font-size: 13px;
		line-height: 1.7;
		color: var(--agent-text-soft);
	}

	.prompt-field {
		display: flex;
		flex-direction: column;
		gap: 10px;
		width: 100%;
	}

	.prompt-toolbar {
		display: flex;
		align-items: flex-start;
		justify-content: space-between;
		gap: 12px;
		width: 100%;
	}

	.prompt-toolbar--end {
		justify-content: flex-end;
	}

	.prompt-template-trigger {
		flex: 0 0 auto;
		padding: 0;
		height: auto;
	}

	.prompt-variable-row {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: 8px;
		padding: 12px 14px;
		border: 1px solid var(--agent-border);
		border-radius: 12px;
		background: rgba(247, 248, 252, 0.8);
	}

	.prompt-variable-label {
		font-size: 12px;
		font-weight: 600;
		color: #64748b;
	}

	.prompt-variable-tag {
		cursor: pointer;
		user-select: none;
	}

	.collapse-body {
		padding: 20px;
	}

	.drawer-footer {
		display: flex;
		justify-content: flex-end;
		gap: 10px;
		padding-top: 6px;
	}

	@media (max-width: 768px) {
		.el-dialog__body {
			padding: 16px;
		}

		:deep(.settings-tabs) {
			display: block;
		}

		:deep(.settings-tabs > .el-tabs__header) {
			margin-right: 0;
			margin-bottom: 16px;
		}

		.tool-group-card__items {
			grid-template-columns: 1fr;
		}

		.prompt-toolbar {
			flex-direction: column;
		}
	}
}
</style>
