<template>
	<el-dialog
		v-model="drawerVisible"
		:title="editingId ? '编辑知识库' : '新建知识库'"
		@open="handleOpen"
		class="knowledge-modal"
		fullscreen
	>
		<el-scrollbar class="modal-wrap">
			<el-form
				ref="formRef"
				:model="form"
				:rules="rules"
				label-position="left"
				label-width="120px"
				class="knowledge-form"
			>
				<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="type">
								<div class="switch-wrap">
									<el-segmented
										v-model="form.type"
										class="selection-segmented"
										:options="knowledgeTypeOptions"
										@change="handleKnowledgeBaseTypeChange"
									/>
									<div class="field-tip">
										FAQ 类型适合结构化问答数据；文档型支持文件解析与分块。
									</div>
								</div>
							</el-form-item>

							<div v-if="isDocumentType" class="subsection ml-120px mb-16px">
								<div class="subsection-title">索引策略</div>
								<div class="subsection-tip">
									配置文档上传后的处理管道。关键词和向量检索为 RAG 必需项，系统会保持开启。
								</div>
								<div class="index-strategy-list">
									<el-form-item label="知识图谱启用">
										<div class="switch-wrap">
											<el-segmented
												v-model="form.graph_enabled"
												class="selection-segmented"
												:options="booleanSegmentedOptions"
											/>
											<div class="field-tip">开启后可使用图谱关系辅助检索。</div>
										</div>
									</el-form-item>
									<el-form-item label="关键字启用">
										<div class="switch-wrap">
											<el-segmented
												v-model="form.keyword_enabled"
												class="selection-segmented"
												:options="booleanSegmentedOptions"
												disabled
											/>
											<div class="field-tip">RAG 检索必须开启，系统会自动保持为开启状态。</div>
										</div>
									</el-form-item>
									<el-form-item label="向量启用">
										<div class="switch-wrap">
											<el-segmented
												v-model="form.vector_enabled"
												class="selection-segmented"
												:options="booleanSegmentedOptions"
												disabled
											/>
											<div class="field-tip">RAG 检索必须开启，系统会自动保持为开启状态。</div>
										</div>
									</el-form-item>
									<el-form-item label="维基启用">
										<div class="switch-wrap">
											<el-segmented
												v-model="form.wiki_enabled"
												class="selection-segmented"
												:options="booleanSegmentedOptions"
											/>
											<div class="field-tip">开启后可从 Wiki 内容中补充知识来源。</div>
										</div>
									</el-form-item>
								</div>
							</div>

							<el-form-item label="知识库名称" prop="name">
								<el-input v-model="form.name" placeholder="请输入知识库名称" />
							</el-form-item>

							<el-form-item label="知识库描述">
								<el-input
									v-model="form.description"
									type="textarea"
									:rows="3"
									placeholder="请输入知识库描述"
								/>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane label="模型配置" name="model">
						<div class="tab-intro">为知识库选择合适的 AI 模型</div>
						<div class="collapse-body">
							<el-form-item label="LLM大语言模型" prop="summary_model_id">
								<el-select v-model="form.summary_model_id" placeholder="请选择">
									<el-option
										v-for="item in summaryModels"
										:key="item.id"
										:label="buildModelLabel(item)"
										:value="item.id"
									/>
								</el-select>
								<div class="field-tip">用于总结和摘要的大语言模型。</div>
							</el-form-item>
							<el-form-item label="Embedding 嵌入模型" prop="embedding_model_id">
								<el-select v-model="form.embedding_model_id" placeholder="请选择">
									<el-option
										v-for="item in embeddingModels"
										:key="item.id"
										:label="buildModelLabel(item)"
										:value="item.id"
									/>
								</el-select>
								<div class="field-tip">用于文本向量化的嵌入模型。</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane label="向量存储" name="vectorStore">
						<div class="tab-intro">从全局向量存储配置中选择, 可为空, 默认/为空：系统默认。</div>
						<div class="collapse-body">
							<el-form-item label="向量存储">
								<el-select
									v-model="form.vector_store_id"
									placeholder="系统默认"
									clearable
									:disabled="!!editingId"
								>
									<el-option
										v-for="item in vectorStoreOptions"
										:key="item.value"
										:label="item.label"
										:value="item.value"
									/>
								</el-select>
								<div class="field-tip">
									创建后不可更改。如需迁移，请创建一个绑定到目标存储的新 KB 并重新索引。
								</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane v-if="isDocumentType" label="解析引擎" name="parser">
						<div class="tab-intro">为不同文件类型选择文档解析引擎</div>
						<div class="collapse-body">
							<div class="field-tip compact-tip">未配置的文件类型将使用内置解析引擎。</div>
							<div class="parser-rule-list">
								<div
									v-for="rule in form.parser_engine_rules"
									:key="rule.file_types.join(',')"
									class="parser-rule-item"
								>
									<div class="parser-rule-item__types">{{ rule.file_types.join(', ') }}</div>
									<el-select v-model="rule.engine" placeholder="请选择">
										<el-option
											v-for="item in parserEngineOptions"
											:key="item"
											:label="item"
											:value="item"
										/>
									</el-select>
								</div>
							</div>
						</div>
					</el-tab-pane>

					<el-tab-pane v-if="isDocumentType" label="图像处理" name="image">
						<div class="tab-intro">配置图像内容理解能力</div>
						<div class="collapse-body">
							<el-form-item label="多模态功能">
								<div class="switch-wrap">
									<el-segmented
										v-model="form.vlm_enabled"
										class="selection-segmented"
										:options="booleanSegmentedOptions"
									/>
									<div class="field-tip">启用图片等多模态内容的理解能力。</div>
								</div>
							</el-form-item>
							<el-form-item v-if="form.vlm_enabled" label="VLLM视觉模型">
								<el-select v-model="form.vlm_model_id" placeholder="请选择">
									<el-option
										v-for="item in vlmModels"
										:key="item.id"
										:label="buildModelLabel(item)"
										:value="item.id"
									/>
								</el-select>
								<div class="field-tip">用于多模态理解的视觉语言模型（必选）。</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane v-if="isDocumentType" label="音频处理" name="audio">
						<div class="tab-intro">配置语音识别（ASR）</div>
						<div class="collapse-body">
							<div class="field-tip compact-tip">
								启用后可上传音频文件并整段转写为文本（常见格式：mp3、wav、m4a、flac、ogg
								等）。暂不支持视频上传。
							</div>
							<el-form-item label="音频语音识别">
								<div class="switch-wrap">
									<el-segmented
										v-model="form.asr_enabled"
										class="selection-segmented"
										:options="booleanSegmentedOptions"
									/>
									<div class="field-tip">
										启用后可上传音频到知识库，系统自动将语音转写为文本并参与解析与检索。
									</div>
								</div>
							</el-form-item>
							<el-form-item v-if="form.asr_enabled" label="ASR模型">
								<el-select v-model="form.asr_model_id" placeholder="请选择">
									<el-option
										v-for="item in asrModels"
										:key="item.id"
										:label="buildModelLabel(item)"
										:value="item.id"
									/>
								</el-select>
								<div class="field-tip">用于音频中语音转文本的识别模型（如 OpenAI Whisper）。</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane v-if="isDocumentType" label="存储引擎" name="storage">
						<div class="tab-intro">选择文档上传使用的文件存储引擎</div>
						<div class="collapse-body">
							<el-form-item label="存储引擎">
								<el-select v-model="form.storage_provider" placeholder="请选择">
									<el-option
										v-for="item in storageProviderOptions"
										:key="item.value"
										:label="item.label"
										:value="item.value"
									/>
								</el-select>
								<div class="field-tip">
									选择该知识库使用的存储引擎，需在全局设置中已配置对应引擎。
								</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane v-if="isDocumentType" label="分块设置" name="chunk">
						<div class="tab-intro">配置文档分块参数，优化检索效果</div>
						<div class="collapse-body">
							<el-form-item label="分块策略">
								<div class="slider-wrap">
									<div class="field-tip mb-4px mt-0">
										选择文档的分块方式。自动模式会分析每个文档的结构并选择最佳策略。
									</div>
									<el-segmented
										v-model="form.chunk_strategy"
										class="selection-segmented"
										:options="chunkStrategyOptions"
									/>
									<!-- <el-select
										v-model="form.chunk_strategy"
										filterable
										default-first-option
										placeholder="请选择"
										:options="chunkStrategyOptions"
									/> -->
									<div class="field-tip">
										{{ chunkSrategyTip?.[form.chunk_strategy] }}
									</div>
								</div>
							</el-form-item>
							<el-form-item label="分块大小">
								<div class="slider-wrap">
									<el-slider
										v-model="form.chunk_size"
										:min="100"
										:max="4000"
										:step="50"
										show-input
									/>
									<div class="field-tip">控制每个文档分块的字符数（100-4000）。</div>
								</div>
							</el-form-item>
							<el-form-item label="分块重叠">
								<div class="slider-wrap">
									<el-slider
										v-model="form.chunk_overlap"
										:min="0"
										:max="500"
										:step="10"
										show-input
									/>
									<div class="field-tip">相邻文档块之间的重叠字符数（0-500）。</div>
								</div>
							</el-form-item>
							<el-form-item label="分隔符">
								<el-select
									v-model="form.separators"
									multiple
									allow-create
									filterable
									default-first-option
									placeholder="请输入或选择分隔符"
								>
									<el-option
										v-for="item in separatorOptions"
										:key="item"
										:label="`${item.label}(${item.displayValue})`"
										:value="item.value"
									/>
								</el-select>
								<div class="field-tip">文档分块时使用的分隔符。</div>
							</el-form-item>

							<el-form-item label="父子分块">
								<div class="switch-wrap">
									<el-segmented
										v-model="form.enable_parent_child"
										class="selection-segmented"
										:options="booleanSegmentedOptions"
									/>
									<div class="field-tip">
										启用两级父子分块策略。大的父块提供上下文，小的子块用于向量匹配检索。
									</div>
								</div>
							</el-form-item>

							<div v-if="form.enable_parent_child" class="subsection ml-120px">
								<div class="subsection-title">父子分块参数</div>

								<el-form-item label="父块大小">
									<div class="slider-wrap">
										<el-slider
											v-model="form.parent_chunk_size"
											:min="512"
											:max="8192"
											:step="128"
											show-input
										/>
										<div class="field-tip">提供上下文的父块字符数（512-8192）。</div>
									</div>
								</el-form-item>
								<el-form-item label="子块大小">
									<div class="slider-wrap">
										<el-slider
											v-model="form.child_chunk_size"
											:min="64"
											:max="2048"
											:step="64"
											show-input
										/>
										<div class="field-tip">用于向量匹配的子块字符数（64-2048）。</div>
									</div>
								</el-form-item>
							</div>

							<el-collapse class="chunk-advanced-collapse mt-12px" expand-icon-position="left">
								<el-collapse-item title="高级" name="advanced">
									<div class="chunk-advanced-panel">
										<el-form-item label="Token 上限">
											<div class="slider-wrap">
												<el-input-number
													v-model="form.token_limit"
													:min="0"
													:max="8192"
													:step="1"
													style="width: 100%"
												/>
												<div class="field-tip">
													每个分块的硬性 Token 上限（0-8192）。0 = 关闭（仅按字符数）。当嵌入模型
													Token 上限较小时启用：MiniLM (256 tok) 用 200，BGE/Cohere (512 tok) 用
													400。现代嵌入器（OpenAI、Voyage、Jina-v3）支持 &gt;2000 tokens，保持 0
													即可。
												</div>
											</div>
										</el-form-item>

										<el-form-item label="语言提示">
											<div class="switch-wrap">
												<el-select
													v-model="form.languages"
													multiple
													clearable
													collapse-tags
													collapse-tags-tooltip
													placeholder="选择语言提示"
												>
													<el-option
														v-for="item in languageOptions"
														:key="item.value"
														:label="item.label"
														:value="item.value"
													/>
												</el-select>
												<div class="field-tip">
													限制启发式模式只识别选定的语言（DE/EN/ZH）。留空 =
													自动检测。同质化语料库可显式设置以避免跨语言误匹配。
												</div>
											</div>
										</el-form-item>
									</div>
								</el-collapse-item>
							</el-collapse>
						</div>
					</el-tab-pane>

					<el-tab-pane v-if="isDocumentType" label="高级设置" name="advanced">
						<div class="tab-intro">配置问题生成等高级功能</div>
						<div class="collapse-body">
							<el-form-item label="AI 问题生成">
								<div class="switch-wrap">
									<el-segmented
										v-model="form.question_generation_enabled"
										class="selection-segmented"
										:options="booleanSegmentedOptions"
									/>
									<div class="field-tip">
										解析文档时调用大模型为每个分块生成相关问题，提高检索召回率。启用后会增加文档解析耗时。
									</div>
								</div>
							</el-form-item>
							<el-form-item v-if="form.question_generation_enabled" label="生成问题数量">
								<el-input-number
									v-model="form.question_count"
									:min="1"
									:max="10"
									style="width: 100%"
								/>
								<div class="field-tip">每个文档分块生成的问题数量（1-10）。</div>
							</el-form-item>
						</div>
					</el-tab-pane>

					<el-tab-pane v-if="!isDocumentType" label="FAQ设置" name="faq">
						<div class="tab-intro">设置 FAQ 知识库的索引策略和问答组织方式</div>
						<div class="collapse-body">
							<el-form-item label="索引方式">
								<div class="switch-wrap">
									<el-segmented
										v-model="form.faq_index_mode"
										class="selection-segmented"
										:options="faqIndexModeOptions"
									/>
									<div class="field-tip">仅索引问题可提升精度，索引问答可提高召回率。</div>
								</div>
							</el-form-item>
							<el-form-item label="问题索引方式">
								<div class="switch-wrap">
									<el-segmented
										v-model="form.faq_question_index_mode"
										class="selection-segmented"
										:options="faqQuestionIndexModeOptions"
									/>
									<div class="field-tip">
										合并索引：标准问和相似问合并索引；分别索引：标准问和每个相似问独立索引，检索更精确但需要更多存储。
									</div>
								</div>
							</el-form-item>
						</div>
					</el-tab-pane>
				</el-tabs>
			</el-form>
		</el-scrollbar>

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

