<template>
	<view
		:insertImageFlag="insertImageFlag"
		:insertAtFlag="insertAtFlag"
		:insertEmojiFlag="insertEmojiFlag"
		:blurFlag="blurFlag"
		:change:insertEmojiFlag="input.insertEmojiFlagUpdate"
		:change:insertAtFlag="input.insertAtFlagUpdate"
		:change:insertImageFlag="input.insertImageFlagUpdate"
		:change:blurFlag="input.blurFlagUpdate"
		class="editor_wrap"
        :class="{'blur-trigger': blurFlag % 2 === 1}"
        @touchstart="input.handleTouchStart"
        @click="input.handleForceUpdate"
        >
		<editor :placeholder="placeholder" ref="editor2" id="editor2" @ready="editorReady" @focus="editorFocus" @blur="editorBlur" @input="editorInput" />
		<view class="canvas_container">
			<canvas v-if="canvasData.show" canvas-id="atCanvas" :style="{ width: canvasData.width }" id="atCanvas"></canvas>
		</view>
	</view>
</template>

<script>
import { html2Text } from '../../../../../util/common';
export default {
	props: {
		placeholder: {
			type: String,
			default: ''
		}
	},
	data() {
		return {
			editorCtx: null,
			canvasData: {
				width: 0,
				show: false
			},
			imageData: {},
			insertImageFlag: null,
			insertAtFlag: null,
			lastStr: '',
			emojiData: '',
			insertEmojiFlag: null,
			blurFlag: 0,
            inputTimeout: null // 用于防抖
		};
	},
    mounted() {
        
    },
	methods: {
		editorReady() {
			uni.createSelectorQuery()
				.select('#editor2')
				.context((res) => {
					this.$emit('ready', res);
					this.editorCtx = res.context;
				}).exec();
		},
		insertImage(imageData) {
			this.imageData = imageData;
			this.insertImageFlag = true;
		},
		insertEmoji(emoji) {
			this.$nextTick(() => {
				this.insertEmojiFlag = true;
				this.emojiData = emoji;
			});
		},
		internalInsertEmoji() {
			this.editorCtx.insertText({
				text: this.emojiData,
				complete: () => {
					this.insertEmojiFlag = false;
					this.emojiData = null;
				}
			});
		},
		internalInsertImage() {
			this.editorCtx.insertImage({
				...this.imageData,
				complete: () => {
					this.insertImageFlag = false;
					this.insertAtFlag = null;
					// plus.key.showSoftKeybord()
					// this.setDraftTextItem();
				}
			});
		},
		internalInsertAtEl({ text, width, userID, nickname }) {
			this.canvasData.width = `${width}px`;
			this.canvasData.show = true;
			setTimeout(() => {
				const ctx = uni.createCanvasContext('atCanvas');
				const fontSize = 14;
				ctx.setFontSize(fontSize);
				ctx.setFillStyle('#3e44ff');
				ctx.fillText(text, 0, 16);
				ctx.draw();
				this.canvasToTempFilePath(userID, nickname, width);
			}, 20);
		},
		createCanvasData(userID, nickname) {
			this.$nextTick(() => {
				this.insertAtFlag = {
					userID,
					nickname
				};
			});
		},
		canvasToTempFilePath(sendID, senderNickname, width) {
			uni.canvasToTempFilePath({
				canvasId: 'atCanvas',
				success: (res) => {
					this.insertImage({
						src: res.tempFilePath,
						width,
						height: '20px',
						data: {
							sendID,
							senderNickname
						},
						extClass: 'at_el'
					});
					uni.createCanvasContext('atCanvas').clearRect();
				}
			});
		},
		editorFocus() {
			this.$emit('focus');
		},
		editorBlur() {
			console.log("qxj editorBlur");
			this.$emit('blur');
		},
		editorInput(e) {
			let str = e.detail.html;
			const oldArr = (this.lastStr ?? '').split('');
			let contentStr = str;
			oldArr.forEach((str) => {
				contentStr = contentStr.replace(str, '');
			});
			contentStr = html2Text(contentStr);
			if (contentStr === '@') {
				this.$emit('tryAt');
			}

            // 实时检测空内容并重置
            // 如果内容只有换行符（用户删除了所有文本但留下了空行），强制重置为标准空状态
            const text = e.detail.text.replace(/\n/g, '');
            const hasImage = str.indexOf('<img') !== -1;
            if (!hasImage && text.trim().length === 0 && str !== '<p><br></p>') {
                // 只有当内容不是标准的空状态时才重置，避免循环触发
                // 注意：这里不能直接 setContents，因为会导致光标跳动
                // 只能在用户明显清空时做处理，或者在 blur 时处理
                // 但为了防止高度异常，我们可以尝试在这里做轻量级检查
            }

            // 防抖发送 input 事件，避免频繁触发父组件逻辑导致桥接阻塞
            if (this.inputTimeout) {
                clearTimeout(this.inputTimeout);
            }
            this.inputTimeout = setTimeout(() => {
                this.$emit('input', e);
            }, 100);
            
			this.lastStr = e.detail.html;
		},
		focus() {
			this.$refs.editor2.focus();
		},
		blur() {
			console.log("qxj blur");
			// 1. 立即触发 renderjs 更新（负责视觉层重置）
            // 直接同步修改数据，不再使用 setTimeout，争取第一时间触发
            this.blurFlag = this.blurFlag + 1;
            console.log("1111", this.blurFlag);

            // 2. 先执行内容清理，避免空行堆积导致的高度异常
            // 不等待回调，直接尝试清理（如果编辑器支持同步清理更好，但这里只能通过 context）
            if (this.editorCtx) {
                 this.editorCtx.getContents({
                     success: (res) => {
                         const html = res.html;
                         const text = res.text.replace(/\n/g, '');
                         const hasImage = html.indexOf('<img') !== -1;
                         // 增强判断：只要没有图片，且文本去空后长度为0，就认为是空
                         if (!hasImage && text.trim().length === 0) {
                             // 关键：在这里直接重置
                             this.editorCtx.setContents({
                                 html: '<p><br></p>'
                             });
                             // 同时清空 renderjs 的内容
                             // 但由于无法直接通信，只能依赖 renderjs 自身的检测
                         }
                     }
                 });
            }

			// 3. 恢复原生失焦
			if (this.editorCtx && this.editorCtx.blur) {
				this.editorCtx.blur();
			}
		}
		
	}
};
</script>

