<template>
  <div class="wrap">
    <div class="editor_div" ref="editorRef" contenteditable></div>
    <div class="tag_list">
      <el-tag v-for="tag in dynamicTags" :key="tag" :closable="tag.type == 'custom'" disable-transitions
        @close="handleClose(tag)" @mousedown.prevent="saveRange" @click="selectTag(tag)" style="cursor: pointer;"
        size="large">
        {{ tag.label }}
      </el-tag>
      <div v-if="inputVisible" style="width: 92px;"><el-input ref="InputRef" v-model="inputValue" placeholder="请输入"
          @keyup.enter="handleInputConfirm" @blur="handleInputConfirm" /></div>
      <el-button v-else class="button-new-tag" @click="showInput">
        +标签
      </el-button>
    </div>
    <div class="tips">变量限制：不支持QQ号、微信号、网址信息</div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick, onBeforeUnmount, defineProps, defineEmits } from 'vue'
import { ElMessage } from 'element-plus'

const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  }
})
const emit = defineEmits(['update:modelValue'])

const editorRef = ref(null)
let lastRange = null // 记录光标位置
let lastInsertTime = 0 // 防止快速连续插入
let needsInput = false // 插入后必须输入内容才能再次插入
const InputRef = ref(null)
const inputValue = ref('')
const inputVisible = ref(false)
const dynamicTags = ref([
  {
    label: '用户昵称',
    value: '${用户昵称}',
    type: 'fix'
  },
  {
    label: '店铺名称',
    value: '${店铺名称}',
    type: 'fix'
  },
  {
    label: '活动名称',
    value: '${活动名称}',
    type: 'fix'
  },
  {
    label: '活动时间',
    value: '${活动时间}',
    type: 'fix'
  },
  {
    label: '数量',
    value: '${数量}',
    type: 'fix'
  },
  {
    label: '金额',
    value: '${金额}',
    type: 'fix'
  },
  {
    label: '时间',
    value: '${时间}',
    type: 'fix'
  }
])
function handleClose(tag) {
  const index = dynamicTags.value.indexOf(tag);
  dynamicTags.value.splice(index, 1);
}
function showInput() {
  inputVisible.value = true;
  nextTick(() => {
    InputRef.value.$el.querySelector('input').focus();
  });
}
function handleInputConfirm() {
  if (inputValue.value && dynamicTags.value.indexOf(inputValue.value) === -1
  ) {
    dynamicTags.value.push({ label: inputValue.value, value: '${' + inputValue.value + '}', type: 'custom' });
  }
  inputVisible.value = false;
  inputValue.value = '';
}

// 记录 selection range（提升到模块作用域，便于模板调用）
function saveRange() {
  const sel = window.getSelection();
  if (sel && sel.rangeCount > 0) {
    const range = sel.getRangeAt(0);
    // 只在光标在 editorRef 内部时才记录
    if (editorRef.value && editorRef.value.contains(range.startContainer)) {
      lastRange = range.cloneRange();
    }
  }
}