<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { aiModel, knowledge, storageProvider, vector } from '@repo/api-service'
import type { KnowledgeBaseForm, KnowledgeModelOption, ParserEngineRule } from '../types'

const emit = defineEmits<{ (e: 'refresh'): void }>()

const submitLoading = ref(false)
const drawerVisible = ref(false)
const editingId = ref('')
const activeTab = ref('basic')
const modelList = ref<KnowledgeModelOption[]>([])
const formRef = ref()

const DEFAULT_PARSER_RULES: ParserEngineRule[] = [
	{ engine: 'builtin', file_types: ['pdf'] },
	{ engine: 'builtin', file_types: ['docx', 'doc'] },
	{ engine: 'markitdown', file_types: ['pptx', 'ppt'] },
	{ engine: 'builtin', file_types: ['xlsx', 'xls'] },
	{ engine: 'simple', file_types: ['csv'] },
	{ engine: 'builtin', file_types: ['md', 'markdown'] },
	{ engine: 'simple', file_types: ['txt'] },
	{ engine: 'simple', file_types: ['json'] },
	{ engine: 'builtin', file_types: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'webp'] },
	{ engine: 'simple', file_types: ['mp3', 'wav', 'm4a', 'flac', 'ogg'] }
]

const separatorOptions = [
	{ label: '双换行', value: '\n\n', displayValue: '\\n\\n' },
	{ label: '单换行', value: '\n', displayValue: '\\n' },
	{ label: '中文句号', value: '。', displayValue: '。' },
	{ label: '感叹号', value: '！', displayValue: '！' },
	{ label: '问号', value: '？', displayValue: '？' },
	{ label: '英文分号', value: ';', displayValue: ';' },
	{ label: '中文分号', value: '；', displayValue: '；' },
	{ label: '空格', value: ' ', displayValue: ' ' }
]
// 默认不选空格
const DEFAULT_SEPARATORS = separatorOptions.map((item) => item.value).filter((item) => item !== ' ')
const parserEngineOptions = ['builtin', 'markitdown', 'simple']
const languageOptions = [
	{ label: '中文', value: 'zh' },
	{ label: '英语', value: 'en' },
	{ label: '德语', value: 'de' }
]
const storageProviderOptions = ref<{ label: string; value: string }[]>([])
const vectorStoreOptions = ref<{ label: string; value: string }[]>([])
const knowledgeTypeOptions = [
	{ label: '文档', value: 'document' },
	{ label: '问答', value: 'faq' }
]
const booleanSegmentedOptions = [
	{ label: '开启', value: true },
	{ label: '关闭', value: false }
]
const faqIndexModeOptions = [
	{ label: '仅索引问题', value: 'question_only' },
	{ label: '索引问答', value: 'question_answer' }
]
const faqQuestionIndexModeOptions = [
	{ label: '合并索引', value: 'combined' },
	{ label: '分别索引', value: 'separate' }
]

