<template>
	<transition name="fade-in">
		<div class="code-preview-wrapper" v-show="visible" @keydown.s.ctrl.prevent="handleModifyFileContent">
			<!-- 顶部信息栏 & 工具栏 -->
			<div class="tip-wrapper" v-if="visible">
				<div class="name" :title="$file.getFileNameComplete(fileInfo)">
					{{ $file.getFileNameComplete(fileInfo) }}
					<span class="un-save" v-show="isModify && !codeMirrorOptions.readOnly">（未保存）</span>
				</div>
				<div class="editor-preveiw">在线预览{{ codeMirrorOptions.readOnly ? '' : ' & 编辑' }}</div>
				<div class="tool-wrapper">
					<a
						class="item download-link"
						target="_blank"
						:href="$file.getDownloadFilePath(fileInfo)"
						:download="$file.getFileNameComplete(fileInfo)"
					>
						<DownloadOutlined title="下载" />
					</a>
					<a-tooltip placement="bottom">
						<template #title>
							操作提示: <br />
							1. 按 Esc 键可退出查看；<br />
							2. 支持在线编辑、保存、下载
						</template>
						<div class="item text-wrapper">
							<span class="text">操作提示</span>
							<BulbOutlined />
						</div>
					</a-tooltip>
					<CloseOutlined class="item" title="关闭预览" @click="closeCodePreview" />
				</div>
			</div>
			<!-- 代码编辑区域 -->
			<div class="code-editor-wrapper">
				<div class="operate-wrapper">
					<SaveOutlined
						class="save-icon"
						title="保存（ctrl+s）"
						v-show="isModify && !codeMirrorOptions.readOnly"
						@click="handleModifyFileContent"
					/>
					<a-form class="editor-set-form" :model="codeMirrorOptions" layout="inline" size="small" label-align="right">
						<a-form-item class="line-wrapper">
							<a-checkbox v-model:checked="codeMirrorOptions.lineWrapping" @change="handleChangeCodeMirrorOption"
								>自动换行</a-checkbox
							>
						</a-form-item>
						<a-form-item class="font-size">
							<a-select v-model:value="codeMirrorCustomOptions.fontSize" filterable>
								<a-select-option v-for="(item, index) in fontSizeList" :key="index" :value="item"
									>{{ item }} px</a-select-option
								>
							</a-select>
						</a-form-item>
						<a-form-item label="代码语言" class="lanaguage">
							<a-select v-model:value="codeMirrorLanguage" filterable @change="handleChangeCodeMirrorOption">
								<a-select-option v-for="[key, value] in fileSuffixCodeModeMap.entries()" :key="key" :value="key">{{
									value.language
								}}</a-select-option>
							</a-select>
						</a-form-item>
						<a-form-item label="主题" class="theme">
							<a-select v-model:value="codeMirrorTheme" filterable @change="handleChangeCodeMirrorOption">
								<a-select-option value="default">default</a-select-option>
								<a-select-option v-for="(item, index) in codeMirrorThemeList" :key="index" :value="item">{{
									item
								}}</a-select-option>
							</a-select>
						</a-form-item>
					</a-form>
				</div>
				<a-spin :spinning="codeMirrorLoading">
					<Codemirror
						class="code-editor"
						ref="codemirrorRef"
						v-model="codeMirrorText"
						:style="{ fontSize: `${codeMirrorCustomOptions.fontSize}px` }"
						:extensions="extensions"
						:disabled="codeMirrorOptions.readOnly"
						:indent-with-tab="true"
						:tab-size="codeMirrorOptions.tabSize"
						:placeholder="'请输入代码...'"
						v-if="isShow"
					/>
				</a-spin>
			</div>
		</div>
	</transition>
</template>