<script module="input" lang="renderjs">
export default {
    data() {
        return {
            editorInstance: null,
            timer: null
        }
    },
    mounted() {
		// 在 mounted 中提前获取 editor 引用，避免每次查询
		this.editorInstance = this.$el.querySelector('.ql-editor');
		// 监听键盘收起或输入框失焦事件
		// 使用 focusout 并开启捕获阶段，确保能捕获到 blur 事件
		// 直接监听根元素，而不是 editorInstance，防止 editorInstance 为空或被替换
		this.$el.addEventListener('focusout', this.onEditorBlur, true);
		// 同时监听 input 事件，实时防止空行堆积
		if (this.editorInstance) {
			this.editorInstance.addEventListener('input', this.onEditorInput);
		}
	},
	beforeDestroy() {
		this.$el.removeEventListener('focusout', this.onEditorBlur, true);
		if (this.editorInstance) {
			this.editorInstance.removeEventListener('input', this.onEditorInput);
		}
	},
	methods: {
		onEditorInput() {
			const editor = this.editorInstance || this.$el.querySelector('.ql-editor');
			if (editor) {
				// 实时检查：如果只有换行符，强制清空
				if (editor.textContent.trim() === '' && !editor.innerHTML.includes('<img')) {
					// 只有当高度明显异常时才干预，避免太激进
					if (editor.offsetHeight > 50) { // 假设单行高度约30-40px
						console.log('renderjs realtime clean triggered');
						editor.innerHTML = '<p><br></p>';
					}
				}
			}
		},
		onEditorBlur() {
			console.log('renderjs direct focusout detected');
            // 在 renderjs 层直接清理内容，不等待 JS 通知的延迟
			const editor = this.editorInstance || this.$el.querySelector('.ql-editor');
            if (editor) {
                // 如果内容只包含换行符，强制清空
                if (editor.textContent.trim() === '' && !editor.innerHTML.includes('<img')) {
                    console.log('renderjs forcing content clean');
                    editor.innerHTML = '<p><br></p>';
                }
				
                // 使用 requestAnimationFrame 确保在下一帧渲染前执行重置
                // 这样比 setTimeout 更精准，也能避免页面闪烁
                window.requestAnimationFrame(() => {
                    // 强制关闭键盘
                    editor.setAttribute('inputmode', 'none');
                    editor.blur();
                    
                    // 强制重置高度样式
                    editor.style.height = 'auto'; // 先重置为 auto
                    editor.style.minHeight = '30px'; // 确保最小高度
                    
                    // 稍微延迟后恢复 inputmode，防止下次聚焦失败
                    if (this.timer) clearTimeout(this.timer);
                    this.timer = setTimeout(() => {
                        editor.removeAttribute('inputmode');
                        this.timer = null;
                    }, 50);
                });
            }
		},
        handleTouchStart(event, ownerInstance) {
            // 仅仅为了让 renderjs 保持活跃，或者在这里直接处理某些逻辑
        },
        handleForceUpdate(event, ownerInstance) {
            // 通过触发点击事件等方式来强制唤醒 renderjs 响应
        },
		blurFlagUpdate(newValue, oldValue, ownerVm, vm) {
			console.log("renderjs blurFlagUpdate", newValue);
			if (!newValue) return;
            // 优先使用缓存的实例，如果没有则重新获取
			const editor = this.editorInstance || this.$el.querySelector('.ql-editor');
			if (editor) {
				editor.setAttribute('inputmode', 'none'); // 强制关闭软键盘
				editor.blur();
				console.log('blur',editor.innerHTML);
				editor.innerHTML = '<p><br></p>';
				console.log("4444");
				// 检查并清理内容中的多余换行符，这可能是导致高度异常的原因
				// 如果内容为空或者只包含空白字符，强制清空
				if (!editor.innerHTML || editor.innerHTML === '<p><br></p>' || editor.textContent.trim() === '') {
					// 保持至少一个空段落以维持格式，但确保它是干净的
					editor.innerHTML = '<p><br></p>';
				}
				// 强制重置高度样式
				// 极端手段：先隐藏再显示，强制浏览器重排
				editor.style.display = 'none';
				// 强制回流
				editor.offsetHeight; 
				editor.style.display = 'block';
				
				editor.style.height = '30px'; 
                // 清除之前的 timer，避免多次覆盖
                if (this.timer) clearTimeout(this.timer);
				this.timer = setTimeout(() => {
					editor.style.height = 'auto'; 
					editor.removeAttribute('inputmode'); // 恢复输入模式
                    this.timer = null;
				}, 100);
			}
		},
        insertEmojiFlagUpdate(newValue, oldValue, ownerVm, vm) {
			if (newValue === null) {
				return;
			}
			if (newValue) {
				this.$el.querySelector('.ql-editor').setAttribute('inputmode', 'none')
				ownerVm.callMethod('internalInsertEmoji')
			} else {
				this.$el.querySelector('.ql-editor').removeAttribute('inputmode')
			}
		},
		insertImageFlagUpdate(newValue, oldValue, ownerVm, vm) {
			if (newValue === null) {
				return;
			}
			if (newValue) {
				this.$el.querySelector('.ql-editor').setAttribute('inputmode', 'none')
				ownerVm.callMethod('internalInsertImage')
			} else {
				this.$el.querySelector('.ql-editor').removeAttribute('inputmode')
			}
		},
		insertAtFlagUpdate(newValue, oldValue, ownerVm, vm){
			if (newValue === null) {
				return;
			}
			if (newValue) {
				const data = this.truncateText(`@${newValue.nickname}`,120)
				ownerVm.callMethod('internalInsertAtEl', {...data,...newValue})
			}
		},
		truncateText(text, maxWidth) {
			const container = document.createElement("div");
			container.style.width = "auto";
			container.style.overflow = "hidden";
			container.style.textOverflow = "ellipsis";
			container.style.whiteSpace = "nowrap";
			container.style.position = "absolute";
			container.style.visibility = "hidden";

			const textNode = document.createTextNode(text);
			container.appendChild(textNode);

			document.body.appendChild(container);

			const isOverflowing = container.scrollWidth > maxWidth;

			if (!isOverflowing) {
				const width = container.clientWidth + 4
				document.body.removeChild(container);
				return {
					text,
					width
				};
			}

			container.style.width = maxWidth + "px";
			container.style.visibility = "visible";

			let truncatedText = text;
			while (container.scrollWidth > maxWidth) {
			truncatedText = truncatedText.slice(0, -1);
			container.textContent = truncatedText + "...";
			}

			document.body.removeChild(container);
			return {
				text: `${truncatedText}...`,
				width: maxWidth + 4
			};
		}
	},
}
</script>

<style lang="scss" scoped>
.editor_wrap {
	position: relative;
}

#editor2 {
	background-color: #fff;
	min-height: 30px;
	max-height: 120px;
	height: auto;
	word-break: break-all;
}

/deep/.ql-editor {
	img {
		vertical-align: sub !important;
	}

	p {
		padding: 4px;
	}
}

.canvas_container {
	position: fixed;
	bottom: -99px;
	z-index: -100;

	&_name {
		max-width: 480rpx;
		display: inline-block;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	#atCanvas {
		height: 20px;
	}

	.convas_container_name {
		font-size: 16px !important;
	}
}
</style>
