<template>
  <div class="flex contenteditable align-center space-between" :class="className">
    <p
      :id="'editor' + id"
      ref="editor"
      :contenteditable="active"
      class="van-field contenteditable-content"
      @focus="onFocus"
      v-html="modelValue"
    ></p>
    <div class="right-icon ml10">
      <slot name="right-icon"></slot>
    </div>
  </div>

  <div v-if="showAction && active" ref="editorAction" class="editor-action">
    <button v-for="item in actions" :key="item.name" @click="funEvent(item, $event)">
      <van-icon class-prefix="mobilefont" :name="item.icon"></van-icon>
    </button>
  </div>
</template>

<script setup>
import { defineEmits, ref, onMounted, watch } from 'vue';
import { v4 as uuidv4 } from 'uuid';
import CommonApi from '@/api/common.js';

const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  },
  className: {
    type: String,
    default: ''
  },
  active: {
    type: Boolean,
    default: false
  }
});

const id = ref(uuidv4());

const editor = ref(null);
const editorAction = ref(null);
const emit = defineEmits(['update:modelValue', 'blur']);
const save = (e) => {
  emit('update:modelValue', e.innerHTML);
};

const savedRange = ref(null);

const functions = {
  boldModern: () => {
    document.execCommand('bold', true, null);
  },
  underLine: () => {
    document.execCommand('underline', false, null);
  },
  italic: () => {
    document.execCommand('italic', false, null);
  },

  uploadImage: async () => {
    // 保存当前光标位置
    savedRange.value = saveSelection();

    const fileInput = document.createElement('input');
    fileInput.type = 'file';

    fileInput.click();

    fileInput.onchange = async (e) => {
      const [file] = e.target.files;
      if (!file) return;
      if (file.size > 2 * 1024 * 1024) {
        // console.error('文件大小不能超过2M');
        return;
      }

      const data = await CommonApi.cosUpload(file);
      const img = document.createElement('img');
      img.src = data.url;
      img.onload = () => {
        const scale = img.naturalHeight / 50;
        const width = (img.naturalWidth / scale).toFixed(0);
        const height = 50;
        const maxWidth = img.naturalWidth;
        const maxHeight = img.naturalHeight;
        const style = `style="width:${width}px;height:${height}px;max-width:${maxWidth}px;max-height:${maxHeight}px"`;
        insertImageAtCaret(`<img src=${data.url} ${style}/>`);

        // 恢复光标位置
        restoreSelection(savedRange.value);
      };
    };
  }
};

const funEvent = (item) => {
  functions[item.fun]();
};

watch(
  () => props.active,
  (newVal) => {
    if (newVal) {
      // showAction.value = true;
    } else {
      save(editor.value);
      setTimeout(() => {
        showAction.value = false;
      }, 100);
    }
  }
);

const showAction = ref(false);
const actions = [
  {
    label: '加粗',
    fun: 'boldModern',
    icon: 'jiacu'
  },
  {
    label: '下划线',
    fun: 'underLine',
    icon: 'xiahuaxian'
  },
  {
    label: '图片上传',
    fun: 'uploadImage',
    icon: 'tupian'
  },
  {
    label: '倾斜',
    fun: 'italic',
    icon: 'qingxie'
  }
];
const checkContains = (element, target) => {
  try {
    return element?.contains(target) ?? false;
  } catch (e) {
    return false;
  }
};

onMounted(() => {
  editor.value.addEventListener('focus', () => {
    showAction.value = true;
  });

  document.addEventListener('click', (e) => {
    if (!editor.value || !editorAction.value) return;

    const target = e.composedPath?.()?.[0] || e.target;
    const isEditor = checkContains(editor.value, target);
    const isActionBar = checkContains(editorAction.value, target);

    if (!isEditor && !isActionBar) {
      showAction.value = false;
      save(editor.value);
      emit('blur', editor.value);
    }
  });

  document.addEventListener('resize', () => {
    showAction.value = false;
  });
});

const onFocus = (e) => {
  // 阻止
  e.preventDefault();
  e.stopPropagation();
  // console.log('Editor focused');
};

// 保存当前光标位置
const saveSelection = () => {
  const selection = window.getSelection();
  if (selection.rangeCount === 0) return null;

  return selection.getRangeAt(0);
};

// 恢复光标位置
const restoreSelection = (range) => {
  if (!range) return;

  const selection = window.getSelection();
  selection.removeAllRanges();
  selection.addRange(range);
};

// 在光标位置插入图片
const insertImageAtCaret = (html) => {
  const selection = window.getSelection();
  if (selection.rangeCount === 0) return;

  const range = selection.getRangeAt(0);
  range.deleteContents();

  const div = document.createElement('div');
  div.innerHTML = html;
  const frag = document.createDocumentFragment();
  for (let child = div.firstChild; child; child = div.firstChild) {
    frag.appendChild(child);
  }

  range.insertNode(frag);
  range.setStartAfter(frag);
  range.collapse(true);

  selection.removeAllRanges();
  selection.addRange(range);
};
</script>

<style scoped lang="scss">
.contenteditable-content {
  width: 100%;
  height: 100%;
}

.right-icon {
  color: #c4c9d4;
}

.editor-action {
  position: fixed;
  bottom: 0;
  left: 0;
  z-index: 2008;
  display: flex;
  width: 100%;
  height: 40px;
  padding: 0 10px;
  background: #fff;
  line-height: 40px;

  & button {
    border: none;
    background: #fff;
    color: #000;
    outline: none;
  }

  button + button {
    margin-left: 10px;
  }
}
</style>