<script setup>
	import { ref, reactive, computed, watch, onMounted, onUnmounted, getCurrentInstance } from 'vue'
	import { message } from 'ant-design-vue'
	import { DownloadOutlined, BulbOutlined, CloseOutlined, SaveOutlined } from '@ant-design/icons-vue'
	import { Codemirror } from 'vue-codemirror'
	import { basicSetup } from 'codemirror'
	import { oneDark } from '@codemirror/theme-one-dark'
	import { javascript } from '@codemirror/lang-javascript'
	import { html } from '@codemirror/lang-html'
	import { css } from '@codemirror/lang-css'
	import { json } from '@codemirror/lang-json'
	import { xml } from '@codemirror/lang-xml'
	import { EditorView } from '@codemirror/view'
	import { fontSizeList, fileSuffixCodeModeMap, codeMirrorThemeList } from '@/libs/map.js'
	import { useMyResourceStore } from '@/store/myResource.js'
	import { getFilePreview, modifyFileContent } from '@/api/myResource/file.js'
	import tool from '@/utils/tool'

	const props = defineProps({
		fileInfo: Object,
		isEdit: Boolean,
		callback: Function
	})
	const myResource = useMyResourceStore()

	const visible = ref(false)
	defineExpose({ visible })

	const originalCodeText = ref('')
	const codeMirrorText = ref('')
	const codeMirrorLoading = ref(false)
	const isShow = ref(true)
	const codemirrorRef = ref(null)
	const codeMirrorLanguage = ref('html')
	const codeMirrorTheme = ref('default')

	// CodeMirror 配置
	const codeMirrorOptions = reactive({
		tabSize: 4,
		mode: 'text/html',
		theme: 'default',
		readOnly: true,
		lineNumbers: true,
		line: true,
		autoCloseBrackets: true,
		foldGutter: true,
		lineWrapping: true,
		gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers']
	})

	const codeMirrorCustomOptions = reactive({
		fontSize: 14
	})

	// 根据语言和主题生成扩展
	const extensions = computed(() => {
		const exts = [basicSetup]

		// 添加语言支持
		switch (codeMirrorLanguage.value) {
			case 'js':
			case 'javascript':
				exts.push(javascript())
				break
			case 'html':
				exts.push(html())
				break
			case 'css':
				exts.push(css())
				break
			case 'json':
				exts.push(json())
				break
			case 'xml':
				exts.push(xml())
				break
			default:
				exts.push(html())
		}

		// 添加主题
		if (codeMirrorTheme.value === 'one-dark') {
			exts.push(oneDark)
		} else {
			// 默认亮色主题
			exts.push(
				EditorView.theme({
					'&': {
						height: '100%',
						fontSize: `${codeMirrorCustomOptions.fontSize}px`,
						color: '#e0e0e0' // 添加默认文本颜色为浅灰色
					},
					'.cm-scroller': {
						overflow: 'auto'
					},
					'.cm-content': {
						color: '#e0e0e0' // 确保内容区域文本为浅灰色
					},
					'.cm-line': {
						color: '#e0e0e0' // 确保每行文本为浅灰色
					},
					// 语法高亮颜色
					'.cm-comment': { color: '#6a9955' }, // 注释
					'.cm-keyword': { color: '#569cd6' }, // 关键字
					'.cm-string': { color: '#ce9178' }, // 字符串
					'.cm-number': { color: '#b5cea8' }, // 数字
					'.cm-property': { color: '#9cdcfe' }, // 属性
					'.cm-operator': { color: '#d4d4d4' }, // 操作符
					'.cm-meta': { color: '#dcdcaa' }, // 元数据
					'.cm-atom': { color: '#4ec9b0' }, // 原子
					'.cm-variable': { color: '#9cdcfe' }, // 变量
					'.cm-tag': { color: '#569cd6' }, // 标签
					'.cm-attribute': { color: '#9cdcfe' } // 属性
				})
			)
		}

		// 添加行号
		if (codeMirrorOptions.lineNumbers) {
			exts.push(EditorView.lineWrapping)
		}

		return exts
	})

	const screenWidth = computed(() => myResource.screenWidth)
	const isModify = computed(() => originalCodeText.value !== codeMirrorText.value)

	watch(visible, (val) => {
		if (val) {
			let fileSuffix = props.fileInfo.extendName.toLowerCase()
			if (fileSuffix === 'yaml') {
				fileSuffix = 'yml'
			}
			if (fileSuffixCodeModeMap.has(fileSuffix)) {
				codeMirrorLanguage.value = fileSuffix
				codeMirrorOptions.mode = fileSuffixCodeModeMap.get(fileSuffix).mime
			}
			codeMirrorOptions.readOnly = !props.isEdit
			codeMirrorTheme.value = localStorage.getItem('qiwen_file_codemirror_theme') || 'default'
			getCodeText()
			document.addEventListener('keyup', handleEscKey)
		} else {
			document.removeEventListener('keyup', handleEscKey)
		}
	})

	watch(
		() => codeMirrorTheme.value,
		(val) => {
			localStorage.setItem('qiwen_file_codemirror_theme', val)
		}
	)

	const getCodeText = () => {
		codeMirrorLoading.value = true
		getFilePreview({
			userFileId: props.fileInfo.userFileId,
			isMin: false,
			shareBatchNum: props.fileInfo.shareBatchNum,
			extractionCode: props.fileInfo.extractionCode,
			token: tool.data.get('TOKEN')
		})
			.then((res) => {
				codeMirrorLoading.value = false
				originalCodeText.value = typeof res === 'object' ? JSON.stringify(res) : res
				codeMirrorText.value = originalCodeText.value + ''
			})
			.catch(() => {
				codeMirrorLoading.value = false
			})
	}

	const handleModifyFileContent = () => {
		if (!isModify.value || codeMirrorOptions.readOnly) {
			return false
		}
		codeMirrorLoading.value = true
		modifyFileContent({
			userFileId: props.fileInfo.userFileId,
			fileContent: codeMirrorText.value
		})
			.then((res) => {
				codeMirrorLoading.value = false
				if (res.success) {
					message.success('已保存')
					getCodeText()
				} else {
					message.error(res.message)
				}
			})
			.catch((err) => {
				codeMirrorLoading.value = false
				message.error(err.message)
			})
	}

	const handleChangeCodeMirrorOption = () => {
		isShow.value = false
		setTimeout(() => {
			isShow.value = true
		}, 0)
	}

	const closeCodePreview = () => {
		visible.value = false
		props.callback('cancel')
	}

	const handleEscKey = (e) => {
		if (e.keyCode === 27) {
			closeCodePreview()
		}
	}

	onMounted(() => {
		if (visible.value) {
			document.addEventListener('keyup', handleEscKey)
		}
	})

	onUnmounted(() => {
		document.removeEventListener('keyup', handleEscKey)
	})
