<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-button :type="headerButtonType" @click="getFlow" class="ml-2">获取json</a-button> -->

          <a-space>
            <a-tooltip placement="bottom" class="ml-2" title="缩小视图">
              <a-button
                :disabled="process.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="process.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, defineEmits, watch, nextTick } from 'vue';
  import { ZoomOutOutlined } from '@ant-design/icons-vue';
  import { ZoomInOutlined } from '@ant-design/icons-vue';
  import { RotateLeftOutlined } from '@ant-design/icons-vue';
  import { RotateRightOutlined } from '@ant-design/icons-vue';
  import { ClearOutlined } from '@ant-design/icons-vue';
  // 生产环境时优化
  import BpmnModeler from 'bpmn-js/lib/Modeler';
  import DefaultEmptyXML from './plugins/defaultEmpty';
  // 翻译方法(汉化)
  import customTranslate from './plugins/translate/customTranslate';

  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';
  interface processType {
    defaultZoom: number;
    previewModelVisible: boolean;
    simulationStatus: boolean;
    previewResult: string;
    previewType: string;
    recoverable: boolean;
    revocable: boolean;
    bpmnModeler: any;
  }
  const process: processType = reactive({
    defaultZoom: 1,
    previewModelVisible: false,
    simulationStatus: false,
    previewResult: '',
    previewType: 'xml',
    recoverable: false,
    revocable: false,
    bpmnModeler: null,
  });
  const props = defineProps({
    processId: {
      type: String,
      default: '',
    },
    processName: {
      type: String,
      default: '',
    },
    value: String, // xml 字符串
    prefix: {
      type: String,
      default: 'flowable',
    },
    events: {
      type: Array,
      default: () => ['element.click'],
    },
    headerButtonSize: {
      type: String,
      default: 'small',
      validator: (value:any) => ['default', 'medium', 'small', 'mini'].indexOf(value) !== -1,
    },
    headerButtonType: {
      type: String,
      default: 'primary',
      validator: (value:any) =>
        ['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 });
    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;
    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');
    // 注册需要的监听事件, 将. 替换为 - , 避免解析异常
    props.events.forEach((event) => {
      EventBus.on(event, function (eventObj) {
        provide('wfdesign', eventObj);
        let eventName = event.replace('.', '-');
        console.log(eventName);
        let element = eventObj ? eventObj.element : null;
        emit(eventName, element, eventObj);
        emit('event', eventName, element, eventObj);
      });
    });
    process.bpmnModeler.on('element.click', ({ element }) => {
      if (element) {
        flowWfDataStore.setWfDataName(element.di.bpmnElement.id, element.di.bpmnElement.name);
      }
    });
    // 监听图形改变返回xml
    EventBus.on('commandStack.changed', async (event) => {
      console.log('commandStack.changed');
      await process.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
        const json = JSON.parse(convert.xml2json(xml, { spaces: 2 }));
        const flowElements = json.elements[0].elements[0].elements;
        for (var j = 0; j < flowElements.length; j++) {
          if (flowElements[j].attributes.name) {
            flowWfDataStore.setWfDataName(
              flowElements[j].attributes.id,
              flowElements[j].attributes.name,
            );
          }
        }
      });
      // 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('shape.added', (e) => {
      let addElement = e.element;
      let name = addElement.di.bpmnElement.name ? addElement.di.bpmnElement.name : '';
      if (name == '') {
        switch (addElement.type) {
          case 'bpmn:Task':
            name = '审核节点';
            nextTick(function () {
              const modeling = process.bpmnModeler.get('modeling');
              if (addElement.type == 'label') return;
              //除了task节点，其他节点都会生成一个label容器
              //所以不需要再给label节点添加，不然无法显示文字
              modeling.updateProperties(addElement, { name });
              flowWfDataStore.setWfDataName(addElement.id, name);
            });
            break;
          default:
            break;
        }
      }
    });
  }
  /* 创建新的流程图 */
  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 processRestart() {
    process.recoverable = false;
    process.revocable = false;
    createNewDiagram(null).then(() => process.bpmnModeler.get('canvas').zoom(1, 'auto'));
    flowWfDataStore.setWfDataAll([]);
  }
  /*-----------------------------    方法结束     ---------------------------------*/
  // function previewProcessXML() {
  //   // process.bpmnModeler.get('elementRegistry').get(图形id)
  //   // 通过图形id获取图形shape节点对象
  //   process.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
  //     console.log(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 });
  //     console.log(process.previewResult);
  //     process.previewType = 'json';
  //     process.previewModelVisible = true;
  //   });
  // }
  async function getFlow() {
    let flowContent;
    let flowElements;
    await process.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
      flowContent = xml;
      const json = JSON.parse(convert.xml2json(xml, { spaces: 2 }));
      flowElements = json.elements[0].elements[0].elements;
      flowWfDataStore.setElments(flowElements);
    });
    return flowContent;
  }
  defineExpose({
    getFlow,
  });
</script>
<style scoped>
  ::v-deep .bjs-container a {
    visibility: hidden;
  }
</style>