function cloneParserRules(rules?: ParserEngineRule[]) {
	return (rules || DEFAULT_PARSER_RULES).map((rule) => ({
		engine: rule.engine,
		file_types: [...rule.file_types]
	}))
}

const createDefaultForm = (): KnowledgeBaseForm => ({
	name: '',
	description: '',
	type: 'document',
	embedding_model_id: '',
	summary_model_id: '',
	faq_index_mode: 'question_only',
	faq_question_index_mode: 'separate',
	vlm_enabled: true,
	vlm_model_id: '',
	asr_enabled: false,
	asr_model_id: '',
	asr_language: '',
	graph_enabled: false,
	keyword_enabled: true,
	vector_enabled: true,
	wiki_enabled: false,
	question_generation_enabled: true,
	question_count: 3,
	chunk_strategy: 'auto',
	chunk_size: 512,
	chunk_overlap: 100,
	separators: [...DEFAULT_SEPARATORS],
	parser_engine_rules: cloneParserRules(),
	enable_parent_child: true,
	parent_chunk_size: 4096,
	child_chunk_size: 384,
	token_limit: 0,
	languages: [],
	storage_provider: 'local',
	vector_store_id: '',
	wiki_extraction_granularity: 'standard',
	wiki_max_pages_per_ingest: 0,
	wiki_synthesis_model_id: ''
})

