<template>
  <div class="my-process-designer">
    <div class="my-process-designer__header">
      <slot name="control-header"></slot>
      <template v-if="!$slots['control-header']">
        <div slot="content">
          <!-- <a-button :type="headerButtonType" :icon="h(SaveOutlined)" @click="onSave" class="ml-2">保存流程 </a-button> -->
          <!-- <a-button :type="headerButtonType" @click="previewProcessXML" class="ml-2">预览XML</a-button> -->
          <!-- <a-button :type="headerButtonType" @click="previewProcessJson" class="ml-2">预览JSON</a-button> -->
          <a-space>
            <a-tooltip placement="bottom" class="ml-2" title="缩小视图">
              <a-button :disabled="defaultZoom <= 0.3" :icon="h(ZoomOutOutlined)" @click="processZoomOut()"></a-button>
            </a-tooltip>
            <a-button>{{ Math.floor(process.defaultZoom * 10 * 10) + "%" }}</a-button>
            <a-tooltip placement="bottom" title="放大视图">
              <a-button :disabled="defaultZoom >= 3.9" :icon="h(ZoomInOutlined)" @click="processZoomIn()"></a-button>
            </a-tooltip>
            <a-tooltip placement="bottom" title="撤销" class="ml-2">
              <a-button :icon="h(RotateLeftOutlined)" @click="processUndo()"></a-button>
            </a-tooltip>
            <a-tooltip placement="bottom" title="恢复">
              <a-button :icon="h(RotateRightOutlined)" @click="processRedo()"></a-button>
            </a-tooltip>
            <a-tooltip placement="bottom" title="重新绘制">
              <a-button :icon="h(ClearOutlined)" @click="processRestart()"></a-button>
            </a-tooltip>
          </a-space>
        </div>

      </template>
      <div>
      </div>
    </div>
    <div class="my-process-designer__container">
      <div class="my-process-designer__canvas" ref="bpmn-canvas" id="bpmn-canvas"></div>
    </div>
    <a-modal v-model:open="process.previewModelVisible" width="60%" title="预览">
      <highlightjs :language="process.previewType" :code="process.previewResult" style="height: 60vh" />
    </a-modal>
  </div>
</template>

