<template>
  <AppHierarchyTree ref="tree" :key="key" :context="_self" :load-tree-data="loadAppTreeData" />
</template>

<script>
import { Tree, Icon, Button, Input, message, Spin, Modal } from 'ant-design-vue'
import OrgService from './org-service'
import components from './_import-components/sd-org-hiera-app-import'

const AppHierarchyTree = {
  props: {
    context: {
      type: Object,
      default: () => {},
    },
    loadTreeData: {
      type: Function,
      default: undefined,
    },
  },
  data() {
    return {
      treeData: [],
      searchValue: '',
      expandedKeys: [],
      dataList: [],
      loading: true,
      autoExpandParent: false,
    }
  },
  created() {
    this.loadTreeData?.()
      .then((data) => {
        this.treeData = data
        this.generateList(this.treeData)
      })
      .finally(() => {
        this.loading = false
      })
  },
  methods: {
    generateList(treeData) {
      for (let i = 0; i < treeData.length; i++) {
        const node = treeData[i]
        const key = node.id
        const title = node.text
        const props = node.props
        this.dataList.push({ key, id: key, title: title, props })
        if (node.children) {
          this.generateList(node.children)
        }
      }
    },
    getParentKey(key, tree) {
      let parentKey
      for (let i = 0; i < tree.length; i++) {
        const node = tree[i]
        if (node.children) {
          if (node.children.some((item) => item.id === key)) {
            parentKey = node.id
          } else if (this.getParentKey(key, node.children)) {
            parentKey = this.getParentKey(key, node.children)
          }
        }
      }
      return parentKey
    },
    onSearchChange(e) {
      const value = e.target.value
      const expandedKeys = this.dataList
        .map((item) => {
          if (item.title.indexOf(value) > -1) {
            return this.getParentKey(item.key, this.treeData)
          }
          return null
        })
        .filter((item, i, self) => item && self.indexOf(item) === i)

      Object.assign(this, {
        expandedKeys,
        searchValue: value,
        autoExpandParent: true,
      })
    },
    loadData(treeNode) {
      return new Promise((resolve) => {
        if (treeNode.dataRef.children) {
          resolve()
        } else {
          this.loadTreeData?.(treeNode.dataRef.id).then((children) => {
            treeNode.dataRef.children = children
            this.treeData = [...this.treeData]
            this.generateList(children)
            resolve()
          })
        }
      })
    },
    refresh(node) {
      // 按节点更新
      if (node) {
        // 先获取节点路径
        const path = [node.key]
        let parentKey = this.getParentKey(node.key, this.treeData)
        while (parentKey) {
          path.unshift(parentKey)
          parentKey = this.getParentKey(parentKey, this.treeData)
        }
        // 获取当前node对应的树(根节点)
        const rootNode = this.treeData.find((t) => t.key === path[0])
        // 重新获取树
        this.loadTreeData?.().then((data) => {
          const updateProperty = (src, data, path) => {
            const key = path.shift()
            const newNode = data.find((d) => d.key === key)
            // 更新除子节点外的属性
            Object.keys(newNode).forEach((k) => {
              if (k !== 'children') {
                src[k] = newNode[k]
              }
            })
            if (path.length > 0) {
              const subSrc = src.children.find((n) => n.key === path[0])
              if (newNode.children) {
                updateProperty(subSrc, newNode.children, path)
              } else {
                this.loadTreeData?.(newNode.id).then((children) => {
                  updateProperty(subSrc, children, path)
                })
              }
            } else {
              // 最后一个节点：有子节点，直接替换
              if (newNode.children) {
                src.children = newNode.children
              } else if (src.children?.length > 0 && !newNode.children) {
                // 判断节点展开过 且 无子节点，则需获取对应的子节点
                this.loadTreeData?.(newNode.id).then((children) => {
                  src.children = children
                })
              }
            }
          }
          updateProperty(rootNode, data, path)
        })
      }
    },
  },
  render() {
    const getTitle = (data) => {
      const title = data.title
      const index = title.indexOf(this.searchValue)
      const iconType =
        data.props.nodeType === 'APP_GROUP'
          ? 'appstore'
          : data.props.nodeType === 'WE_APP'
          ? 'sd-module'
          : data.props.nodeType === 'WE_APP_MODULE'
          ? 'profile'
          : 'sd-3-circle'
      return (
        <div class={this.context.$style.treeNode}>
          <span title={title} class={this.context.$style.title}>
            <Icon type={iconType} />
            {index !== -1
              ? [
                  title.substr(0, index),
                  <span class={this.context.$style.active}>{this.searchValue}</span>,
                  title.substr(index + this.searchValue.length),
                ]
              : title}
          </span>
          {data.props.hierarchyAuth === 'true' ? '(已下放)' : ''}
          {data.props.nodeType !== 'APP_GROUP' ? (
            data.props.hierarchyAuth === 'true' ? (
              <Button
                type='link'
                size='small'
                loading={this.context.loadingBtn[data.id]}
                onClick={() => this.context.takeBack(data)}
              >
                收回
              </Button>
            ) : (
              <Button
                type='link'
                size='small'
                loading={this.context.loadingBtn[data.id]}
                onClick={() => this.context.Issued(data)}
              >
                下放
              </Button>
            )
          ) : (
            ''
          )}
        </div>
      )
    }
    return (
      <Spin spinning={this.loading}>
        <Input.Search
          value={this.searchValue}
          placeholder='请输入搜索条件'
          allowClear
          onChange={this.onSearchChange}
        />
        <Tree
          blockNode
          showIcon
          treeData={this.treeData}
          loadData={this.loadData}
          autoExpandParent={this.autoExpandParent}
          expandedKeys={this.expandedKeys}
          selectable={false}
          scopedSlots={{
            title: ({ dataRef }) => getTitle(dataRef),
          }}
          onExpand={(expandedKeys) => {
            this.expandedKeys = expandedKeys
            this.autoExpandParent = false
          }}
        />
      </Spin>
    )
  },
}

