<template>
  <div>
    <p v-if="config.page.length === 0"> 未选中任何工作空间 </p>
    <a-tree
      v-if="showTree"
      defaultExpandAll
      show-icon
      @select="handleTreeSelect"
      :selectedKeys="selectedKeys"
      style="overflow: hidden"
      :draggable="true"
      @drop="treeDrop"
      :tree-data="treeData">
      <!--   右键菜单   -->
      <template #title="{ key: treeKey, title }">
        <a-dropdown :trigger="['contextmenu']">
          <span>{{ title }}</span>
          <template #overlay>
            <a-menu @click="({ key: menuKey }) => onContextMenuClick(treeKey, menuKey)">
              <a-menu-item key="copy"><a-icon type="copy" />&nbsp;&nbsp;复制</a-menu-item>
              <a-menu-item key="paste" :disabled="copyCache === undefined"><a-icon type="snippets" />&nbsp;&nbsp;粘贴</a-menu-item>
              <a-menu-divider />
              <a-menu-item key="split" :disabled="determineLevel(treeKey) !== 'item'"><a-icon type="fullscreen" />&nbsp;&nbsp;拆分</a-menu-item>
              <a-menu-item key="add" :disabled="determineLevel(treeKey) === 'item'"><a-icon type="plus-square" />&nbsp;&nbsp;添加</a-menu-item>
              <a-menu-item key="rename" :disabled="determineLevel(treeKey) !== 'item' && determineLevel(treeKey) !== 'page'"><a-icon type="italic" />&nbsp;&nbsp;重命名</a-menu-item>
              <a-menu-divider />
              <a-menu-item key="delete"><a-icon type="delete" />&nbsp;&nbsp;删除</a-menu-item>
            </a-menu>
          </template>
        </a-dropdown>
      </template>
      <!--   树中的图标   -->
      <a-icon slot="file" type="file" />
      <a-icon slot="appstore" type="appstore" />
      <a-icon slot="pause" type="pause" />
      <a-icon slot="ordered-list" type="ordered-list" />
    </a-tree>
    <!--  页面容器重命名弹框  -->
    <a-modal
      title="页面容器重命名"
      width="60%"
      :z-index="1001"
      :destroyOnClose="true"
      @ok="handleRenameModalOk"
      @cancel="() => { showRenameModal = false }"
      :visible="showRenameModal">
      <a-form :label-col="{ span: 7 }" :wrapper-col="{ span: 12 }">
        <!--    新名称    -->
        <a-form-item label="新名称">
          <a-input v-model="pageNewName"/>
        </a-form-item>
      </a-form>
    </a-modal>
  </div>
</template>

