<template>
	<div :style="{ '--editor-height': editorHeight }">
		<ckeditor :editor="editor" v-model="editorData" :config="editorConfig" :disabled="disabled" @blur="onBlur"
			@focus="onFocus"></ckeditor>
	</div>
</template>

<script setup>
import {
	ClassicEditor,
	Alignment,
	AutoImage,
	Autoformat,
	BlockQuote,
	Bold,
	CodeBlock,
	DataFilter,
	DataSchema,
	Essentials,
	FindAndReplace,
	FontBackgroundColor,
	FontColor,
	FontFamily,
	FontSize,
	GeneralHtmlSupport,
	Heading,
	Highlight,
	HorizontalLine,
	Image,
	ImageCaption,
	ImageInsert,
	ImageResize,
	ImageStyle,
	ImageToolbar,
	ImageUpload,
	Indent,
	IndentBlock,
	Italic,
	Link,
	LinkImage,
	List,
	MediaEmbed,
	MediaEmbedToolbar,
	Mention,
	Paragraph,
	PasteFromOffice,
	RemoveFormat,
	SelectAll,
	ShowBlocks,
	SourceEditing,
	SpecialCharacters,
	SpecialCharactersArrows,
	SpecialCharactersCurrency,
	SpecialCharactersEssentials,
	SpecialCharactersLatin,
	SpecialCharactersMathematical,
	SpecialCharactersText,
	Style,
	Subscript,
	Superscript,
	Table,
	TableCaption,
	TableCellProperties,
	TableColumnResize,
	TableProperties,
	TableToolbar,
	TextTransformation,
	TodoList,
	Underline,
	Undo,
	WordCount,
} from "ckeditor5";
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
import { UploadAdapterPlugin } from "./UploadAdapter.js";

import { ref, computed, watch } from "vue";
import { useCurrentInstance } from "@/utils/tool";

import coreTranslations from "ckeditor5/translations/zh-cn.js";
import "ckeditor5/ckeditor5.css";

const { proxy } = useCurrentInstance();

// 组件名称
defineOptions({
	name: "scCkeditor"
});

// Props 定义
const props = defineProps({
	modelValue: {
		type: String,
		default: "",
	},
	placeholder: {
		type: String,
		default: "请输入内容……",
	},
	toolbar: {
		type: String,
		default: "basic",
	},
	height: {
		type: String,
		default: "400px",
	},
	disabled: {
		type: Boolean,
		default: false,
	},
});

// Emits 定义
const emit = defineEmits(["update:modelValue"]);

// 工具栏配置常量
const TOOLBARS = {
	full: [
		"sourceEditing",
		"undo",
		"redo",
		"heading",
		"style",
		"|",
		"superscript",
		"subscript",
		"removeFormat",
		"bold",
		"italic",
		"underline",
		"link",
		"fontBackgroundColor",
		"fontFamily",
		"fontSize",
		"fontColor",
		"|",
		"outdent",
		"indent",
		"alignment",
		"bulletedList",
		"numberedList",
		"todoList",
		"|",
		"blockQuote",
		"insertTable",
		"imageInsert",
		"mediaEmbed",
		"highlight",
		"horizontalLine",
		"selectAll",
		"showBlocks",
		"specialCharacters",
		"codeBlock",
		"findAndReplace",
	],
	basic: [
		"sourceEditing",
		"undo",
		"redo",
		"heading",
		"|",
		"removeFormat",
		"bold",
		"italic",
		"underline",
		"link",
		"fontBackgroundColor",
		"fontFamily",
		"fontSize",
		"fontColor",
		"|",
		"outdent",
		"indent",
		"alignment",
		"bulletedList",
		"numberedList",
		"todoList",
		"|",
		"insertTable",
		"imageInsert",
		"mediaEmbed",
	],
	simple: [
		"undo",
		"redo",
		"heading",
		"|",
		"removeFormat",
		"bold",
		"italic",
		"underline",
		"link",
		"fontBackgroundColor",
		"fontFamily",
		"fontSize",
		"fontColor",
		"|",
		"insertTable",
		"imageInsert",
		"mediaEmbed",
	],
};

