<template>
  <div>
    <el-upload
      v-if="type === 'url'"
      :action="upload.url"
      :before-upload="handleBeforeUpload"
      :on-success="handleUploadSuccess"
      :on-error="handleUploadError"
      class="editor-img-uploader"
      name="file"
      :show-file-list="false"
      :headers="upload.headers"
    >
      <i ref="uploadRef"></i>
    </el-upload>
  </div>
  <div class="editor">
    <quill-editor
      ref="quillEditorRef"
      v-model:content="content"
      content-type="html"
      :options="options"
      :style="styles"
      @text-change="(e: any) => $emit('update:modelValue', content)"
    />
  </div>
</template>

<script setup lang="ts">
import '@vueup/vue-quill/dist/vue-quill.snow.css';

import { QuillEditor, Quill } from '@vueup/vue-quill';
import { propTypes } from '@/utils/propTypes';
import { globalHeaders } from '@/utils/request';

defineEmits(['update:modelValue']);

const props = defineProps({
  /* 编辑器的内容 */
  modelValue: propTypes.string,
  /* 高度 */
  height: propTypes.number.def(400),
  /* 最小高度 */
  minHeight: propTypes.number.def(400),
  /* 只读 */
  readOnly: propTypes.bool.def(false),
  /* 上传文件大小限制(MB) */
  fileSize: propTypes.number.def(5),
  /* 类型（base64格式、url格式） */
  type: propTypes.string.def('url')
});

const { proxy } = getCurrentInstance() as ComponentInternalInstance;

const upload = reactive<UploadOption>({
  headers: globalHeaders(),
  url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
});
const quillEditorRef = ref();
const uploadRef = ref<HTMLDivElement>();