export default {
  name: 'SdOrgHieraApp',
  components: {
    ...components,
    AppHierarchyTree,
  },
  props: {
    unid: {
      type: String,
      default: undefined,
    },
  },
  data() {
    return {
      key: 0,
      loadingBtn: {},
    }
  },
  methods: {
    init() {
      this.key++
    },
    loadAppTreeData(id) {
      const params = { groupId: this.unid }
      if (id) {
        params.appId = id
      }
      return OrgService.getAppTransferTree(params).then((res) => {
        return this.transTreeData(res.data)
      })
    },
    transTreeData(data) {
      return data.map((d) => {
        const { children, ...rest } = d
        return {
          ...rest,
          key: d.id,
          title: d.text,
          isLeaf: d.leaf,
          children: children && this.transTreeData(children),
          scopedSlots: { title: 'title' },
        }
      })
    },
    // 下放
    Issued(node) {
      Modal.confirm({
        title: '确认下放吗？',
        onOk: () => {
          this.$set(this.loadingBtn, node.id, true)
          OrgService.appIssued({
            groupId: this.unid,
            nodeId: node.id,
            nodeType: node.props.nodeType,
          })
            .then((res) => {
              if (res.status === 200) {
                message.success('下放成功！')
                this.$refs.tree.refresh(node)
              }
            })
            .finally(() => {
              this.$delete(this.loadingBtn, node.id)
            })
        },
      })
    },
    // 回收
    takeBack(node) {
      Modal.confirm({
        title: '确认收回吗？',
        onOk: () => {
          this.$set(this.loadingBtn, node.id, true)
          OrgService.appTakeBack({
            groupId: this.unid,
            nodeId: node.id,
            nodeType: node.props.nodeType,
          })
            .then((res) => {
              if (res.status === 200) {
                message.success('回收成功！')
                this.$refs.tree.refresh(node)
              }
            })
            .finally(() => {
              this.$delete(this.loadingBtn, node.id)
            })
        },
      })
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
.tree-node {
  display: flex;
  .title {
    overflow: hidden;
    text-overflow: ellipsis;
    :global(.anticon) {
      margin-right: 5px;
    }
    .active {
      color: $primary-color;
    }
  }
  button {
    display: none;
  }
  &:hover button {
    display: inline;
  }
}
.extra {
  float: right;
}
.searchdiv {
  margin-left: 10px;
  :global(.ant-input-search) {
    width: 200px;
  }
}
</style>