</script>

<style lang="less" scoped>
	@import '@/style/myResource/varibles.less';
	@import '@/style/myResource/mixins.less';

	.code-preview-wrapper {
		position: fixed;
		top: 0;
		right: 0;
		bottom: 0;
		left: 0;
		overflow: auto;
		width: 100%;
		height: 100vh;
		z-index: 2;
		display: flex;
		align-items: center;
		animation: imgPreviewAnimation 0.3s;
		-webkit-animation: imgPreviewAnimation 0.3s; /* Safari and Chrome */
		animation-iteration-count: 0.3;
		-webkit-animation-iteration-count: 0.3;
		animation-fill-mode: forwards;
		-webkit-animation-fill-mode: forwards; /* Safari 和 Chrome */
		@keyframes imgPreviewAnimation {
			0% {
				background: transparent;
			}
			100% {
				background: rgba(0, 0, 0, 0.8);
			}
		}
		.tip-wrapper {
			position: fixed;
			top: 0;
			left: 0;
			z-index: 2;
			background: rgba(0, 0, 0, 0.5);
			padding: 0 48px;
			width: 100%;
			height: 48px;
			line-height: 48px;
			color: #fff;
			font-size: 16px;
			display: flex;
			justify-content: space-between;
			.name {
				flex: 1;
				padding-right: 16px;
				text-align: left;
				overflow: hidden;
				text-overflow: ellipsis;
				white-space: nowrap;
				.un-save {
					color: @warning-color;
					font-size: 14px;
				}
			}
			.tool-wrapper {
				flex: 1;
				display: flex;
				justify-content: flex-end;
				.item {
					margin-left: 16px;
					height: 48px;
					line-height: 48px;
					cursor: pointer;
					&:hover {
						opacity: 0.7;
					}
				}
				.download-link {
					color: inherit;
					font-size: 18px;
				}
				.text-wrapper {
					.text {
						margin-right: 8px;
					}
				}
			}
		}

		.code-editor-wrapper {
			margin: 56px auto 0 auto;
			width: 90vw;
			height: calc(100vh - 80px);
			.operate-wrapper {
				display: flex;
				justify-content: space-between;
				align-items: center;
				border-radius: 8px 8px 0 0;
				border-bottom: 1px solid @border-color-base;
				padding: 8px 16px;
				background: #1e1e1e; /* 修改为暗色背景 */
				color: #e0e0e0; /* 添加文字颜色为浅色 */
				.save-icon {
					font-size: 20px;
					cursor: pointer;
					color: @Info;
					font-weight: 550;
					&:hover {
						opacity: 0.5;
					}
				}
				.editor-set-form {
					flex: 1;
					text-align: right;
					:deep(.ant-form-item) {
						margin-bottom: 0;
						/* 修改表单项文字颜色 */
						color: #e0e0e0;
						.ant-form-item-label > label {
							color: #e0e0e0;
						}
						.ant-checkbox-wrapper {
							color: #e0e0e0;
						}
						&.font-size {
							.ant-form-item-control-input-content {
								.ant-select {
									width: 96px;
								}
							}
						}
						&.lanaguage {
							.ant-form-item-control-input-content {
								.ant-select {
									width: 120px;
								}
							}
						}
						&.theme {
							.ant-form-item-control-input-content {
								.ant-select {
									width: 190px;
								}
							}
						}
					}
				}
			}
			.code-editor {
				height: calc(100vh - 129px);
				background: #1e1e1e; /* 添加暗色背景 */
				:deep(.cm-editor) {
					border-radius: 0 0 8px 8px;
					height: inherit;
					font-size: inherit;
					background: #1e1e1e; /* 添加暗色背景 */
					color: #e0e0e0; /* 确保编辑器文本为浅灰色 */
					* {
						font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace !important;
					}
					.cm-scroller {
						width: 100%;
						padding: 8px 0 0 0;
						line-height: 1.5;
						font-size: inherit;
						overflow: auto;
						background: #1e1e1e; /* 添加暗色背景 */
					}
					.cm-content {
						color: #e0e0e0; /* 确保内容区域文本为浅灰色 */
					}
					.cm-line {
						color: #e0e0e0; /* 确保每行文本为浅灰色 */
					}
					.cm-gutters {
						background: #1e1e1e; /* 行号区域背景 */
						border-right: 1px solid #333; /* 行号右侧边框 */
						color: #858585; /* 行号颜色 */
					}
					.cm-activeLineGutter {
						background-color: #2c2c2c; /* 当前行的行号背景 */
					}
				}
			}
		}
	}
</style>
