<template>
  <div class="w-full h-full" ref="containerRef"></div>
</template>

<script setup lang="tsx">
import { ref, defineComponent, createApp, watch, nextTick } from 'vue'
import MindMap from 'simple-mind-map'
import { useElementSize, watchOnce } from '@vueuse/core'
import defaultTheme from './theme'
import { useResizeObserver } from '@vueuse/core'
import NodeItem from './NodeItem.vue'
import { useProjectStore } from '@/store/modules/project'
import { useAppStore } from '@/store/modules/app'
import { bfsWalk } from 'simple-mind-map/src/utils'
import { klona } from 'klona'

import type { NodeItemType, OptionType } from './type'
import { v4 } from 'uuid'

const containerRef = ref<HTMLElement | null>(null)
const { width, height } = useElementSize(containerRef)
const mindMap = ref<MindMap | null>(null)
const projectStore = useProjectStore()

// 监听容器尺寸变化
useResizeObserver(containerRef, () => {
  if (mindMap.value && width.value && height.value) {
    mindMap.value.resize()
  }
})

const mindMapData = ref<NodeItemType>()
const appStore = useAppStore()

watch(
  () => [projectStore.activeWidget, appStore.compositeTabAcitve],
  async () => {
    const widget = klona(projectStore.activeWidget)
    // 当前选择的最后一个元素且不是当前元素 切换
    if (widget && widget.id !== mindMapData.value?.id) {
      const data: NodeItemType = {
        id: widget.id,
        name: widget.name,
        nodeType: 'root',
        children: widget.events as unknown as any,
        config: null
      }
      // 添加增加节点
      bfsWalk(data, (child) => {
        if (child.children && child.nodeType !== 'action') {
          child.children.push(getAddNode(child.id, child.nodeType))
        }
      })
      mindMapData.value = data
      await nextTick()
      mindMap.value?.setData(mindMapData.value)
    }
  }
)

watch(
  () => mindMapData.value,
  () => {
    const data = klona(mindMapData.value)
    const item = projectStore.activeWidget
    if (data && item?.id === data.id) {
      // 移除添加按钮
      bfsWalk(data, (child) => {
        if (child.children) {
          child.children = child.children.filter((item) => item.nodeType !== 'add')
        }
      })
      item.events = data.children as unknown as any
    }
  },
  {
    immediate: true,
    deep: true
  }
)

// 刷新节点
const refresh = () => {
  mindMap.value?.updateData(mindMapData.value)
}

// 获取添加按钮
const getAddNode = (parentId: string, parentType: NodeItemType['parentType']): NodeItemType => {
  return {
    id: v4(),
    name: 'add_btn',
    nodeType: 'add',
    parentId,
    parentType
  }
}

// 添加节点
const handleAddNode = (parentId: string, parentType: string, values: OptionType[]) => {
  const nodes: NodeItemType[] = []
  switch (parentType) {
    case 'root':
      values.forEach((val) => {
        const id = v4()
        nodes.push({
          id,
          name: val.label,
          value: val.value,
          nodeType: 'event',
          config: {
            data: val?.data
          },
          children: [getAddNode(id, 'event')]
        })
      })
      break
    case 'event':
      values.forEach((val) => {
        const id = v4()
        // 自定义代码
        if (val.value === 'customCode') {
          nodes.push({
            id,
            name: val.label,
            value: val.value,
            nodeType: 'target',
            config: {
              data: val?.data
            },
            children: [
              {
                id: v4(),
                name: 'custom_code',
                value: '',
                nodeType: 'action',
                config: {}
              }
            ]
          })
        } else {
          nodes.push({
            id,
            name: val.label,
            nodeType: 'target',
            value: val.value,
            config: {
              data: val?.data
            },
            children: [getAddNode(id, 'target')]
          })
        }
      })
      break
    case 'target':
      values.forEach((val) => {
        const id = v4()
        nodes.push({
          id,
          name: val.value,
          nodeType: 'action',
          value: klona(val?.defaultValue),
          config: {
            data: val
          }
        })
      })
      break
  }
  bfsWalk(mindMapData.value, (node) => {
    if (parentId === node.id) {
      // 往倒数第二个位置插入
      node.children.splice(node.children.length - 1, 0, ...nodes)
    }
  })
  refresh()
}

// 删除节点
const handleDeleteNode = (id: string) => {
  bfsWalk(mindMapData.value, (node) => {
    if (node.children) {
      node.children = node.children.filter((item) => item.id !== id)
    }
  })
  refresh()
}

// 修改节点
const handleChangeNode = (node: NodeItemType) => {
  if (!node) return
  bfsWalk(mindMapData.value, (child) => {
    if (child.id === node.id) {
      child.name = node.name
      child.config = node.config
      child.value = node.value
    }
  })
}

watchOnce(
  () => [width.value, height.value],
  ([w, h]) => {
    if (w && h) {
      // 初始化思维导图
      // 配置参考：https://wanglin2.github.io/mind-map-docs/api/constructor/constructor-options.html
      mindMap.value = new MindMap({
        el: containerRef.value,
        themeConfig: defaultTheme,
        initRootNodePosition: ['5%', 'center'],
        fitPadding: 12,
        data: mindMapData.value,
        readonly: true,
        isUseCustomNodeContent: true,
        customCreateNodeContent: (node: any) => {
          const sourceData = node.nodeData
          const App = defineComponent({
            render() {
              return (
                <NodeItem
                  node={sourceData as NodeItemType}
                  onAdd={handleAddNode}
                  onDelete={handleDeleteNode}
                  onChange={handleChangeNode}
                />
              )
            }
          })

          // return你的自定义DOM节点
          let div = document.createElement('div')
          const app = createApp(App)
          div.style = 'user-select: none;'
          app.mount(div)

          return div
        }
      } as any)
      // 监听数据变化
      mindMap.value.on('data_change_detail', (data: any) => {
        console.log('date change detail', data)
      })
    }
  }
)
</script>
