<template>
  <div class="containers">
    <div class="flow-viewer">
      <div class="process-status">
        <span class="intro">状态：</span>
        <div class="finish">已办理</div>
        <div class="processing">处理中</div>
        <div class="todo">未进行</div>
      </div>
      <!-- 流程图显示 -->
      <a-spin :spinning="loading" class="canvas-container">
        <div class="canvas" ref="flowCanvasRef"></div>
      </a-spin>
      <!--  按钮区域  -->
      <a-button-group class="button-group">
          <a-tooltip title="适中" placement="bottom">
            <a-button size="small" @click="fitViewport" class="tool-button">
              <FullscreenOutlined />
              <span class="button-text">适中</span>
            </a-button>
          </a-tooltip>
          <a-tooltip title="放大" placement="bottom">
            <a-button size="small" @click="zoomViewport(true)" class="tool-button">
              <ZoomInOutlined />
              <span class="button-text">放大</span>
            </a-button>
          </a-tooltip>
          <a-tooltip title="缩小" placement="bottom">
            <a-button size="small" @click="zoomViewport(false)" class="tool-button">
              <ZoomOutOutlined />
              <span class="button-text">缩小</span>
            </a-button>
          </a-tooltip>
        </a-button-group>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, watch, onMounted, onUnmounted } from 'vue'
import { CustomViewer as BpmnViewer } from '@/components/Process/common'
import { FullscreenOutlined, ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons-vue'

interface FlowData {
  xmlData: string
  nodeData?: NodeData[]
}

interface NodeData {
  key: string
  completed: boolean
}

interface Props {
  // 回显数据传值
  flowData?: FlowData
  procInsId?: string
}

const props = withDefaults(defineProps<Props>(), {
  flowData: () => ({} as FlowData),
  procInsId: ''
})

const bpmnViewer = ref<any>(null)
const flowCanvasRef = ref<HTMLElement | null>(null)
const loading = ref(true)
const zoom = ref(1)

// 监听flowData变化
watch(
  () => props.flowData,
  (newValue) => {
    if (newValue && Object.keys(newValue).length > 0) {
      // 生成实例
      if (bpmnViewer.value) {
        bpmnViewer.value.destroy()
      }
      
      if (flowCanvasRef.value) {
        bpmnViewer.value = new BpmnViewer({
          container: flowCanvasRef.value,
          height: 'calc(100vh - 200px)',
        })
        loadFlowCanvas(newValue)
      }
    }
  },
  { deep: true }
)

// 加载流程图片
const loadFlowCanvas = async (flowData: FlowData) => {
  try {
    if (!bpmnViewer.value) return
    
    await bpmnViewer.value.importXML(flowData.xmlData)
    await fitViewport()
    
    // 流程线高亮设置
    if (flowData.nodeData !== undefined && flowData.nodeData.length > 0 && props.procInsId) {
      await fillColor(flowData.nodeData)
    }
  } catch (err) {
    console.error(err.message, err.warnings)
  }
}

// 让图能自适应屏幕
const fitViewport = () => {
  if (!bpmnViewer.value) return
  
  zoom.value = bpmnViewer.value.get('canvas').zoom('fit-viewport', 'auto')
  loading.value = false
}

// 放大缩小
const zoomViewport = (zoomIn = true) => {
  if (!bpmnViewer.value) return
  
  zoom.value = bpmnViewer.value.get('canvas').zoom()
  zoom.value += zoomIn ? 0.1 : -0.1
  
  if (zoom.value >= 0.2) {
    bpmnViewer.value.get('canvas').zoom(zoom.value)
  }
}

// 设置高亮颜色
const fillColor = (nodeData: NodeData[]) => {
  if (!bpmnViewer.value) return
  
  const canvas = bpmnViewer.value.get('canvas')
  const flowElements = bpmnViewer.value.getDefinitions().rootElements[0].flowElements
  
  flowElements.forEach((n: any) => {
    const completeTask = nodeData.find(m => m.key === n.id)
    const todoTask = nodeData.find(m => !m.completed)
    const endTask = nodeData[nodeData.length - 1]
    
    if (n.$type === 'bpmn:UserTask') {
      if (completeTask) {
        canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo')
        n.outgoing?.forEach((nn: any) => {
          const targetTask = nodeData.find(m => m.key === nn.targetRef.id)
          if (targetTask) {
            if (todoTask && completeTask.key === todoTask.key && !todoTask.completed) {
              canvas.addMarker(nn.id, todoTask.completed ? 'highlight' : 'highlight-todo')
              canvas.addMarker(nn.targetRef.id, todoTask.completed ? 'highlight' : 'highlight-todo')
            } else {
              canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo')
              canvas.addMarker(nn.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo')
            }
          }
        })
      }
    }

    else if (n.$type === 'bpmn:ExclusiveGateway') {
      if (completeTask) {
        canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo')
        n.outgoing?.forEach((nn: any) => {
          const targetTask = nodeData.find(m => m.key === nn.targetRef.id)
          if (targetTask) {
            canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo')
            canvas.addMarker(nn.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo')
          }
        })
      }
    }

    else if (n.$type === 'bpmn:ParallelGateway') {
      if (completeTask) {
        canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo')
        n.outgoing?.forEach((nn: any) => {
          const targetTask = nodeData.find(m => m.key === nn.targetRef.id)
          if (targetTask) {
            canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo')
            canvas.addMarker(nn.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo')
          }
        })
      }
    } else if (n.$type === 'bpmn:StartEvent') {
      n.outgoing.forEach((nn: any) => {
        const completeTask = nodeData.find(m => m.key === nn.targetRef.id)
        if (completeTask) {
          canvas.addMarker(nn.id, 'highlight')
          canvas.addMarker(n.id, 'highlight')
          return
        }
      })
    } else if (n.$type === 'bpmn:EndEvent') {
      if (endTask.key === n.id && endTask.completed) {
        canvas.addMarker(n.id, 'highlight')
        return
      }
    }
  })
}

onUnmounted(() => {
  if (bpmnViewer.value) {
    bpmnViewer.value.destroy()
  }
})
</script>

<style lang="scss">
@use "../style/flow-viewer.scss" as *;
</style>