const chunkStrategyOptions = [
	{
		label: '自动',
		value: 'auto'
	},
	{
		label: '按标题切分',
		value: 'heading'
	},
	{
		label: '结构感知',
		value: 'heuristic'
	},
	{
		label: '按长度切分',
		value: 'legacy'
	}
]

const chunkSrategyTip = {
	auto: '文档分析器根据内容结构自动在「按标题切分」「结构感知」「按长度切分」之间选择。',
	heading:
		'在 Markdown 标题（#、##、###）边界处切分，每块自动带上所在标题路径。适合结构清晰的 Markdown 文档。',
	heuristic:
		'识别分页符、编号章节、多语言章节标记（DE/EN/ZH）、全大写标题等结构信号进行切分。适合没有 Markdown 标题的 PDF / 扫描件。',
	legacy: '忽略结构，仅按字符数和分隔符递归切分——原始行为。当上述策略对你的内容效果不佳时使用。'
}

const form = reactive<KnowledgeBaseForm>(createDefaultForm())

const embeddingModels = computed(() => modelList.value.filter((item) => item.type === 'Embedding'))
const summaryModels = computed(() => modelList.value.filter((item) => item.type === 'KnowledgeQA'))
const vlmModels = computed(() => modelList.value.filter((item) => item.type === 'VLLM'))
const asrModels = computed(() =>
	modelList.value.filter((item) => ['ASR', 'Asr', 'asr'].includes(item.type))
)
const isDocumentType = computed(() => form.type === 'document')