// 插件配置常量
const PLUGINS = [
	Alignment,
	AutoImage,
	Autoformat,
	BlockQuote,
	Bold,
	CodeBlock,
	DataFilter,
	DataSchema,
	Essentials,
	FindAndReplace,
	FontBackgroundColor,
	FontColor,
	FontFamily,
	FontSize,
	GeneralHtmlSupport,
	Heading,
	Highlight,
	HorizontalLine,
	Image,
	ImageCaption,
	ImageInsert,
	ImageResize,
	ImageStyle,
	ImageToolbar,
	ImageUpload,
	Indent,
	IndentBlock,
	Italic,
	Link,
	LinkImage,
	List,
	MediaEmbed,
	MediaEmbedToolbar,
	Mention,
	Paragraph,
	PasteFromOffice,
	RemoveFormat,
	SelectAll,
	ShowBlocks,
	SourceEditing,
	SpecialCharacters,
	SpecialCharactersArrows,
	SpecialCharactersCurrency,
	SpecialCharactersEssentials,
	SpecialCharactersLatin,
	SpecialCharactersMathematical,
	SpecialCharactersText,
	Style,
	Subscript,
	Superscript,
	Table,
	TableCaption,
	TableCellProperties,
	TableColumnResize,
	TableProperties,
	TableToolbar,
	TextTransformation,
	TodoList,
	Underline,
	Undo,
	WordCount,
	UploadAdapterPlugin,
];

// 响应式数据
const editorData = ref("");
const editorHeight = ref(props.height);
const editor = ClassicEditor;

// 编辑器配置
const editorConfig = computed(() => ({
	language: { ui: "zh-cn", content: "zh-cn" },
	translations: [coreTranslations],
	plugins: PLUGINS,
	toolbar: {
		shouldNotGroupWhenFull: true,
		items: TOOLBARS[props.toolbar] || TOOLBARS.basic,
	},
	placeholder: props.placeholder,
	image: {
		styles: ["alignLeft", "alignCenter", "alignRight"],
		toolbar: [
			"imageTextAlternative",
			"toggleImageCaption",
			"|",
			"imageStyle:alignLeft",
			"imageStyle:alignCenter",
			"imageStyle:alignRight",
			"|",
			"linkImage",
		],
	},
	mediaEmbed: {
		previewsInData: true,
		providers: [
			{
				name: "mp4",
				url: /\.(mp4|avi|mov|flv|wmv|mkv)$/i,
				html: match => {
					const url = match["input"];
					return ('<video controls width="100%" height="100%" src="' + url + '"></video>')
				},
			},
		],
	},
	fontSize: {
		options: [10, 12, 14, 16, 18, 20, 22, 24, 26, 30, 32, 36],
	},
	style: {
		definitions: [
			{
				name: "Article category",
				element: "h3",
				classes: ["category"],
			},
			{
				name: "Info box",
				element: "p",
				classes: ["info-box"],
			},
		],
	},
	upload: {
		uploadUrl: proxy?.$API?.common?.upload?.url || "",
		withCredentials: false,
		extendData: { type: "images" },
		headers: {
			Authorization: "Bearer " + proxy?.$TOOL?.data?.get("TOKEN"),
		},
	},
}));

// 监听 modelValue 变化
watch(
	() => props.modelValue,
	(newVal) => {
		editorData.value = newVal ?? "";
	},
	{ immediate: true }
);

// 监听 height 变化
watch(
	() => props.height,
	(newVal) => {
		editorHeight.value = newVal;
	}
);

// 移除图片宽高的正则替换函数
const stripImageDimensions = (html) => {
	return html.replace(/<img[^>]*>/gi, (match) => {
		return match
			.replace(/width="[^"]*"/gi, "")
			.replace(/height="[^"]*"/gi, "");
	});
};

// 失去焦点事件 - 移除图片的固定宽高，避免响应式布局问题
const onBlur = () => {
	const cleanedData = stripImageDimensions(editorData.value);
	editorData.value = cleanedData;
	emit("update:modelValue", cleanedData);
};
</script>

<style>
:root {
	--ck-z-panel: 9999;
}

.ck-content {
	height: var(--editor-height);
}

.ck-source-editing-area,
.ck-source-editing-area textarea {
	height: var(--editor-height);
}

.ck-source-editing-area textarea {
	overflow-y: scroll !important;
}
</style>