const options = ref<any>({
  theme: 'snow',
  bounds: document.body,
  debug: 'warn',
  modules: {
    // 工具栏配置
    toolbar: {
      container: [
        ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
        ['blockquote', 'code-block'], // 引用  代码块
        [{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表
        [{ indent: '-1' }, { indent: '+1' }], // 缩进
        [{ size: ['small', false, 'large', 'huge'] }], // 字体大小
        [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
        [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
        [{ align: [] }], // 对齐方式
        ['clean'], // 清除文本格式
        ['link', 'image', 'video'] // 链接、图片、视频
      ],
      handlers: {
        image: (value: boolean) => {
          if (value) {
            // 调用element图片上传
            uploadRef.value.click();
          } else {
            Quill.format('image', true);
          }
        }
      }
    },
    clipboard: {
      matchVisual: false, // 关闭视觉换行
      matchers: [] // 清空所有匹配器
    }
  },
  placeholder: '请输入内容',
  readOnly: props.readOnly
});

const styles = computed(() => {
  const style: any = {};
  if (props.minHeight) {
    style.minHeight = `${props.minHeight}px`;
  }
  if (props.height) {
    style.height = `${props.height}px`;
  }
  return style;
});

const content = ref('');
watch(
  () => props.modelValue,
  (v: string) => {
    if (v !== content.value) {
      content.value = v || '<p></p>';
    }
  },
  { immediate: true }
);

// 图片上传成功返回图片地址
const handleUploadSuccess = (res: any) => {
  // 如果上传成功
  if (res.code === 200) {
    // 获取富文本实例
    const quill = toRaw(quillEditorRef.value).getQuill();
    // 获取光标位置
    const length = quill.selection.savedRange.index;
    // 插入图片，res为服务器返回的图片链接地址
    quill.insertEmbed(length, 'image', res.data.url);
    // 调整光标到最后
    quill.setSelection(length + 1);
    proxy?.$modal.closeLoading();
  } else {
    proxy?.$modal.msgError('图片插入失败');
    proxy?.$modal.closeLoading();
  }
};

// 图片上传前拦截
const handleBeforeUpload = (file: any) => {
  const type = ['image/jpeg', 'image/jpg', 'image/png', 'image/svg'];
  const isJPG = type.includes(file.type);
  //检验文件格式
  if (!isJPG) {
    proxy?.$modal.msgError(`图片格式错误!`);
    return false;
  }
  // 校检文件大小
  if (props.fileSize) {
    const isLt = file.size / 1024 / 1024 < props.fileSize;
    if (!isLt) {
      proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
      return false;
    }
  }
  proxy?.$modal.loading('正在上传文件，请稍候...');
  return true;
};
// 图片失败拦截
const handleUploadError = (err: any) => {
  proxy?.$modal.msgError('上传文件失败');
};
import { onMounted, nextTick } from 'vue';
import Delta from 'quill-delta';

onMounted(async () => {
  await nextTick();
  const quill = quillEditorRef.value?.getQuill();
  if (!quill) return;

  // 清空默认行为
  quill.clipboard.matchers = [];

  quill.clipboard.addMatcher(Node.ELEMENT_NODE, (node: HTMLElement, delta: Delta) => {
    const tempDiv = document.createElement('div');
    tempDiv.innerHTML = node.outerHTML;

    // ✅ 只清除 background 相关样式，保留 color
    cleanBackgroundOnly(tempDiv);

    // 构建 Delta（支持格式 + 列表）
    const newDelta = new Delta();
    buildDeltaWithListSupport(tempDiv, newDelta, {}, null);
    return newDelta;
  });
});

// ✅ 只清除 background，保留 color/font-size 等
function cleanBackgroundOnly(parent: HTMLElement) {
  if (parent.style) {
    parent.style.backgroundColor = '';
    parent.style.background = '';
    parent.style.color = '';
    parent.style.backgroundImage = '';
    parent.style.backgroundPosition = '';
    parent.style.backgroundRepeat = '';
    parent.style.backgroundSize = '';
    parent.style.backgroundAttachment = '';
    // ✅ 不动 color、font、size 等
  }

  Array.from(parent.children).forEach((child) => {
    if (child instanceof HTMLElement) {
      cleanBackgroundOnly(child);
    }
  });
}

// ✅ 支持列表的 Delta 构建
function buildDeltaWithListSupport(
  node: Node,
  delta: Delta,
  formatStack: { [key: string]: any },
  listType: 'ordered' | 'bullet' | null // 当前是否在列表中
) {
  if (node.nodeType === Node.TEXT_NODE) {
    const text = node.textContent || '';
    if (text.trim() || text === ' ') {
      delta.insert(text, formatStack);
    }
    return;
  }

  if (node.nodeType !== Node.ELEMENT_NODE) return;

  const el = node as HTMLElement;
  const tagName = el.tagName.toLowerCase();

  const currentFormat = { ...formatStack };
  let newListType: 'ordered' | 'bullet' | null = listType;

  // 处理列表开始
  if (tagName === 'ol') {
    newListType = 'ordered';
  }
  if (tagName === 'ul') {
    newListType = 'bullet';
  }

  // 处理列表项
  if (tagName === 'li') {
    if (listType) {
      // 标记为列表项
      currentFormat.list = listType;
    }
    // 如果 li 有嵌套 ol/ul，子项可能改变类型，但这里简化处理
  }

  // 添加内联格式
  if (tagName === 'strong' || tagName === 'b') {
    currentFormat.bold = true;
  }
  if (tagName === 'em' || tagName === 'i') {
    currentFormat.italic = true;
  }
  if (tagName === 'u' || el.style.textDecoration === 'underline') {
    currentFormat.underline = true;
  }
  if (tagName === 's' || tagName === 'strike') {
    currentFormat.strike = true;
  }

  // ✅ 保留颜色（关键！）
  if (el.style.color) {
    currentFormat.color = el.style.color;
  }
  if (el.style.fontSize) {
    currentFormat.size = el.style.fontSize; // 注意：Quill 的 size 是 small/large/huge 或值
  }
  if (el.style.fontFamily) {
    currentFormat.font = el.style.fontFamily.split(',')[0].trim().replace(/['"]/g, '');
  }

  // 是否是块级元素（需要换行）
  const isBlock = ['p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'br'].includes(tagName);

  // 遍历子节点
  for (let i = 0; i < el.childNodes.length; i++) {
    const child = el.childNodes[i];

    if (child.nodeType === Node.TEXT_NODE && isBlock && i === 0) {
      // 块级元素开头插入换行（除了第一个）
      if (delta.length() > 0) {
        delta.insert('\n');
      }
    }

    buildDeltaWithListSupport(child, delta, currentFormat, newListType);

    // 如果是块级元素且不是最后一个，加换行
    if (isBlock && i === el.childNodes.length - 1 && (el.nextSibling || el.parentNode !== el.ownerDocument?.body)) {
      if (!delta.ops.length || delta.ops[delta.ops.length - 1].insert !== '\n') {
        delta.insert('\n');
      }
    }
  }
}
/*

onMounted(async () => {
  await nextTick();
  const quill = quillEditorRef.value?.getQuill();
  if (!quill) return;

  // ✅ 1. 移除所有默认的 matcher，避免干扰
  quill.clipboard.matchers = [];

  // ✅ 2. 添加自定义 matcher：对所有元素节点，只提取 innerText
  quill.clipboard.addMatcher(Node.ELEMENT_NODE, (node: HTMLElement, delta: Delta) => {
    // 获取纯文本
    const text = node.innerText || node.textContent || '';

    // 返回一个新的 Delta，只包含纯文本，无任何格式
    return new Delta().insert(text);
  });

  // ✅ 3. 特别处理根节点是纯文本的情况（比如从记事本复制）
  quill.clipboard.addMatcher(Node.TEXT_NODE, (node: Text, delta: Delta) => {
    return new Delta().insert(node.data || '');
  });

  // ✅ 4. 可选：如果你希望保留换行，可以不做处理，Quill 会自动处理 p/br
  // 如果你想更激进地清理，也可以在这里统一处理

  console.log('[Clipboard] Custom matcher set, only plain text will be pasted.');
});


import { onMounted } from 'vue';

onMounted(() => {
  const quill = quillEditorRef.value.getQuill();
  debugger;
  // ✅ 2. 手动监听 paste 事件，完全由你控制
  quill.root.addEventListener('paste', async (e) => {
    e.preventDefault(); // ✅ 阻止浏览器默认行为

    const clipboardData = e.clipboardData || (e as any).originalEvent.clipboardData;
    const html = clipboardData.getData('text/html');
    const text = clipboardData.getData('text/plain');

    // 使用 HTML 优先，否则用纯文本
    const tempDiv = document.createElement('div');
    tempDiv.innerHTML = html || text;

    // 清理所有样式和 class
    const walk = (node: Node) => {
      if (node.nodeType === Node.ELEMENT_NODE) {

        const el = node as HTMLElement;
        el.style.cssText = '';
        el.removeAttribute('class');
        el.removeAttribute('style');

        // 特别清理 span 的内联样式
        if (el.tagName === 'SPAN') {
          el.style.color = '';
          el.style.backgroundColor = '';
          el.style.fontWeight = '';
          el.style.fontStyle = '';
          el.style.textDecoration = '';
        }

        Array.from(el.children).forEach((child) => walk(child));
      }
    };

    Array.from(tempDiv.childNodes).forEach(walk);

    const cleanHtml = tempDiv.innerHTML;
    const range = quill.getSelection();
    const index = range ? range.index : 0;
    // ✅ 调试：打印关键信息
    console.log('[Paste Debug]', { html, text, cleanHtml, index });

    // ✅ 插入清理后的内容
    quill.clipboard.dangerouslyPasteHTML(index, cleanHtml);

    // 可选：将光标移到末尾
    // setTimeout(() => {
    //   const length = quill.getLength();
    //   quill.setSelection(length, 0);
    // }, 10);
  });
});*/
</script>

<style>
.editor-img-uploader {
  display: none;
}
.editor,
.ql-toolbar {
  white-space: pre-wrap !important;
  line-height: normal !important;
}
.quill-img {
  display: none;
}
.ql-snow .ql-tooltip[data-mode='link']::before {
  content: '请输入链接地址:';
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  border-right: 0;
  content: '保存';
  padding-right: 0;
}
.ql-snow .ql-tooltip[data-mode='video']::before {
  content: '请输入视频地址:';
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
  content: '14px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before {
  content: '10px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before {
  content: '18px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before {
  content: '32px';
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
  content: '文本';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
  content: '标题1';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
  content: '标题2';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
  content: '标题3';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
  content: '标题4';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
  content: '标题5';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
  content: '标题6';
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
  content: '标准字体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before {
  content: '衬线字体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before {
  content: '等宽字体';
}

.editor .ql-editor {
  white-space: pre-wrap; /* 强制换行 */
  word-break: break-all; /* 防止长单词或URL溢出 */
}
</style>
