<template>
	<!-- 组件根容器 -->
	<div class="cy-tab-dialog">
		<!-- 独立遮罩层：仅当 visible 且 modal 为 true 时显示，点击可关闭 -->
		<div
			v-show="visible && modal"
			contenteditable="false"
			class="cy-tab-dialog-modal"
			:style="{ zIndex: modelZIndex, height: modelHeight ? modelHeight : '100%' }"
			@click="closeOnClickModal && handleClose"
		></div>

		<!-- 基础对话框：禁用自带遮罩/滚动锁定，改用上方自管遮罩 -->
		<el-dialog
			:visible="visible"
			:title="title"
			:width="width"
			:fullscreen="fullscreen"
			:modal="false"
			:modal-append-to-body="false"
			:append-to-body="false"
			:lock-scroll="true"
			:custom-class="customClass"
			:close-on-click-modal="appendToTagsView ? false : closeOnClickModal"
			:close-on-press-escape="appendToTagsView ? false : closeOnPressEscape"
			:show-close="showClose"
			:center="center"
			:destroy-on-close="destroyOnClose"
			contenteditable="false"
			v-dialog-drag="isDrag"
			v-dialog-drag-width="isDrag"
			v-dialog-drag-height="isDrag"
			:before-close="beforeClose"
			@open="handleOpen"
			@opened="handleOpened"
			@close="handleClose"
			@closed="handleClosed"
		>
			<!-- 自定义标题插槽 -->
			<template v-if="$slots.title" slot="title">
				<slot name="title"></slot>
			</template>

			<!-- 默认插槽：对话框主体内容 -->
			<slot></slot>

			<!-- 自定义底部操作区插槽 -->
			<template v-if="$slots.footer" slot="footer">
				<slot name="footer"></slot>
			</template>
		</el-dialog>
	</div>
</template>

<script>
// 引入 Element UI 底层 Dialog 组件（直接引用源码而非全量注册）
import ElDialog from '../../../dialog';
import Vue from 'vue';