async function fetchModels() {
	const res = await aiModel.postModelPageList({
		keyword: '',
		type: '',
		source: '',
		pageIndex: 1,
		pageSize: 200
	})
	if (res?.isSuccess) {
		modelList.value = (res.result?.model || []) as KnowledgeModelOption[]
		applyModelDefaults()
	}
}

async function fetchStorageProviders() {
	const res = await storageProvider.postAiStorageProviderEngines({})
	if (res?.isSuccess) {
		storageProviderOptions.value = (res.result || [])
			.filter((item) => {
				return item.allowed && item.available
			})
			.map((item) => ({ label: item.name, value: item.name }))
		applyModelDefaults()
	}
}

async function fetchVectorStores() {
	try {
		const res = await vector.postPageList({ keyword: '', pageIndex: 1, pageSize: 200 })
		if (res?.isSuccess && res.result) {
			const data = (res.result as any)?.model
			const items = Array.isArray(data) ? data : data?.list || data?.items || data?.data || []
			vectorStoreOptions.value = items.map((item: any) => ({
				label: item.name || item.display_name || item.id,
				value: item.id
			}))
		}
	} catch {
		// silent
	}
}

function applyModelDefaults() {
	if (!form.embedding_model_id && embeddingModels.value.length) {
		form.embedding_model_id = embeddingModels.value[0]!.id
	}
	if (!form.summary_model_id && summaryModels.value.length) {
		form.summary_model_id = summaryModels.value[0]!.id
	}
	if (!form.wiki_synthesis_model_id && summaryModels.value.length) {
		form.wiki_synthesis_model_id = summaryModels.value[0]!.id
	}
	if (vlmModels.value.length) {
		if (!form.vlm_model_id) form.vlm_model_id = vlmModels.value[0]!.id
	} else {
		form.vlm_enabled = false
		form.vlm_model_id = ''
	}
	if (asrModels.value.length) {
		if (!form.asr_model_id) form.asr_model_id = asrModels.value[0]!.id
	} else {
		form.asr_enabled = false
		form.asr_model_id = ''
		form.asr_language = ''
	}
}