// 选择标签
function selectTag(tag) {
  // 防抖：300ms 内再次触发插入判定为重复，忽略
  const now = Date.now();
  if (now - lastInsertTime < 300) {
    return;
  }
  // 如果上次插入后还没输入任何可见字符，则禁止再次插入
  if (needsInput) {
    ElMessage.warning('请输入内容');
    return;
  }
  // 新需求：同一种标签只能存在一个，如果已存在则提示并阻止插入
  if (editorRef.value) {
    const existing = Array.from(editorRef.value.querySelectorAll('.tag-chip'))
      .some(el => el.dataset && el.dataset.value === tag.value);
    if (existing) {
      ElMessage.warning('已存在该标签');
      return;
    }
  }
  if (editorRef.value) {
    // 如果光标前紧邻一个变量标签且两者之间没有其他可见字符，则禁止连续插入
    function isCaretAfterTag(range) {
      if (!range) return false;
      const sc = range.startContainer;
      const offset = range.startOffset;
      // 辅助：去除零宽空格并判断文本是否为空
      const textEmpty = (txt) => !txt || txt.replace(/\u200B/g, '').trim().length === 0;

      // 如果在文本节点内
      if (sc.nodeType === Node.TEXT_NODE) {
        const before = sc.textContent.slice(0, offset);
        if (!textEmpty(before)) return false;
        // 向前查找非空白节点
        let p = sc.previousSibling;
        while (p) {
          if (p.nodeType === Node.TEXT_NODE) {
            if (!textEmpty(p.textContent)) return false;
            p = p.previousSibling; continue;
          }
          if (p.nodeType === Node.ELEMENT_NODE) {
            return !!(p.dataset && p.dataset.value);
          }
          p = p.previousSibling;
        }
        return false;
      }

      // 如果在元素节点内
      if (sc.nodeType === Node.ELEMENT_NODE) {
        if (offset === 0) {
          // 在元素开始位置，检查元素的前一个兄弟节点
          let p = sc.previousSibling;
          while (p) {
            if (p.nodeType === Node.TEXT_NODE) {
              if (!textEmpty(p.textContent)) return false;
              p = p.previousSibling; continue;
            }
            if (p.nodeType === Node.ELEMENT_NODE) {
              return !!(p.dataset && p.dataset.value);
            }
            p = p.previousSibling;
          }
          return false;
        } else {
          const nodeBefore = sc.childNodes[offset - 1];
          if (!nodeBefore) return false;
          if (nodeBefore.nodeType === Node.ELEMENT_NODE) {
            return !!(nodeBefore.dataset && nodeBefore.dataset.value);
          }
          if (nodeBefore.nodeType === Node.TEXT_NODE) {
            if (!textEmpty(nodeBefore.textContent)) return false;
            // 再向前找
            let p = nodeBefore.previousSibling;
            while (p) {
              if (p.nodeType === Node.TEXT_NODE) {
                if (!textEmpty(p.textContent)) return false;
                p = p.previousSibling; continue;
              }
              if (p.nodeType === Node.ELEMENT_NODE) {
                return !!(p.dataset && p.dataset.value);
              }
              p = p.previousSibling;
            }
          }
          return false;
        }
      }

      return false;
    }

    // 检查当前保存的 lastRange 或当前 selection
    const checkRange = lastRange || (window.getSelection() && window.getSelection().rangeCount ? window.getSelection().getRangeAt(0) : null);
    // 进一步：如果光标前最近的可见节点就是相同变量标签，禁止插入（防止首次双插入）
    function getNodeBeforeCaret(range) {
      if (!range) return null;
      const sc = range.startContainer;
      const offset = range.startOffset;
      // 如果在文本节点内，从文本节点切片前部判断
      if (sc.nodeType === Node.TEXT_NODE) {
        // 若文本前有非空白字符则返回 null
        const beforeText = sc.textContent.slice(0, offset).replace(/\u200B/g, '');
        if (beforeText.trim().length > 0) return null;
        // 检查前一个兄弟
        let p = sc.previousSibling;
        while (p) {
          if (p.nodeType === Node.TEXT_NODE) {
            if (p.textContent.replace(/\u200B/g, '').trim().length > 0) return null;
            p = p.previousSibling; continue;
          }
          return p;
        }
        return sc.parentNode && sc.parentNode.previousSibling ? sc.parentNode.previousSibling : null;
      }
      // 如果在元素节点
      if (sc.nodeType === Node.ELEMENT_NODE) {
        if (offset === 0) {
          return sc.previousSibling;
        }
        return sc.childNodes[offset - 1] || null;
      }
      return null;
    }
    const nodeBefore = getNodeBeforeCaret(checkRange);
    if (nodeBefore && nodeBefore.nodeType === Node.ELEMENT_NODE) {
      const el = nodeBefore;
      if (el.dataset && el.dataset.value && el.dataset.value === tag.value) {
        ElMessage.warning('请输入内容');
        return;
      }
    }
    if (checkRange && isCaretAfterTag(checkRange)) {
      ElMessage.warning('请输入内容');
      return;
    }
    // 先恢复光标位置（不要先 focus，focus 可能改变 selection）
    // 创建一个span标签用于插入
    const span = document.createElement('span');
    span.textContent = tag.label;
    span.contentEditable = "false";
    span.style.display = "inline-block";
    span.style.background = "#f0f0f0";
    span.style.borderRadius = "4px";
    span.style.padding = "0 4px";
    span.style.fontSize = "12px";
    span.style.margin = "0 2px";
    span.style.cursor = "pointer";
    span.style.border = "1px solid #dcdcdc";
    span.style.userSelect = "none";
    // 关键：保存变量值到 dataset
    span.dataset.value = tag.value;
    span.dataset.type = tag.type || 'custom';
    span.className = 'tag-chip';
    // 添加删除按钮
    const closeBtn = document.createElement('span');
    closeBtn.textContent = ' ×';
    closeBtn.style.color = "#999";
    closeBtn.style.cursor = "pointer";
    closeBtn.className = 'tag-close';
    closeBtn.onclick = function (e) {
      e.stopPropagation();
      span.remove();
      emitValue();
    };
    span.appendChild(closeBtn);

    // 恢复光标位置
    let sel = window.getSelection();
    let inserted = false;
    if (lastRange) {
      sel.removeAllRanges();
      sel.addRange(lastRange);
      // 插入到光标处
      if (sel && sel.rangeCount > 0) {
        const range = sel.getRangeAt(0);
        range.collapse(false);
        range.insertNode(span);
        // 光标移到span后
        range.setStartAfter(span);
        range.setEndAfter(span);
        sel.removeAllRanges();
        sel.addRange(range);
        // 更新 lastRange
        lastRange = range.cloneRange();
        inserted = true;
      }
    }
    // 插入完成后确保 editor 聚焦（在插入之后调用 focus 更稳妥）
    if (editorRef.value) {
      try { editorRef.value.focus(); } catch (e) { }
    }
    // 如果没有光标，则插入到内容尾部
    if (!inserted) {
      editorRef.value.appendChild(span);
    }
    // 插入后 emit 内容
    emitValue();
    lastInsertTime = Date.now();
    // 设置需要输入标志，直到用户输入可见字符
    needsInput = true;
  }
}

