<script setup lang="ts">
import { onMounted, watch } from "vue";

const props = defineProps<{
  value: string;
}>();
const emit = defineEmits<{
  (e: "update:value", value: string): void;
  (e: "change", value: string): void;
}>();

let textValue = $ref("");
const editContentRef: Element = $ref();
let copyFragment: DocumentFragment = $ref();

function clearDomScriptTag(s: string) {
  const reg = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
  s = s.replace(reg, "");
  return s;
}

function toCopy() {
  const selection = window.getSelection();
  if (!selection) return;
  const range = selection.getRangeAt(0);
  if (range.collapsed) return;
  copyFragment = range.cloneContents();
}
function toCut() {
  const selection = window.getSelection();
  if (!selection) return;
  const range = selection.getRangeAt(0);
  if (range.collapsed) return;
  copyFragment = range.extractContents();
  textInput();
}
function toPaste() {
  if (!copyFragment) return;
  const selection = window.getSelection();
  if (!selection) return;
  const range = selection.getRangeAt(0);
  range.deleteContents();
  range.insertNode(copyFragment.cloneNode(true));
  textInput();
}
/**
 * 设置上标下标
 * @param type 类型，上标(sup)或下标(sub)
 * @param cancel 是否取消上标下标
 */
function toSupSub(type: "sub" | "sup", cancel: boolean) {
  const selection = window.getSelection();
  if (!selection) return;
  const range = selection.getRangeAt(0);
  if (range.collapsed) return;

  const selectFragment = range.cloneContents();
  const editContent = selectFragment.textContent as string;
  const fullFragment = range.commonAncestorContainer;

  console.dir(fullFragment.parentNode);
  if (
    fullFragment.parentNode &&
    ["SUP", "SUB"].includes(fullFragment.parentNode.nodeName)
  ) {
    const perNodeName = fullFragment.parentNode.nodeName;
    const [startOffset, endOffset] = [range.startOffset, range.endOffset];
    console.log(startOffset, endOffset);
    const fullContent = fullFragment.parentNode.textContent as string;
    range.selectNode(fullFragment.parentNode);
    range.deleteContents();
    // 后段
    const nextContent = fullContent.substring(endOffset);
    if (nextContent) {
      const nextDom = document.createElement(perNodeName);
      nextDom.appendChild(document.createTextNode(nextContent));
      range.insertNode(nextDom);
    }

    // 中段
    let midDom = null;
    if (cancel) {
      midDom = document.createTextNode(editContent);
      range.insertNode(midDom);
    } else {
      midDom = document.createElement(type);
      midDom.appendChild(document.createTextNode(editContent));
      range.insertNode(midDom);
    }

    // 前段
    const prevContent = fullContent.substring(0, startOffset);
    if (prevContent) {
      const prevDom = document.createElement(perNodeName);
      prevDom.appendChild(document.createTextNode(prevContent));
      range.insertNode(prevDom);
    }
    range.selectNode(midDom);
  } else {
    range.deleteContents();
    if (cancel) {
      const modDom = document.createTextNode(editContent);
      range.insertNode(modDom);
    } else {
      const modDom = document.createElement(type);
      modDom.appendChild(document.createTextNode(editContent));
      range.insertNode(modDom);
    }
  }

  textInput();
}

/** 操作上标下标中间内容时，将编辑整个上标下标块 */
// function toSupSub1(type: "sub" | "sup", cancel: boolean) {
//   const selection = window.getSelection();
//   if (!selection) return;
//   const range = selection.getRangeAt(0);
//   let selectFragment = range.cloneContents();
//   if (!selectFragment.textContent) return;

//   const fullFragment = range.commonAncestorContainer;
//   if (
//     fullFragment.parentNode &&
//     ["SUP", "SUB"].includes(fullFragment.parentNode.nodeName)
//   ) {
//     range.selectNode(fullFragment.parentNode);
//   }

//   selectFragment = range.cloneContents();
//   if (!selectFragment.textContent) return;

//   if (cancel) {
//     const modDom = document.createTextNode(selectFragment.textContent);
//     range.deleteContents();
//     range.insertNode(modDom);
//   } else {
//     const modDom = document.createElement(type);
//     modDom.appendChild(document.createTextNode(selectFragment.textContent));
//     range.deleteContents();
//     range.insertNode(modDom);
//   }
//   textInput();
// }

function textInput() {
  let content = editContentRef.innerHTML;
  content = clearDomScriptTag(content);
  content = content.replace(/<sub><\/sub>/g, "");
  content = content.replace(/<sup><\/sup>/g, "");
  textValue = content;
  emitInput(textValue);
}
function emitInput(val: string) {
  emit("update:value", val);
  emit("change", val);
}

function keydownEvent(e: KeyboardEvent) {
  if (e.ctrlKey || e.metaKey || e.altKey) {
    e.preventDefault();
    return false;
  }
  return true;
}

watch(
  () => props.value,
  (val) => {
    if (val !== textValue) {
      textValue = val;
      editContentRef.innerHTML = props.value;
    }
  }
);
onMounted(() => {
  editContentRef.innerHTML = props.value;
});
</script>

<template>
  <div class="text-edit">
    <div class="edit-menu">
      <n-button type="primary" size="small" @click="toCopy">复制</n-button>
      <n-button type="primary" size="small" @click="toCut">剪切</n-button>
      <n-button type="primary" size="small" @click="toPaste">粘贴</n-button>
      <n-button type="primary" size="small" @click="toSupSub('sup', false)"
        >上标</n-button
      >
      <n-button type="primary" size="small" @click="toSupSub('sup', true)"
        >取消上标</n-button
      >
      <n-button type="primary" size="small" @click="toSupSub('sub', false)"
        >下标</n-button
      >
      <n-button type="primary" size="small" @click="toSupSub('sub', true)"
        >取消下标</n-button
      >
    </div>
    <div
      ref="editContentRef"
      class="edit-content"
      :contenteditable="true"
      ondragstart="return false"
      ondrop="return false"
      @keydown="keydownEvent($event)"
      @input="textInput"
    ></div>
  </div>
</template>

<style scoped>
.edit-content {
  outline: none;
  border: 1px solid var(--app-color-border-dark);
  border-radius: var(--app-border-radius);
  padding: 10px;
  line-height: 20px;
  min-height: 100px;
  max-height: 300px;
  margin-top: 10px;
  overflow: auto;
}
.edit-content:focus {
  border-color: var(--app-color-primary);
}
</style>