export default {
	name: 'CyTabDialog',
	components: {
		ElDialog
	},
	props: {
		// 是否显示 Dialog，支持 .sync 修饰符
		visible: {
			type: Boolean,
			default: false
		},
		// Dialog 的标题，也可通过具名 slot 自定义
		title: {
			type: String,
			default: ''
		},
		// Dialog 的宽度
		width: {
			type: String,
			default: '50%'
		},
		// 是否为全屏 Dialog
		fullscreen: {
			type: Boolean,
			default: false
		},
		// Dialog CSS 中的 margin-top 值
		top: {
			type: String,
			default: '6vh'
		},
		// 是否需要遮罩层
		modal: {
			type: Boolean,
			default: true
		},
		// 遮罩层是否插入至 body 元素上，若为 false，则遮罩层会插入至 Dialog 的父元素上
		appendToBody: {
			type: Boolean,
			default: false
		},
		// 是否在 Dialog 出现时将 body 或上层滚动锁定
		lockScroll: {
			type: Boolean,
			default: true
		},
		// Dialog 的自定义类名
		customClass: {
			type: String,
			default: ''
		},
		// 是否可以通过点击 modal 关闭 Dialog
		closeOnClickModal: {
			type: Boolean,
			default: false
		},
		// 是否可以通过按下 ESC 关闭 Dialog
		closeOnPressEscape: {
			type: Boolean,
			default: true
		},
		// 是否显示关闭按钮
		showClose: {
			type: Boolean,
			default: true
		},
		// 是否对头部和底部采用居中布局
		center: {
			type: Boolean,
			default: false
		},
		// 关闭时销毁 Dialog 中的元素
		destroyOnClose: {
			type: Boolean,
			default: false
		},
		// 是否放到 tagsView 中（即当前 app-views 下面）；此属性为 true 时 appendToBody 无效
		appendToTagsView: {
			type: Boolean,
			default: false
		},
		// 对话框是否可拖拽
		isDrag: {
			type: Boolean,
			default: true
		},
		// 关闭前的回调，会暂停 Dialog 的关闭
		beforeClose: {
			type: Function
		}
	},
	data() {
		return {
			// 判断 dialog 是否已经放到对应的 div 下
			rendered: false,
			// 自管遮罩层的 z-index
			modelZIndex: 1000,
			// 自管遮罩层的高度（根据父容器动态计算）
			modelHeight: 0,
			// 当前 app-views 的 dom 元素
			parentDom: null,
			// 当前 el-dialog 的 dom 元素
			elDialogDom: null
		};
	},
	watch: {
		// 监听 visible：控制 dialog 显示/隐藏、挂载位置、键盘事件、遮罩层级
		visible: {
			immediate: true,
			handler(val) {
				if (val) {
					this.$emit('open');
					Vue.nextTick(() => {
						const dom = this.$el;
						// 首次打开时处理挂载位置
						if (!this.rendered) {
							this.rendered = true;
							if (this.appendToTagsView) {
								// 将当前 dialog 挪到当前 app-views 里面的 app-container
								this.parentDom = dom.closest('.app-container');
								if (!this.parentDom) this.parentDom = document.body;
								this.parentDom.append(dom);
							} else if (this.appendToBody) {
								// 将当前 dialog 挪到当前 body 里面
								this.parentDom = document.body;
								this.parentDom.append(dom);
							}
							// 添加键盘监听事件（用于 ESC 关闭）
							if (this.closeOnPressEscape) {
								document.addEventListener('keydown', this.escKeyDown);
							}
						}

						setTimeout(() => {
							if (this.parentDom) this.modelHeight = this.parentDom.scrollHeight + 'px';
							// 当前 VDialog 不在 body 中时
							if (!this.parentDom || this.parentDom.tagName.toUpperCase() !== 'BODY') {
								// 获取 el-dialog 的宽度，如果大于 app-views 的宽度，则 el-dialog 不居中显示
								let elDialogWidth = dom.getElementsByClassName('el-dialog')[0].clientWidth;
								if (!this.parentDom || elDialogWidth < this.parentDom.clientWidth) {
									dom.getElementsByClassName('el-dialog')[0].style.left = '50%';
									dom.getElementsByClassName('el-dialog')[0].style.transform = 'translateX(-50%)';
								} else {
									dom.getElementsByClassName('el-dialog')[0].style.left = '0';
								}
							}
							dom.getElementsByClassName('el-dialog')[0].style.marginTop = this.top;
						}, 50);

						// 获取 el-dialog 的 z-index，赋值给 model，用于处理 model 的层级问题
						this.elDialogDom = dom.children[1];
						setTimeout(() => {
							this.modelZIndex = this.elDialogDom.style.zIndex;
						}, 50);
					});
				} else {
					// immediate=true 时，首次打开不需要触发 close 事件
					if (this.rendered) this.$emit('close');
				}
			}
		}
	},
	methods: {
		/**
		 * 打开回调，透传 open 事件
		 * @fires {Event} open
		 * @returns {void}
		 */
		handleOpen() {
			this.$emit('open');
		},

		/**
		 * 打开动画结束回调，透传 opened 事件
		 * @fires {Event} opened
		 * @returns {void}
		 */
		handleOpened() {
			this.$emit('opened');
		},

		/**
		 * 关闭回调：同步 visible 并透传 close 事件
		 * @fires {Event} update:visible
		 * @fires {Event} close
		 * @returns {void}
		 */
		handleClose() {
			this.$emit('update:visible', false);
			this.$emit('close');
		},

		/**
		 * 关闭动画结束回调，透传 closed 事件
		 * @fires {Event} closed
		 * @returns {void}
		 */
		handleClosed() {
			this.$emit('closed');
		},

		/**
		 * 监听 esc 键，按层级优先级关闭最上层 dialog
		 * @param {KeyboardEvent} event - 键盘事件对象
		 * @returns {void}
		 */
		escKeyDown(event) {
			if (event.keyCode === 27) {
				// 获取 body 下的直接子节点中的已打开的 VDialog
				let bodyVDialogDomArr = [];
				let bodyChildrenArr = document.body.childNodes;
				for (let i = 0; i < bodyChildrenArr.length; i++) {
					let item = bodyChildrenArr[i];
					if (item.tagName && item.tagName.toUpperCase() === 'DIV' && item.className && item.className.split(' ').includes('cy-tab-dialog-opened')) {
						bodyVDialogDomArr.push(item);
					}
				}
				// 判断 body 中是否有已打开的 VDialog，如果有，优先关闭 body 下的 VDialog
				if (bodyVDialogDomArr.length > 0) {
					// 获取当前 cy-tab-dialog 在当前 body 中的下标
					let curDomIndex = [].indexOf.call(bodyVDialogDomArr, this.$el);
					if (curDomIndex === bodyVDialogDomArr.length - 1) {
						this.handleClose();
					}
				} else if (document.getElementById('tags-view-container') && this.parentDom.parentElement.getAttribute('include_name')) {
					// 获取当前 app-views 对应的 include_name 值
					let includeName = this.parentDom.parentElement.getAttribute('include_name');
					// 根据 includeName 获取 tagsView 中的 tag 标签页
					let tagDom = document.getElementById('tags-view-container').querySelectorAll(`[include_name=${ includeName }]`);
					if (tagDom && tagDom[0]) {
						// 判断此标签页是否为选中状态，只有选中状态中的 VDialog 才可以进行关闭
						if (tagDom[0].className.split(' ').includes('active')) {
							let vDialogList = this.parentDom.getElementsByClassName('cy-tab-dialog-opened');
							// 获取当前 cy-tab-dialog 在当前 app-views 中的下标
							let curDomIndex = [].indexOf.call(vDialogList, this.$el);
							if (curDomIndex === vDialogList.length - 1) {
								this.handleClose();
							}
						}
					}
				} else {
					this.handleClose();
				}
			}
		}
	},

	/**
	 * 组件销毁前移除键盘监听，避免内存泄漏
	 * @returns {void}
	 */
	beforeDestroy() {
		document.removeEventListener('keydown', this.escKeyDown);
	}
};
</script>