// 获取序列化内容（如：尊共的${username}）
function getSerializedContent() {
  if (!editorRef.value) return '';
  function walk(node) {
    let out = '';
    node.childNodes.forEach(n => {
      if (n.nodeType === Node.TEXT_NODE) {
        out += n.textContent;
      } else if (n.nodeType === Node.ELEMENT_NODE) {
        // 如果是我们插入的 tag 节点并且有 data-value，则用 data-value
        const el = n;
        if (el.dataset && el.dataset.value) {
          out += el.dataset.value;
        } else {
          out += walk(el);
        }
      }
    });
    return out;
  }
  return walk(editorRef.value);
}

// emit 内容给父组件
function emitValue() {
  emit('update:modelValue', getSerializedContent());
}

// 重置编辑器内容和内部状态
function reset() {
  if (editorRef.value) {
    // 清空内容
    editorRef.value.innerHTML = '';
  }
  // 重置状态
  lastRange = null;
  lastInsertTime = 0;
  needsInput = false;
  inputValue.value = '';
  inputVisible.value = false;
  // 通知父组件内容清空
  emit('update:modelValue', '');
}

onMounted(() => {
  const events = ['input', 'keyup', 'mouseup', 'blur', 'focus'];
  events.forEach((ev) => editorRef.value && editorRef.value.addEventListener(ev, saveRange));
  // input 事件实时 emit 内容
  editorRef.value && editorRef.value.addEventListener('input', emitValue);
  // 当用户输入可见字符时，允许再次插入
  const inputHandler = (e) => {
    const text = editorRef.value ? editorRef.value.innerText.replace(/\u200B/g, '').trim() : '';
    if (text.length > 0) {
      needsInput = false;
    }
  }
  editorRef.value && editorRef.value.addEventListener('input', inputHandler);

  onBeforeUnmount(() => {
    events.forEach((ev) => editorRef.value && editorRef.value.removeEventListener(ev, saveRange));
    editorRef.value && editorRef.value.removeEventListener('input', emitValue);
    editorRef.value && editorRef.value.removeEventListener('input', inputHandler);
  });
})

// 暴露方法给父组件
defineExpose({
  reset
});
</script>

<style scoped lang="scss">
.wrap {
  width: 100%;
}

.tag_list {
  padding: 10px 0;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}

.tips {
  color: #999;
  font-size: 12px;
}

.editor_div {
  flex: 1;
  border: 1px solid #ddd;
  border-radius: 4px;
  min-height: 100px;
  padding: 10px 10px;
  transition: all .1s ease-in-out;

  &:focus {
    border-color: var(--el-color-primary);
  }

  /* 核心：placeholder样式 */
  &:empty:not(:focus):before {
    content: '请输入内容';
    /* placeholder文本 */
    color: rgb(168, 168, 168);
    /* 占位符颜色 */
    pointer-events: none;
    font-size: 14px;
    /* 点击时穿透到容器 */
  }
}
</style>