<script>
import * as lowcodeUtils from '@vue2-client/utils/lowcode/lowcodeUtils'
export default {
  props: {
    config: {
      type: Object,
      required: true,
    },
    // 可以由外侧控制哪个节点被选中
    selectTreeNode: {
      type: String,
      default: undefined
    }
  },
  methods: {
    // 重命名弹框确认
    handleRenameModalOk () {
      this.$emit('rename', this.renameId, this.pageNewName)
      this.renameId = undefined
      this.showRenameModal = false
    },
    // 根据id返回类型
    determineLevel (id) {
      if (id.startsWith('page')) {
        return 'page'
      } else if (id.startsWith('container_page_')) {
        return 'container_page'
      } else if (id.startsWith('row')) {
        return 'row'
      } else {
        return 'item'
      }
    },
    // 将树中的key转换回原始ID
    getOriginalKey (treeKey) {
      if (treeKey.startsWith('page')) {
        return treeKey.substring('page_'.length)
      } else if (treeKey.startsWith('container_page_')) {
        return treeKey.substring('container_page_'.length)
      } else if (treeKey.startsWith('row')) {
        const newRowId = treeKey.substring('row_'.length)
        const lastIndex = newRowId.lastIndexOf('_')
        const pre = newRowId.substring(0, lastIndex)
        const index = newRowId.substring(lastIndex + 1)
        const newIndex = Number(index) - 1
        return pre + '_' + newIndex
      } else {
        return treeKey
      }
    },
    // 根据ID，返回拖拽级别和类型，便于拖拽模式判断
    determineDragLevel (id) {
      if (id.startsWith('page')) {
        return {
          type: 'page',
          level: 0
        }
      } else if (id.startsWith('container_page_')) {
        return {
          type: 'container_page',
          level: 2
        }
      } else if (id.startsWith('row')) {
        return {
          type: 'row',
          level: 1
        }
      } else {
        return {
          type: 'item',
          level: 2
        }
      }
    },
    // 树拖拽事件
    treeDrop (info) {
      // 拖拽结束目标的id
      const dropKey = info.node.eventKey
      // 被拖拽的id
      const dragKey = info.dragNode.eventKey
      // 拖拽目标的位置
      const dropPos = info.node.pos.split('-')

      // 拖拽结束目标的类型
      const dropLevel = this.determineDragLevel(dropKey)
      // 被拖拽的类型
      const dragLevel = this.determineDragLevel(dragKey)

      // 拖拽对于目标的定位，-1表示之前，0表示插入，1表示之后
      const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])

      // 以下几种为非法拖拽
      // 1. 平级移动但是目标是新增
      // 2. 高一级移动但不是新增
      // 3. 高级组件移动到低级
      // 4. 相差2级移动
      // 唯一特例，行可以插入容器页面，容器页面等于模块级别，但可以被行插入

      // 只有三种情况可以拖拽
      // 1.平级挪
      // 2.高一级插
      // 3.行插子页面
      // 4.平级插入改为替换双方位置（特例）

      // 1. 平级挪
      if (dropLevel.level === dragLevel.level && dropPosition !== 0) {
        const dragType = 'move'
        this.$emit('componentMove', this.getOriginalKey(dragKey), this.getOriginalKey(dropKey), dragLevel, dropLevel, dropPosition, dragType)
        return
      }

      // 2.高一级插
      if (dropLevel.level === (dragLevel.level - 1) && dropPosition === 0) {
        const dragType = 'higher'
        this.$emit('componentMove', this.getOriginalKey(dragKey), this.getOriginalKey(dropKey), dragLevel, dropLevel, dropPosition, dragType)
        return
      }

      // 3.行插子页面
      if (dragLevel.type === 'row' && dropLevel.type === 'container_page' && dropPosition === 0) {
        const dragType = 'rowToContainer'
        this.$emit('componentMove', this.getOriginalKey(dragKey), this.getOriginalKey(dropKey), dragLevel, dropLevel, dropPosition, dragType)
        return
      }

      // 4.平级插入改为替换双方位置（特例）
      if (dropLevel.level === dragLevel.level && dropPosition === 0) {
        const dragType = 'switch'
        this.$emit('componentMove', this.getOriginalKey(dragKey), this.getOriginalKey(dropKey), dragLevel, dropLevel, dropPosition, dragType)
        return
      }

      // 能到这不return的证明都是非法移动
      this.$message.error('不合法的拖拽！')
    },
    // 删除
    handleDelete (targetType, originalKey) {
      const _this = this
      if (targetType === 'item') {
        this.$confirm({
          title: `确认删除此组件？`,
          content: `组件ID：${originalKey}`,
          onOk () {
            _this.$emit('deleteComponent', originalKey, 'component')
          },
          onCancel () {},
        })
      } else if (targetType === 'page') {
        const page = lowcodeUtils.getPageConfigById(originalKey, this.config)
        this.$confirm({
          title: `确认删除此页面？`,
          content: `所选页面：${page.title}[${lowcodeUtils.resolvePageType(page.type)}]`,
          onOk () {
            _this.$emit('deleteComponent', originalKey, 'page')
          },
          onCancel () {},
        })
      } else if (targetType === 'row') {
        this.$confirm({
          title: `确认删除此行？`,
          content: `所选行：${originalKey}`,
          onOk () {
            _this.$emit('deleteComponent', originalKey, 'row')
          },
          onCancel () {},
        })
      } else if (targetType === 'container_page') {
        this.$confirm({
          title: `确认删除此容器页面？`,
          content: `所选容器：${originalKey}`,
          onOk () {
            _this.$emit('deleteComponent', originalKey, 'container_page')
          },
          onCancel () {},
        })
      }
    },
    // 复制
    handleCopy (treeKey, targetType) {
      const originalKey = this.getOriginalKey(treeKey)
      // 获取复制对象
      let temp
      if (targetType === 'container_page') {
        temp = lowcodeUtils.getContainerPageOuterByContainerPageId(originalKey, this.config)
      } else {
        temp = lowcodeUtils.getConfig(originalKey, this.config)
      }
      // 复制
      let copy = JSON.parse(JSON.stringify(temp))
      if (targetType === 'page') {
        // 重新修改id和title
        copy.id = 'page_' + lowcodeUtils.nanoidWithoutSymbol(6)
        copy.title = copy.title + '_副本'
        // 复制页面自动粘贴
        this.$emit('pasteItem', originalKey, copy, 'page')
      } else {
        if (targetType === 'row') {
          // 将行内每个组件重新修改id
          const target = copy.body
          copy.id = 'undefine'
          target.forEach(item => {
            if (item.type === 'container_page') {
              item.id = 'container_' + lowcodeUtils.nanoidWithoutSymbol(6)
              item = lowcodeUtils.reRandomComponentId(item)
            } else {
              const prefix = item.id.split('_')[0]
              item.id = prefix + '_' + lowcodeUtils.nanoidWithoutSymbol(6)
            }
          })
        } else if (targetType === 'item') {
          // 重新修改id
          const prefix = copy.id.split('_')[0]
          copy.id = prefix + '_' + lowcodeUtils.nanoidWithoutSymbol(6)
        } else if (targetType === 'container_page') {
          // 重新修改id
          copy.id = 'container_' + lowcodeUtils.nanoidWithoutSymbol(6)
          copy = lowcodeUtils.reRandomComponentId(copy)
        }
        this.copyCache = {
          type: targetType,
          content: copy
        }
        this.$message.success('复制成功！')
      }
    },
    // 粘贴
    handlePaste (targetType, originalKey) {
      // 同级别内容不能粘贴到另一个中
      if (targetType === this.copyCache.type) {
        this.$message.error('该操作不合法！')
        return
      }

      // 行只能复制到容器页面和页面中
      if (this.copyCache.type === 'row') {
        if (targetType === 'page' || targetType === 'container_page') {
          this.$emit('pasteItem', originalKey, this.copyCache, 'page-row')
          return
        }
      }

      // 模块，容器页面只能复制到行
      if (this.copyCache.type === 'item' || this.copyCache.type === 'container_page') {
        if (targetType === 'row') {
          this.$emit('pasteItem', originalKey, this.copyCache, 'row-item')
          return
        }
      }

      // 其余操作均不合法
      this.$message.error('该操作不合法！')
    },
    // 重命名
    handleRename (targetType, originalKey) {
      const target = lowcodeUtils.getConfig(originalKey, this.config)
      this.renameId = target.id
      if (target.title) {
        this.pageNewName = target.title
      } else if (target.name) {
        this.pageNewName = target.name
      } else {
        this.pageNewName = target.id
      }
      this.showRenameModal = true
    },
    // 拆分
    handleSplit (originalKey) {
      const _this = this
      this.$confirm({
        title: `是否垂直拆分？`,
        onOk () {
          _this.$emit('split', originalKey, true)
        },
        onCancel () {
          _this.$emit('split', originalKey, false)
        },
      })
    },
    // 添加
    handleAdd (targetType, originalKey) {
      if (targetType === 'page' || targetType === 'container_page') {
        this.$emit('add', originalKey, 'row')
      } else if (targetType === 'row') {
        this.$emit('add', originalKey, 'container')
      }
    },
    // 树右键事件
    onContextMenuClick (treeKey, menuKey) {
      // 判断目标类型
      const targetType = this.determineLevel(treeKey)
      const originalKey = this.getOriginalKey(treeKey)
      // 点击右键菜单中删除的事件
      switch (menuKey) {
        case 'delete':
          this.handleDelete(targetType, originalKey)
          return
        case 'copy':
          this.handleCopy(treeKey, targetType)
          return
        case 'paste':
          this.handlePaste(targetType, originalKey)
          return
        case 'rename':
          this.handleRename(targetType, originalKey)
          return
        case 'split':
          this.handleSplit(originalKey)
          return
        case 'add':
          this.handleAdd(targetType, originalKey)
      }
    },
    // 处理架构树点击事件
    handleTreeSelect (value) {
      // 如果是反选
      if (value.length === 0) {
        return
      }
      this.selectedKeys = value
      const type = this.determineLevel(value[0])
      if (type === 'page') {
        this.$emit('treeOrganizationClick', null)
      }
      this.$emit('treeOrganizationClick', this.getOriginalKey(value[0]))
    },
    // 初始化树
    initTree (config, container = undefined) {
      const result = []
      // 从配置中，抽取组件，初始化成树的格式
      for (let i = 0; i < config.page.length; i++) {
        // push第一级页面容器
        const page = config.page[i]
        let title, icon, key
        if (page.title) {
          title = page.title + '(' + lowcodeUtils.resolvePageType(page.type) + ')'
          icon = 'file'
          key = 'page_' + page.id
        } else {
          title = '列容器'
          icon = 'pause'
          key = 'container_page_' + page.id
        }
        result.push({
          title: title,
          key: key,
          children: [],
          slots: {
            icon: icon,
          },
        })
        // 在页面容器中，push第二级行容器
        for (let j = 0; j < page.body.length; j++) {
          const row = page.body[j]
          result[i].children.push({
            title: '行容器' + (j + 1),
            key: 'row_' + page.id + '_' + (j + 1),
            children: [],
            slots: {
              icon: 'ordered-list',
            },
          })
          // 在行容器中，push第三级组件
          for (let k = 0; k < row.body.length; k++) {
            const item = row.body[k]
            let name
            if (item.name) {
              name = item.name
            } else {
              name = item.id
            }
            // 如果item进行了嵌套，递归调用
            if (item.type === 'container_page') {
              this.initTree(item, result[i].children[j])
            } else {
              // 如果是container则显示为列容器
              if (item.type === 'container') {
                name = '列容器'
                result[i].children[j].children.push({
                  title: name,
                  key: item.id,
                  children: [],
                  slots: {
                    icon: 'pause',
                  },
                })
              } else {
                result[i].children[j].children.push({
                  title: name,
                  key: item.id,
                  children: [],
                  slots: {
                    icon: 'appstore',
                  },
                })
              }
            }
          }
        }
      }
      if (!container) {
        this.treeData = result
      } else {
        container.children = container.children.concat(result)
      }
    },
  },
  mounted () {
    this.initTree(this.config)
    this.showTree = true
  },
  data () {
    return {
      // 树的数据
      treeData: [],
      // 控制树的渲染
      showTree: false,
      // 控制重命名弹框显隐
      showRenameModal: false,
      // 复制的缓存
      copyCache: undefined,
      // 重命名绑定变量
      pageNewName: undefined,
      // 重命名对象的id
      renameId: undefined,
      // 在树中已选中的key
      selectedKeys: []
    }
  },
  watch: {
    // 如果外侧指定了某个节点，让树选中该节点
    selectTreeNode: {
      handler (newVal) {
        if (newVal) {
          this.selectedKeys = [newVal]
        } else {
          this.selectedKeys = []
        }
      }
    }
  }
}
</script>

<style scoped lang="less">

</style>
