// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

<template>
  <resource-layout>
    <a-spin :spinning="loading" slot="left">
      <a-card :bordered="false">
        <a-input-search
          size="default"
          :placeholder="$t('label.search')"
          v-model="searchQuery"
          @search="onSearch"
        >
          <a-icon slot="prefix" type="search" />
        </a-input-search>
        <a-spin :spinning="loadingSearch">
          <a-tree
            showLine
            v-if="treeViewData.length > 0"
            class="list-tree-view"
            :treeData="treeViewData"
            :loadData="onLoadData"
            :expandAction="false"
            :showIcon="true"
            :defaultSelectedKeys="defaultSelected"
            :checkStrictly="true"
            @select="onSelect"
            @expand="onExpand"
            :defaultExpandedKeys="arrExpand">
            <a-icon slot="parent" type="folder" />
            <a-icon slot="leaf" type="block" />
          </a-tree>
        </a-spin>
      </a-card>
    </a-spin>
    <a-spin :spinning="detailLoading" slot="right">
      <a-card
        class="spin-content"
        :bordered="true"
        style="width:100%">
        <a-tabs
          style="width: 100%"
          :animated="false"
          :defaultActiveKey="tabs[0].name"
          @change="onTabChange" >
          <a-tab-pane
            v-for="tab in tabs"
            :tab="$t('label.' + tab.name)"
            :key="tab.name"
            v-if="checkShowTabDetail(tab)">
            <component
              :is="tab.component"
              :resource="resource"
              :items="items"
              :tab="tabActive"
              :loading="loading"
              :bordered="false" />
          </a-tab-pane>
        </a-tabs>
      </a-card>
    </a-spin>
  </resource-layout>
</template>

<script>
import store from '@/store'
import { api } from '@/api'
import DetailsTab from '@/components/view/DetailsTab'
import ResourceView from '@/components/view/ResourceView'
import ResourceLayout from '@/layouts/ResourceLayout'