<script lang="ts" setup>
  import { h, provide, reactive, onMounted, defineProps, computed, defineEmits ,watch} from 'vue';
  import { SaveOutlined, ZoomOutOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
  // 生产环境时优化
  import BpmnModeler from "bpmn-js/lib/Modeler";
  import DefaultEmptyXML from "./plugins/defaultEmpty.ts";
  // 翻译方法(汉化)
  import customTranslate from "./plugins/translate/customTranslate.ts";

  import MoveModule from 'diagram-js/lib/features/move'
  import ModelingModule from 'bpmn-js/lib/features/modeling'
  import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'

  const emit = defineEmits(['init-finished', 'event', 'commandStack-changed', 'input', 'change', 'canvas-viewbox-changed', 'destroy', 'save', 'element-click', 'connection-added', 'connection-removed', 'connection-changed']);
  import { getDetail } from '@/api/sys/WFSchemeInfo'
  import { flowStore } from '@/store/modules/flow';
  const flowWfDataStore = flowStore();
  // 引入json转换与高亮
  import convert from "xml-js";
  const process = reactive({
    defaultZoom: 1,
    previewModelVisible: false,
    simulationStatus: false,
    previewResult: "",
    previewType: "xml",
    recoverable: false,
    revocable: false,
    bpmnModeler: null
  })
  const props = defineProps({
    value: String, // xml 字符串
    prefix: {
      type: String,
      default: "flowable"
    },
    events: {
      type: Array,
      default: () => ["element.click"]
    },
    headerButtonSize: {
      type: String,
      default: "small",
      validator: value => ["default", "medium", "small", "mini"].indexOf(value) !== -1
    },
    headerButtonType: {
      type: String,
      default: "primary",
      validator: value => ["default", "primary", "success", "warning", "danger", "info"].indexOf(value) !== -1
    },
    schemeCode: String,
    pageFlow: String,
    pageType: String,
  })
  watch(
    () => props.pageFlow,
    (newVal, oldVal) => {
      createNewDiagram(newVal)
    }
  )
  onMounted(() => {
    initBpmnModeler();
    createNewDiagram(props.value);
    if (props.schemeCode) {
      getDetailInfo(1)
    }
    if (props.pageType == 'detail') {
      createNewDiagram(props.pageFlow)
    }
  })
  async function getDetailInfo(a) {
    let data = await getDetail({ code: props.schemeCode })
    let scheme = JSON.parse(data.scheme.content);
    let wfData = scheme.wfData
    if (a == 1) {
      createNewDiagram(data.scheme.flowContent)
    }
  }
  function onSave() {
    return new Promise((resolve, reject) => {
      if (process.bpmnModeler == null) {
        reject();
      }
      process.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
        emit('save', xml);
        resolve(xml);
      });
    })
  }
  function initBpmnModeler() {
    if (process.bpmnModeler) return;
    const containerEl = document.querySelector('#bpmn-canvas');
    process.bpmnModeler = new BpmnModeler({
      container: '#bpmn-canvas',
      additionalModules: [
        {
          translate: ['value', customTranslate]
        },
      ],
    });
    emit("init-finished", process.bpmnModeler);
    initModelListeners();
  }
  function initModelListeners() {
    const EventBus = process.bpmnModeler.get("eventBus");
    const that = this;
    // 注册需要的监听事件, 将. 替换为 - , 避免解析异常
    props.events.forEach(event => {
      EventBus.on(event, function (eventObj) {
        provide('wfdesign', eventObj)
        let eventName = event.replace('.', "-");
        let element = eventObj ? eventObj.element : null;
        emit(eventName, element, eventObj);
        emit('event', eventName, element, eventObj);
      });
    });
    // 监听图形改变返回xml
    EventBus.on("commandStack.changed", async event => {
      try {
        process.recoverable = process.bpmnModeler.get("commandStack").canRedo();
        process.revocable = process.bpmnModeler.get("commandStack").canUndo();
        let { xml } = await process.bpmnModeler.saveXML({ format: true });
        emit("commandStack-changed", event);
        emit("input", xml);
        emit("change", xml);
      } catch (e) {
        console.error(`[Process Designer Warn]: ${e.message || e}`);
      }
    });
    // 监听视图缩放变化
    process.bpmnModeler.on("canvas.viewbox.changed", ({ viewbox }) => {
      emit("canvas-viewbox-changed", { viewbox });
      const { scale } = viewbox;
      process.defaultZoom = Math.floor(scale * 100) / 100;
    });
    // 监听选择事件，修改当前激活的元素以及表单
    process.bpmnModeler.on("selection.changed", ({ newSelection }) => {
    });
    process.bpmnModeler.on("element.changed", ({ element }) => {

    });
  }
  /* 创建新的流程图 */
  async function createNewDiagram(xml) {
    // 将字符串转换成图显示出来
    let newId = props.processId || `Process_${new Date().getTime()}`;
    let newName = props.processName || `业务流程_${new Date().getTime()}`;
    let xmlString = xml || DefaultEmptyXML(newId, newName, props.prefix);
    try {
      let { warnings } = await process.bpmnModeler.importXML(xmlString);
      if (warnings && warnings.length) {
        warnings.forEach(warn => console.warn(warn));
      }
    } catch (e) {
      console.error(`[Process Designer Warn]: ${e.message || e}`);
    }
  }


  function processRedo() {
    process.bpmnModeler.get("commandStack").redo();
  }
  function processUndo() {
    process.bpmnModeler.get("commandStack").undo();
  }
  function processZoomIn(zoomStep = 0.1) {
    let newZoom = Math.floor(process.defaultZoom * 100 + zoomStep * 100) / 100;
    if (newZoom > 4) {
      throw new Error("[Process Designer Warn ]: The zoom ratio cannot be greater than 4");
    }
    process.defaultZoom = newZoom;
    process.bpmnModeler.get("canvas").zoom(process.defaultZoom);
  }
  function processZoomOut(zoomStep = 0.1) {
    let newZoom = Math.floor(process.defaultZoom * 100 - zoomStep * 100) / 100;
    if (newZoom < 0.2) {
      throw new Error("[Process Designer Warn ]: The zoom ratio cannot be less than 0.2");
    }
    process.defaultZoom = newZoom;
    process.bpmnModeler.get("canvas").zoom(process.defaultZoom);
  }
  function processReZoom() {
    process.defaultZoom = 1;
    process.bpmnModeler.get("canvas").zoom("fit-viewport", "auto");
  }
  function processRestart() {
    process.recoverable = false;
    process.revocable = false;
    createNewDiagram(null).then(() => process.bpmnModeler.get("canvas").zoom(1, "auto"));
    flowWfDataStore.setWfDataAll([])
  }
  /*-----------------------------    方法结束     ---------------------------------*/
  function previewProcessXML() {
    process.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
      process.previewResult = xml;
      process.previewType = "xml";
      process.previewModelVisible = true;
    });
  }
  function previewProcessJson() {
    process.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
      process.previewResult = convert.xml2json(xml, { spaces: 2 });
      process.previewType = "json";
      process.previewModelVisible = true;
    });
  }
  async function getFlow() {
    let flowContent
    await process.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
      flowContent = xml;
    });
    return flowContent
  }
  defineExpose({
    getFlow
  })
</script>
<style scoped>
  ::v-deep .bjs-container a {
    visibility: hidden;
  }
</style>