async function hydrateSelectedModels() {
	const selectedIds = [
		form.embedding_model_id,
		form.summary_model_id,
		form.vlm_model_id,
		form.asr_model_id,
		form.wiki_synthesis_model_id
	].filter(Boolean)
	const missingIds = Array.from(new Set(selectedIds)).filter(
		(id) => !modelList.value.some((item) => item.id === id)
	)
	if (!missingIds.length) return
	const results = await Promise.all(
		missingIds.map((id) => aiModel.postModelInfo({ id }).catch(() => null))
	)
	const hydratedModels = results
		.filter((res): res is NonNullable<typeof res> => !!res?.isSuccess && !!res.result)
		.map((res) => res.result as KnowledgeModelOption)
	if (hydratedModels.length) {
		modelList.value = [...modelList.value, ...hydratedModels].filter(
			(item, index, list) => list.findIndex((candidate) => candidate.id === item.id) === index
		)
	}
}

const rules = {
	name: [{ required: true, message: '请输入知识库名称', trigger: 'blur' }],
	type: [{ required: true, message: '请选择知识库类型', trigger: 'change' }],
	embedding_model_id: [{ required: true, message: '请选择 Embedding 模型', trigger: 'change' }],
	summary_model_id: [{ required: true, message: '请选择摘要模型', trigger: 'change' }]
}

function buildModelLabel(item: KnowledgeModelOption) {
	const title = item.title?.trim()
	return title ? `${title} (${item.name})` : item.name
}

function handleKnowledgeBaseTypeChange(type: KnowledgeBaseForm['type']) {
	activeTab.value = 'basic'
	if (type === 'faq') {
		form.graph_enabled = false
		form.keyword_enabled = true
		form.vector_enabled = true
		form.wiki_enabled = false
		form.vlm_enabled = false
		form.asr_enabled = false
		form.question_generation_enabled = false
		form.faq_index_mode = 'question_only'
		form.faq_question_index_mode = 'separate'
		return
	}

	form.graph_enabled = false
	form.keyword_enabled = true
	form.vector_enabled = true
	form.wiki_enabled = false
	form.question_generation_enabled = true
	form.question_count = 3
	form.chunk_size = 512
	form.chunk_overlap = 100
	form.separators = [...DEFAULT_SEPARATORS]
	form.parser_engine_rules = cloneParserRules()
	form.enable_parent_child = true
	form.parent_chunk_size = 4096
	form.child_chunk_size = 384
	form.token_limit = 0
	form.languages = []
	form.storage_provider = 'local'
	form.vector_store_id = ''
	form.wiki_extraction_granularity = 'standard'
	form.wiki_max_pages_per_ingest = 0
	applyModelDefaults()
}

function resetForm() {
	Object.assign(form, createDefaultForm())
	activeTab.value = 'basic'
	applyModelDefaults()
}

function handleOpen() {
	activeTab.value = 'basic'
}

function openCreateDrawer() {
	editingId.value = ''
	resetForm()
	drawerVisible.value = true
}