export default {
  name: 'TreeView',
  components: {
    ResourceLayout,
    ResourceView
  },
  props: {
    treeData: {
      type: Array,
      required: true
    },
    treeSelected: {
      type: Object,
      required: true
    },
    tabs: {
      type: Array,
      default () {
        return [{
          name: 'details',
          component: DetailsTab
        }]
      }
    },
    loadedKeys: {
      type: Array,
      default () {
        return []
      }
    },
    loading: {
      type: Boolean,
      default: false
    },
    actionData: {
      type: Array,
      default () {
        return []
      }
    }
  },
  data () {
    return {
      detailLoading: false,
      loadingSearch: false,
      tabActive: 'details',
      selectedTreeKey: '',
      resource: {},
      defaultSelected: [],
      treeVerticalData: [],
      treeViewData: [],
      oldTreeViewData: [],
      apiList: '',
      apiChildren: '',
      apiDetail: '',
      metaName: '',
      page: 1,
      pageSize: 20,
      items: [],
      showSetting: false,
      oldSearchQuery: '',
      searchQuery: '',
      arrExpand: [],
      rootKey: ''
    }
  },
  created: function () {
    this.metaName = this.$route.meta.name
    this.apiList = this.$route.meta.permission[0] ? this.$route.meta.permission[0] : ''
    this.apiChildren = this.$route.meta.permission[1] ? this.$route.meta.permission[1] : ''
  },
  watch: {
    loading () {
      this.detailLoading = this.loading
    },
    treeData () {
      if (this.oldTreeViewData.length === 0) {
        this.treeViewData = this.treeData
        this.treeVerticalData = this.treeData
      }

      if (this.treeViewData.length > 0) {
        this.oldTreeViewData = this.treeViewData
        this.rootKey = this.treeViewData[0].key
      }

      if (Object.keys(this.resource).length > 0) {
        const resourceIndex = this.treeVerticalData.findIndex(item => item.id === this.resource.id)
        if (resourceIndex === -1) {
          this.$el.querySelector(`[title=${this.resource.parentdomainname}]`).click()
        }
      }
    },
    treeSelected () {
      if (Object.keys(this.treeSelected).length === 0) {
        return
      }

      if (Object.keys(this.resource).length > 0) {
        this.selectedTreeKey = this.resource.key
        this.$emit('change-resource', this.resource)

        // set default expand
        if (this.defaultSelected.length > 1) {
          const arrSelected = this.defaultSelected
          this.defaultSelected = []
          this.defaultSelected.push(arrSelected[0])
        }

        return
      }

      this.resource = this.treeSelected
      this.resource = this.createResourceData(this.resource)
      this.selectedTreeKey = this.treeSelected.key
      this.defaultSelected.push(this.selectedTreeKey)

      // set default expand
      if (this.defaultSelected.length > 1) {
        const arrSelected = this.defaultSelected
        this.defaultSelected = []
        this.defaultSelected.push(arrSelected[0])
      }
    },
    actionData (newData, oldData) {
      if (!newData || newData.length === 0) {
        return
      }

      this.reloadTreeData(newData)
    }
  },
  methods: {
    onLoadData (treeNode) {
      if (this.searchQuery !== '' && treeNode.eventKey !== this.rootKey) {
        return new Promise(resolve => {
          resolve()
        })
      }

      const params = {
        listAll: true,
        id: treeNode.eventKey
      }

      return new Promise(resolve => {
        api(this.apiChildren, params).then(json => {
          const dataResponse = this.getResponseJsonData(json)
          const dataGenerate = this.generateTreeData(dataResponse)
          treeNode.dataRef.children = dataGenerate

          if (this.treeVerticalData.length === 0) {
            this.treeVerticalData = this.treeViewData
          }

          this.treeViewData = [...this.treeViewData]
          this.oldTreeViewData = this.treeViewData

          for (let i = 0; i < dataGenerate.length; i++) {
            const resource = this.treeVerticalData.filter(item => item.id === dataGenerate[i].id)

            if (!resource || resource.length === 0) {
              this.treeVerticalData.push(dataGenerate[i])
            } else {
              this.treeVerticalData.filter((item, index) => {
                if (item.id === dataGenerate[i].id) {
                  // replace all value of tree data
                  Object.keys(dataGenerate[i]).forEach((value, idx) => {
                    this.$set(this.treeVerticalData[index], value, dataGenerate[i][value])
                  })
                }
              })
            }
          }

          resolve()
        })
      })
    },
    onSelect (selectedKeys, event) {
      if (!event.selected) {
        setTimeout(() => { event.node.$refs.selectHandle.click() })
        return
      }

      // check item tree selected, set selectedTreeKey
      if (selectedKeys && selectedKeys[0]) {
        this.selectedTreeKey = selectedKeys[0]
      }

      this.getDetailResource(this.selectedTreeKey)
    },
    onExpand (treeExpand) {
      this.arrExpand = treeExpand
    },
    onSearch (value) {
      if (this.searchQuery === '' && this.oldSearchQuery === '') {
        return
      }

      this.searchQuery = value
      this.newTreeData = this.treeViewData
      this.treeVerticalData = this.newTreeData

      // set parameter for the request
      const params = {}
      params.listall = true

      // Check the search query to set params and variables using reset data
      if (this.searchQuery !== '') {
        this.oldSearchQuery = this.searchQuery
        params.keyword = this.searchQuery
      } else if (this.metaName === 'domain') {
        this.oldSearchQuery = ''
        params.id = this.$store.getters.userInfo.domainid
      }

      this.arrExpand = []
      this.treeViewData = []
      this.loadingSearch = true

      api(this.apiList, params).then(json => {
        const listDomains = this.getResponseJsonData(json)
        this.treeVerticalData = this.treeVerticalData.concat(listDomains)

        if (!listDomains || listDomains.length === 0) {
          return
        }

        if (listDomains[0].id === this.rootKey) {
          const rootDomain = this.generateTreeData(listDomains)
          this.treeViewData = rootDomain
          this.defaultSelected = []
          this.defaultSelected.push(this.treeViewData[0].key)
          this.resource = this.treeViewData[0]
          this.$emit('change-resource', this.resource)

          return
        }

        this.recursiveTreeData(listDomains)

        if (this.treeViewData && this.treeViewData[0]) {
          this.defaultSelected = []
          this.defaultSelected.push(this.treeViewData[0].key)
          this.resource = this.treeViewData[0]
          this.$emit('change-resource', this.resource)
        }

        // check treeViewData, set to expand first children
        if (this.treeViewData &&
            this.treeViewData[0] &&
            this.treeViewData[0].children &&
            this.treeViewData[0].children.length > 0
        ) {
          this.arrExpand.push(this.treeViewData[0].children[0].key)
        }
      }).finally(() => {
        this.loadingSearch = false
      })
    },
    onTabChange (key) {
      this.tabActive = key
    },
    reloadTreeData (objData) {
      if (objData && objData[0].isDel) {
        this.treeVerticalData = this.treeVerticalData.filter(item => item.id !== objData[0].id)
        this.treeVerticalData = this.treeVerticalData.filter(item => item.parentdomainid !== objData[0].id)
      } else {
        // data response from action
        let jsonResponse = this.getResponseJsonData(objData[0])
        jsonResponse = this.createResourceData(jsonResponse)

        // resource for check create or edit
        const resource = this.treeVerticalData.filter(item => item.id === jsonResponse.id)

        // when edit
        if (resource && resource[0]) {
          this.treeVerticalData.filter((item, index) => {
            if (item.id === jsonResponse.id) {
              // replace all value of tree data
              Object.keys(jsonResponse).forEach((value, idx) => {
                this.$set(this.treeVerticalData[index], value, jsonResponse[value])
              })
            }
          })
        } else {
          // when create
          let resourceExists = true

          // check is searching data
          if (this.searchQuery !== '') {
            resourceExists = jsonResponse.title.indexOf(this.searchQuery) > -1
          }

          // push new resource to tree data
          if (this.resource.haschild && resourceExists) {
            this.treeVerticalData.push(jsonResponse)
          }

          // set resource is currently active as a parent
          this.treeVerticalData.filter((item, index) => {
            if (item.id === this.resource.id) {
              this.$set(this.treeVerticalData[index], 'isLeaf', false)
              this.$set(this.treeVerticalData[index], 'haschild', true)
            }
          })
        }
      }
      this.recursiveTreeData(this.treeVerticalData)
    },
    getDetailResource (selectedKey) {
      // set api name and parameter
      const apiName = this.$route.meta.permission[0]
      const params = {}

      // set id to parameter
      params.id = selectedKey
      params.listAll = true
      params.page = 1
      params.pageSize = 1

      this.detailLoading = true

      api(apiName, params).then(json => {
        const jsonResponse = this.getResponseJsonData(json)

        // check json response is empty
        if (!jsonResponse || jsonResponse.length === 0) {
          this.resource = []
        } else {
          this.resource = jsonResponse[0]
          this.resource = this.createResourceData(this.resource)
          // set all value of resource tree data
          this.treeVerticalData.filter((item, index) => {
            if (item.id === this.resource.id) {
              this.treeVerticalData[index] = this.resource
            }
          })
        }

        // emit change resource to parent
        this.$emit('change-resource', this.resource)
      }).finally(() => {
        this.detailLoading = false
      })
    },
    getResponseJsonData (json) {
      let responseName
      let objectName
      let hasJobId = false
      for (const key in json) {
        if (key.includes('response')) {
          for (const res in json[key]) {
            if (res === 'jobid') {
              hasJobId = true
              break
            }
          }
          responseName = key
          break
        }
      }

      for (const key in json[responseName]) {
        if (key === 'count') {
          continue
        }

        objectName = key
        break
      }
      if (hasJobId) {
        return {}
      }
      return json[responseName][objectName]
    },
    checkShowTabDetail (tab) {
      if ('show' in tab) {
        return tab.show(this.resource, this.$route, store.getters.userInfo)
      }
      // get permission from the route
      const permission = tab.permission ? tab.permission[0] : ''

      // check permission not exists
      if (!permission || permission === '') {
        return true
      }

      // Check the permissions to see the tab for a user
      if (!Object.prototype.hasOwnProperty.call(store.getters.apis, permission)) {
        return false
      }

      return true
    },
    generateTreeData (jsonData) {
      if (!jsonData || jsonData.length === 0) {
        return []
      }

      for (let i = 0; i < jsonData.length; i++) {
        jsonData[i] = this.createResourceData(jsonData[i])
      }

      return jsonData
    },
    createResourceData (resource) {
      if (!resource || Object.keys(resource) === 0) {
        return {}
      }

      Object.keys(resource).forEach((value, idx) => {
        if (resource[value] === 'Unlimited') {
          this.$set(resource, value, '-1')
        }
      })
      this.$set(resource, 'title', resource.name)
      this.$set(resource, 'key', resource.id)
      resource.slots = {
        icon: 'parent'
      }

      if (!resource.haschild) {
        this.$set(resource, 'isLeaf', true)
        resource.slots = {
          icon: 'leaf'
        }
      }

      return resource
    },
    recursiveTreeData (treeData) {
      const maxLevel = Math.max.apply(Math, treeData.map((o) => { return o.level }))
      const items = treeData.filter(item => item.level <= maxLevel)
      this.treeViewData = this.getNestedChildren(items, 0, maxLevel)
      this.oldTreeViewData = this.treeViewData
    },
    getNestedChildren (dataItems, level, maxLevel, id) {
      if (level > maxLevel) {
        return
      }

      let items = []

      if (!id || id === '') {
        items = dataItems.filter(item => item.level === level)
      } else {
        items = dataItems.filter(item => {
          let parentKey = ''
          const arrKeys = Object.keys(item)
          for (let i = 0; i < arrKeys.length; i++) {
            if (arrKeys[i].indexOf('parent') > -1 && arrKeys[i].indexOf('id') > -1) {
              parentKey = arrKeys[i]
              break
            }
          }

          return parentKey ? item[parentKey] === id : item.level === level
        })
      }

      if (items.length === 0) {
        return this.getNestedChildren(dataItems, (level + 1), maxLevel)
      }

      for (let i = 0; i < items.length; i++) {
        items[i] = this.createResourceData(items[i])

        if (items[i].haschild) {
          items[i].children = this.getNestedChildren(dataItems, (level + 1), maxLevel, items[i].key)
        }
      }

      return items
    }
  }
}
</script>

