<template>
	<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :width="800" :close-on-click-modal="false" draggable :destroy-on-close="true" class="dark:bg-gray-800">
		<el-form
			ref="dataFormRef"
			:model="form"
			:rules="dataRules"
			formDialogRef
			@submit.prevent
			label-width="90px"
			v-loading="loading"
			class="dark:text-gray-300"
		>
			<el-collapse v-model="activeNames" class="dark:border-gray-700">
				<el-row :gutter="24">
					<el-col :span="12" class="mt-8 mb20">
						<el-form-item label="知识库" prop="datasetId" class="dark:text-gray-300">
							<el-select v-model="form.datasetId" placeholder="请选择知识库" class="dark:bg-gray-700">
								<el-option v-for="item in datasetList" :key="item.id" :label="item.name" :value="item.id" class="dark:hover:bg-gray-600" />
							</el-select>
						</el-form-item>
					</el-col>
					<el-col :span="12" class="mt-8 mb20">
						<el-form-item label="来源" prop="sourceType" class="dark:text-gray-300">
							<el-radio-group v-model="form.sourceType" class="dark:text-gray-300">
								<el-radio-button
									v-for="item in source_type"
									:key="item.value"
									:label="item.value"
									border
									class="dark:border-gray-600 dark:text-gray-300"
								>
									{{ item.label }}
								</el-radio-button>
							</el-radio-group>
						</el-form-item>
					</el-col>
				</el-row>

				<TextDocumentForm v-if="form.sourceType === '2'" v-model="form" />
				<FileDocumentForm v-else-if="form.sourceType === '1'" v-model="form.files" />
				<QADocumentForm v-else-if="form.sourceType === '3'" v-model="form.files" />
				<CrawlerDocumentForm v-else-if="form.sourceType === '4'" v-model="form" />

				<el-collapse-item name="3" class="dark:border-gray-700" :disabled="false">
					<template #title>
						<div class="flex items-center mb-3 font-medium text-gray-700 dark:text-gray-300">
							<el-icon class="mr-1"><Setting /></el-icon>
							分片设置
						</div>
					</template>
					<el-row :gutter="24" class="mb-4">
						<el-col :span="24">
							<el-form-item label="分片算法" prop="sliceType" class="dark:text-gray-300">
								<div class="flex flex-wrap gap-2 items-center">
									<div
										v-for="item in slice_algorithm_types"
										:key="item.value"
										:class="[
											'cursor-pointer mr-6 border rounded-lg py-2 px-3 flex items-center transition-all hover:shadow-sm',
											form.sliceType === item.value ? 'border-blue-500 shadow-sm dark:bg-gray-700' : 'border-gray-200 dark:border-gray-600',
										]"
										@click="form.sliceType = item.value"
									>
										<div
											:class="[
												'rounded-full w-6 h-6 flex items-center justify-center mr-2',
												form.sliceType === item.value ? 'bg-blue-500' : 'bg-gray-100 dark:bg-gray-600',
											]"
										>
											<el-icon :class="['text-lg', form.sliceType === item.value ? 'text-white' : 'text-gray-500 dark:text-gray-300']">
												<component :is="getIconForType(item.value)" />
											</el-icon>
										</div>
										<span :class="['text-sm', form.sliceType === item.value ? 'font-medium text-blue-500 dark:text-blue-400' : 'dark:text-gray-300']">
											{{ item.label }}
										</span>
									</div>
								</div>
							</el-form-item>
						</el-col>
					</el-row>
					<el-row :gutter="24" class="mt-6">
						<el-col :span="12">
							<el-form-item label="分片值" prop="maxSegmentSizeInTokens" class="dark:text-gray-300">
								<template #label>分片值 <tip content="每个分片里面字符总数量" /> </template>

								<el-input-number
									v-model="form.maxSegmentSizeInTokens"
									:min="500"
									:max="4000"
									:step="100"
									class="w-full dark:bg-gray-700"
									placeholder="请输入分片大小"
								/>
							</el-form-item>
						</el-col>
						<el-col :span="12">
							<el-form-item prop="maxOverlapSizeInTokens" class="dark:text-gray-300">
								<template #label>重叠值 <tip content="是指分片之间的重叠大小，避免分割丢失上下文" /> </template>
								<el-input-number
									v-model="form.maxOverlapSizeInTokens"
									:min="0"
									:max="200"
									:step="50"
									class="w-full dark:bg-gray-700"
									placeholder="请输入重叠大小"
								/>
							</el-form-item>
						</el-col>
					</el-row>
				</el-collapse-item>
			</el-collapse>
		</el-form>
		<template #footer>
			<span class="dialog-footer">
				<el-button @click="visible = false" class="dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-700"> 取消 </el-button>
				<el-button type="primary" @click="onSubmit" :disabled="loading" class="dark:border-gray-600"> 确认 </el-button>
			</span>
		</template>
	</el-dialog>
</template>

<script setup lang="ts" name="AiDocumentDialog">
import { defineAsyncComponent } from 'vue';
import { useDict } from '/@/hooks/dict';
import { useMessage } from '/@/hooks/message';
import { getObj, addObj, putObj } from '/@/api/knowledge/aiDocument';
import { fetchDataList } from '/@/api/knowledge/aiDataset';
import { rule } from '/@/utils/validate';
import { Setting, Document, ChatLineRound, Reading, Collection, Paperclip, Operation, Link } from '@element-plus/icons-vue';

const TextDocumentForm = defineAsyncComponent(() => import('./sources/TextDocumentForm.vue'));
const FileDocumentForm = defineAsyncComponent(() => import('./sources/FileDocumentForm.vue'));
const QADocumentForm = defineAsyncComponent(() => import('./sources/QADocumentForm.vue'));
const CrawlerDocumentForm = defineAsyncComponent(() => import('./sources/CrawlerDocumentForm.vue'));

