<template>
  <div class="math-formula">
    <div :class="`math-formula-content ${id}`">
      <img v-if="mathTextareaValue" :src="imageUrl" :width="width" :height="height" />
      <span v-else>添加公式</span>
    </div>
    <Modal v-model:visible="visible" title="公式编辑器" width="1000px" wrap-class-name="math-formula-modal" cancel-text="取消" ok-text="保存" @ok="handleOk">
      <Tabs :activeKey="activeKey" @change="changePanel">
        <TabPane v-for="(mt, i) in mathTypeList" :key="i" :tab="mt.name" />
      </Tabs>
      <div v-if="visible" class="math-modal-content">
        <div class="math-modal-content-left">
          <div class="math-model-node" v-for="mc in mathTypeList[activeKey].children" @click="addTextareaValue(mc)" :key="mc">$${{ mc }}$$</div>
        </div>
        <div class="math-modal-content-right">
          <Textarea
            class="content-editor-input"
            v-model:value="mathTextareaValue"
            placeholder="请输入latex公式"
            @focus="setSelection"
            @blur="setSelection"
            @click="setSelection"
            @input="renderPreview"
            :auto-size="{ minRows: 5, maxRows: 6 }"
            allow-clear
          />
          <div class="content-editor-preview">
            {{ mathPreviewValue }}
          </div>
        </div>
      </div>
    </Modal>
  </div>
</template>
<script lang="ts">
import 'katex/dist/katex.css';
import renderMathInElement from 'katex/contrib/auto-render/auto-render';
import { Modal, Tabs, TabPane, Textarea } from 'ant-design-vue';
import { PropType, defineComponent, ref, reactive, nextTick, onMounted } from 'vue';
import { katexOption, mathList } from './constant';
import { MathValue } from './type';
import html2canvas from 'html2canvas';

export default defineComponent({
  name: 'math-comp',
  components: { Modal, Tabs, TabPane, Textarea },
  props: {
    value: { type: Object as PropType<MathValue>, required: true },
    defaultVisible: { type: Boolean, required: false },
    change: { type: Function as PropType<(item: any) => void> },
  },
  setup(props) {
    const { defaultVisible, value, change } = { ...props };
    const id = ref<string>(value.id);
    const width = ref<number>(value.width);
    const height = ref<number>(value.height);
    const imageUrl = ref<string>(value.imageUrl);
    const visible = ref<boolean>(defaultVisible);
    const activeKey = ref<number>(0);
    let mathTypeList = ref<any>(mathList);
    const mathTextareaValue = ref<string>(value.code || '');
    const mathPreviewValue = ref<string>('');
    const textareaSelectionInfo = reactive({
      start: -1,
      end: -1,
    });

    onMounted(() => {
      changePanel(0);
      renderMath();
    });

    const handleOk = (e: MouseEvent) => {
      console.log('mathTextareaValue', mathTextareaValue.value);
      nextTick(() => {
        const mathPreview = document.querySelector('.content-editor-preview span.katex') as HTMLDivElement;
        html2canvas(mathPreview, { scale: 2 }).then((canvas: any) => {
          let url = canvas.toDataURL('image/svg+xml');
          imageUrl.value = url;
          width.value = mathPreview.offsetWidth * 1.2;
          height.value = mathPreview.offsetHeight * 1.2;
          visible.value = false;
          if (change) {
            change({
              code: mathTextareaValue.value,
              width: width.value,
              height: height.value,
              imageUrl: imageUrl.value,
            });
          }
        });
      });
    };

    const changePanel = (index: any) => {
      activeKey.value = index;
      nextTick(() => {
        let nodeList = document.getElementsByClassName('math-model-node');
        for (let k = 0; k < nodeList.length; k++) {
          renderMathInElement(nodeList[k], katexOption);
        }
      });
    };

    const addTextareaValue = (tex: any) => {
      let textareaValue = mathTextareaValue.value;
      let start = textareaSelectionInfo.start;
      let end = textareaSelectionInfo.end;
      if (start === -1 && end === -1) {
        start = textareaValue.length;
        end = textareaValue.length;
      }
      const startStr = textareaValue.substring(0, start);
      const endStr = textareaValue.substring(end);
      mathTextareaValue.value = `${startStr}${tex}${endStr}`;
      console.log('addTextareaValue', start, end);
      renderMath();
    };

    const setSelection = () => {
      const textarea = document.querySelector('textarea.ant-input.content-editor-input') as HTMLTextAreaElement;
      if (!textarea) return;
      console.log('setSelection', textarea.selectionStart, textarea.selectionEnd);
      let textareaValue = mathTextareaValue.value;
      let start = textareaSelectionInfo.start;
      let end = textareaSelectionInfo.end;
      if (textareaValue.length === start && textareaValue.length === end) {
        textareaSelectionInfo.start = -1;
        textareaSelectionInfo.end = -1;
      } else {
        textareaSelectionInfo.start = textarea.selectionStart;
        textareaSelectionInfo.end = textarea.selectionEnd;
      }
    };

    const renderMath = () => {
      if (mathTextareaValue.value) {
        const mathPreview = document.querySelector('.content-editor-preview') as HTMLDivElement;
        if (!mathPreview) return;
        mathPreview.innerHTML = `$$${mathTextareaValue.value}$$`;
        nextTick(() => {
          renderMathInElement(mathPreview, katexOption);
        });
      }
    };

    const renderPreview = () => {
      setSelection();
      renderMath();
    };

    return {
      id,
      width,
      height,
      imageUrl,
      visible,
      activeKey,
      mathTypeList,
      mathTextareaValue,
      mathPreviewValue,
      changePanel,
      addTextareaValue,
      setSelection,
      renderPreview,
      handleOk,
    };
  },
});
</script>

<style lang="less">
.math-formula-content {
  max-width: 690px;
  overflow: auto;
}
.math-formula-modal {
  .ant-modal {
    overflow-y: hidden;
    .ant-modal-body {
      padding-top: 16px;
      padding-bottom: 16px;
      .math-modal-content {
        display: flex;
        .math-modal-content-left {
          width: 240px;
          height: 320px;
          overflow: auto;
          .math-model-node {
            cursor: pointer;
            border: 1px solid #ccc;
            margin: 0 5px 10px 5px;
            border-radius: 5px;
            transition: all 0.3s;
            &:hover {
              border: 1px solid #8f8d8d;
            }
          }
        }
        .math-modal-content-right {
          flex: 1;
          margin-left: 10px;
          overflow: auto;
          .content-editor-input {
            max-height: 180px;
            textarea {
              height: 180px !important;
              max-height: 180px !important;
            }
          }
          .content-editor-preview {
            height: 130px;
            margin-top: 10px;
            border: 1px solid #ccc;
            overflow: auto;
            display: flex;
            align-items: center;
            justify-content: center;
          }
        }
      }
    }
  }
}
</style>