<style lang="less" scoped>
.list-tree-view {
  overflow-y: hidden;
}
/deep/.ant-tree.ant-tree-directory {
  li.ant-tree-treenode-selected {
    span.ant-tree-switcher {
      color: rgba(0, 0, 0, 0.65);
    }
    span.ant-tree-node-content-wrapper.ant-tree-node-selected > span {
      color: rgba(0, 0, 0, 0.65);
      background-color: #bae7ff;
    }
    span.ant-tree-node-content-wrapper::before {
      background: #ffffff;
    }
  }

  .ant-tree-child-tree {
    li.ant-tree-treenode-selected {
      span.ant-tree-switcher {
        color: rgba(0, 0, 0, 0.65);
      }
      span.ant-tree-node-content-wrapper::before {
        background: #ffffff;
      }
    }
  }
}

/deep/.ant-tree li span.ant-tree-switcher.ant-tree-switcher-noop {
  display: none;
}

/deep/.ant-tree-node-content-wrapper-open > span:first-child,
/deep/.ant-tree-node-content-wrapper-close > span:first-child {
  display: none;
}

/deep/.ant-tree-icon__customize {
  color: rgba(0, 0, 0, 0.45);
  background: #fff;
  padding-right: 5px;
}

/deep/.ant-tree li .ant-tree-node-content-wrapper {
  padding-left: 0;
  margin-left: 3px;
}
</style>