const emit = defineEmits(['refresh']);

// 定义变量内容
const { source_type } = useDict('source_type');
const dataFormRef = ref();
const route = useRoute();
const visible = ref(false);
const loading = ref(false);
const fileType = ref(['jpeg', 'png', 'jpg', 'gif', 'md', 'doc', 'xls', 'ppt', 'txt', 'pdf', 'docx', 'xlsx', 'pptx', 'html']);

/**
 * 文档分片算法枚举
 */
enum SliceAlgorithm {
	PARAGRAPH = 'paragraph', // 段落分割器
	LINE = 'line', // 行分割器
	SENTENCE = 'sentence', // 句子分割器
	WORD = 'word', // 单词分割器
	CHARACTER = 'character', // 字符分割器
	REGEX = 'regex', // 正则表达式分割器
	RECURSIVE = 'recursive', // 递归智能分割器
}

// 分片算法选项
const slice_algorithm_types = [
	{ value: SliceAlgorithm.RECURSIVE, label: '智能分片' },
	{ value: SliceAlgorithm.PARAGRAPH, label: '段落分片' },
	{ value: SliceAlgorithm.SENTENCE, label: '句子分片' },
	{ value: SliceAlgorithm.CHARACTER, label: '字符分片' },
];

// 提交表单数据
const form = reactive({
	id: '',
	name: '',
	datasetId: '',
	fileType: '',
	content: '',
	files: [],
	sourceType: '1',
	sliceCount: '',
	hitCount: '',
	fileSize: '',
	fileStatus: '1',
	sliceType: SliceAlgorithm.RECURSIVE,
	repoType: '',
	repoOwner: '',
	repoName: '',
	accessToken: '',
	maxSegmentSizeInTokens: 1000,
	maxOverlapSizeInTokens: 50,
});

// 定义校验规则
const dataRules = ref({
	datasetId: [{ required: true, message: '所属知识库不能为空', trigger: 'blur' }],
	name: [
		{ validator: rule.overLength, trigger: 'blur' },
		{ required: true, message: '文件名不能为空', trigger: 'blur' },
	],
	content: [{ required: true, message: '内容不能为空', trigger: 'blur' }],
	url: [
		{ required: true, message: '网址不能为空', trigger: 'blur' },
		{ validator: rule.overLength, trigger: 'blur' },
		{ type: 'url', message: '请输入正确的网址', trigger: 'blur' },
	],
	settings: [{ required: true, message: '请输入配置', trigger: 'change' }],
	sliceType: [{ required: true, message: '请选择分片算法', trigger: 'change' }],
	maxSegmentSizeInTokens: [{ required: true, message: '请输入分片大小', trigger: 'blur' }],
	maxOverlapSizeInTokens: [{ required: true, message: '请输入重叠大小', trigger: 'blur' }],
	files: [
		{
			validator: (rule: any, value: any, callback: any) => {
				if (form.sourceType === '1' && (!form.files || form.files.length === 0)) {
					callback(new Error('文件不能为空'));
				} else {
					callback();
				}
			},
			trigger: 'change',
		},
	],
});
// 打开弹窗
const openDialog = (id: string) => {
	visible.value = true;
	form.id = '';
	form.files = [];

	// 重置表单数据
	nextTick(() => {
		dataFormRef.value?.resetFields();
	});

	getDatasetList();

	// 获取aiDocument信息
	if (id) {
		form.id = id;
		getAiDocumentData(id);
	}
};

// 监听 form.sourceType 变化，如果 sourceType === 1 则打开 excelUploadRef.show()
watch(
	() => form.sourceType,
	(value) => {
		if (value === '3') {
			fileType.value = ['xlsx'];
		} else {
			fileType.value = ['jpeg', 'png', 'jpg', 'gif', 'md', 'doc', 'xls', 'ppt', 'txt', 'pdf', 'docx', 'xlsx', 'pptx', 'html'];
		}
	}
);

// 提交
const onSubmit = async () => {
	const valid = await dataFormRef.value.validate().catch(() => {});
	if (!valid) return false;

	try {
		loading.value = true;
		form.id ? await putObj(form) : await addObj(form);
		useMessage().success(form.id ? '修改成功' : '添加成功');
		visible.value = false;
		emit('refresh');
	} catch (err: any) {
		useMessage().error(err.msg);
	} finally {
		loading.value = false;
	}
};

const datasetList = ref<{ id: string; name: string }[]>([]);
const getDatasetList = async () => {
	const { data } = await fetchDataList();
	datasetList.value = data;
};

// 初始化表单数据
const getAiDocumentData = (id: string) => {
	// 获取数据
	loading.value = true;
	getObj(id)
		.then((res: any) => {
			Object.assign(form, res.data);
		})
		.finally(() => {
			loading.value = false;
		});
};

onMounted(() => {
	const datasetId = route.query.datasetId;
	if (typeof datasetId === 'string') {
		form.datasetId = datasetId;
	}
});
// 暴露变量
defineExpose({
	openDialog,
});

// 新增的响应式变量
const activeNames = ref(['1', '2', '3']);

// 获取对应切片类型的图标
const getIconForType = (type: string) => {
	switch (type) {
		case SliceAlgorithm.PARAGRAPH:
			return Document;
		case SliceAlgorithm.LINE:
			return Reading;
		case SliceAlgorithm.SENTENCE:
			return ChatLineRound;
		case SliceAlgorithm.WORD:
			return Collection;
		case SliceAlgorithm.CHARACTER:
			return Paperclip;
		case SliceAlgorithm.REGEX:
			return Operation;
		case SliceAlgorithm.RECURSIVE:
			return Link;
		default:
			return Document;
	}
};
</script>