async function openEditDrawer(id: string) {
	editingId.value = id
	resetForm()
	const res = await knowledge.postAiKnowledgeBaseInfo({ id })
	if (!res?.isSuccess) return

	const detail = res.result
	const chunkingConfig = (detail.chunking_config || {}) as {
		strategy?: KnowledgeBaseForm['chunk_strategy']
		chunk_size?: number
		chunk_overlap?: number
		separators?: string[]
		parser_engine_rules?: ParserEngineRule[]
		enable_parent_child?: boolean
		parent_chunk_size?: number
		child_chunk_size?: number
		tokenLimit?: number
		languages?: string[]
	}
	Object.assign(form, {
		name: detail.name,
		description: detail.description || '',
		type: (detail.type || 'document') as KnowledgeBaseForm['type'],
		embedding_model_id: detail.embedding_model_id || '',
		summary_model_id: detail.summary_model_id || '',
		faq_index_mode: detail.faq_config?.index_mode || 'question_only',
		faq_question_index_mode: detail.faq_config?.question_index_mode || 'separate',
		vlm_enabled: detail.vlm_config?.enabled ?? false,
		vlm_model_id: detail.vlm_config?.model_id || '',
		asr_enabled: detail.asr_config?.enabled ?? false,
		asr_model_id: detail.asr_config?.model_id || '',
		asr_language: detail.asr_config?.language || '',
		graph_enabled: detail.indexing_strategy?.graph_enabled ?? false,
		keyword_enabled: true,
		vector_enabled: true,
		wiki_enabled: detail.indexing_strategy?.wiki_enabled ?? false,
		question_generation_enabled: detail.question_generation_config?.enabled ?? true,
		question_count: detail.question_generation_config?.question_count ?? 3,
		chunk_strategy: chunkingConfig.strategy ?? 'auto',
		chunk_size: chunkingConfig.chunk_size ?? 512,
		chunk_overlap: chunkingConfig.chunk_overlap ?? 100,
		separators: chunkingConfig.separators?.length
			? [...chunkingConfig.separators]
			: [...DEFAULT_SEPARATORS],
		parser_engine_rules: cloneParserRules(chunkingConfig.parser_engine_rules),
		enable_parent_child: chunkingConfig.enable_parent_child ?? true,
		parent_chunk_size: chunkingConfig.parent_chunk_size ?? 4096,
		child_chunk_size: chunkingConfig.child_chunk_size ?? 384,
		token_limit: chunkingConfig.tokenLimit ?? 0,
		languages: chunkingConfig.languages?.length ? [...chunkingConfig.languages] : [],
		storage_provider:
			detail.storage_provider_config?.provider || detail.storage_config?.provider || 'local',
		vector_store_id: detail.vector_store_id || '',
		wiki_extraction_granularity: detail.wiki_config?.extraction_granularity || 'standard',
		wiki_max_pages_per_ingest: detail.wiki_config?.max_pages_per_ingest ?? 0,
		wiki_synthesis_model_id: detail.wiki_config?.synthesis_model_id || ''
	})
	await hydrateSelectedModels()
	applyModelDefaults()
	drawerVisible.value = true
}

function buildCommonPayload() {
	const keywordEnabled = true
	const vectorEnabled = true
	const wikiEnabled = form.wiki_enabled
	const vlmEnabled = vectorEnabled && form.vlm_enabled
	const asrEnabled = vectorEnabled && form.asr_enabled
	const questionGenerationEnabled = vectorEnabled && form.question_generation_enabled

	return {
		name: form.name,
		description: form.description,
		indexing_strategy: {
			graph_enabled: form.graph_enabled,
			keyword_enabled: keywordEnabled,
			vector_enabled: vectorEnabled,
			wiki_enabled: wikiEnabled
		},
		embedding_model_id: form.embedding_model_id,
		summary_model_id: form.summary_model_id,
		wiki_config: {
			extraction_granularity: form.wiki_extraction_granularity,
			max_pages_per_ingest: form.wiki_max_pages_per_ingest,
			synthesis_model_id: wikiEnabled
				? form.wiki_synthesis_model_id || form.summary_model_id
				: form.summary_model_id
		},
		chunking_config: {
			strategy: form.chunk_strategy,
			chunk_size: form.chunk_size,
			chunk_overlap: form.chunk_overlap,
			separators: form.separators.length ? form.separators : [...DEFAULT_SEPARATORS],
			parser_engine_rules: cloneParserRules(form.parser_engine_rules),
			enable_parent_child: form.enable_parent_child,
			parent_chunk_size: form.parent_chunk_size,
			child_chunk_size: form.child_chunk_size,
			tokenLimit: form.token_limit,
			languages: [...form.languages]
		},
		vlm_config: {
			model_id: vlmEnabled ? form.vlm_model_id : '',
			enabled: vlmEnabled
		},
		asr_config: {
			model_id: asrEnabled ? form.asr_model_id : '',
			language: asrEnabled ? form.asr_language : '',
			enabled: asrEnabled
		},
		storage_provider_config: {
			provider: form.storage_provider
		},
		storage_config: {
			provider: form.storage_provider
		},
		question_generation_config: {
			enabled: questionGenerationEnabled,
			question_count: form.question_count
		},
		vector_store_id: form.vector_store_id || undefined
	}
}

function buildPayload() {
	const commonPayload = buildCommonPayload()

	if (form.type === 'faq') {
		return {
			...commonPayload,
			type: form.type,
			faq_config: {
				index_mode: form.faq_index_mode,
				question_index_mode: form.faq_question_index_mode
			}
		}
	}

	return {
		...commonPayload,
		type: form.type
	}
}

async function formValidate(formInstance: any) {
	return formInstance
		?.validate()
		.then(() => true)
		.catch(() => false)
}

async function submitForm() {
	const valid = await formValidate(formRef.value)
	if (!valid) return

	submitLoading.value = true
	try {
		const payload = buildPayload()
		if (editingId.value) {
			await knowledge.postAiKnowledgeBaseUpdate({
				id: editingId.value,
				...(payload as any)
			} as any)
			ElMessage.success('知识库已更新')
		} else {
			await knowledge.postAiKnowledgeBaseCreate(payload as any)
			ElMessage.success('知识库已创建')
		}
		drawerVisible.value = false
		emit('refresh')
	} catch {
		ElMessage.error('保存失败')
	} finally {
		submitLoading.value = false
	}
}

defineExpose({
	openCreateDrawer,
	openEditDrawer,
	resetForm,
	close: () => {
		resetForm()
		drawerVisible.value = false
	}
})

onMounted(async () => {
	await fetchModels()
	await fetchStorageProviders()
	await fetchVectorStores()
	resetForm()
})
</script>

<style lang="less">
.knowledge-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%);
	}

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

	: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: var(--text-strong);
	}

	.collapse-body {
		padding: 20px;
	}

	.switch-wrap,
	.slider-wrap {
		width: 100%;
	}

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

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

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

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

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

	.compact-tip {
		margin-bottom: 16px;
	}

	.index-strategy-list {
		display: grid;
		gap: 10px;
		margin-top: 16px;
	}

	.form-grid {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 0 12px;
	}

	.subsection {
		margin-top: 12px;
		padding: 16px;
		border: 1px solid var(--agent-border);
		border-radius: 14px;
		background: var(--bg-container);
	}

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

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

	.chunk-advanced-collapse {
		margin-left: 120px;
	}

	.chunk-advanced-panel {
		padding-top: 12px;
	}

	.parser-rule-list {
		display: grid;
		gap: 12px;
	}

	.parser-rule-item {
		display: grid;
		grid-template-columns: minmax(0, 1fr) 220px;
		gap: 12px;
		align-items: center;
	}

	.parser-rule-item__types {
		padding: 10px 14px;
		border: 1px solid var(--agent-border);
		border-radius: 12px;
		background: var(--bg-container);
		color: var(--agent-text);
		line-height: 1.5;
	}

	.separator-grid {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 10px;
	}

	.separator-chip {
		display: inline-flex;
		align-items: center;
		justify-content: space-between;
		gap: 8px;
		width: 100%;
		padding: 10px 12px;
		border: 1px solid var(--agent-border);
		border-radius: 10px;
		background: var(--bg-container);
		color: var(--agent-text);
		font-size: 13px;
		text-align: left;
		cursor: pointer;
		transition: all 0.2s ease;
	}

	.separator-chip:hover {
		border-color: var(--agent-border-strong);
		background: var(--bg-container);
	}

	.separator-chip--active {
		border-color: rgba(20, 83, 45, 0.35);
		background: rgba(20, 83, 45, 0.08);
		color: var(--agent-accent);
	}

	.separator-chip__value {
		font-size: 12px;
		color: var(--agent-text-soft);
	}

	.separator-chip__close {
		flex-shrink: 0;
		font-size: 16px;
		line-height: 1;
		opacity: 0.6;
	}

	.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;
		}

		.form-grid,
		.parser-rule-item,
		.separator-grid {
			grid-template-columns: 1fr;
		}
	}
}
</style>
