<template>
  <div
    v-loading="loading"
    class="l-flex--col c-tree"
  >
    <el-tabs
      v-if="__STAGING__"
      v-model="active"
      class="c-tabs has-bottom-padding"
    >
      <el-tab-pane
        label="分组"
        name="group"
      />
      <el-tab-pane
        label="分辨率"
        name="ratio"
      />
    </el-tabs>
    <warning
      v-if="error"
      @click="getDevices"
    />
    <template v-else>
      <div
        v-if="isEmpty"
        class="c-tree__empty"
      >
        暂无设备
      </div>
      <template v-else>
        <div class="l-flex__none l-flex--row has-bottom-padding">
          <div class="l-flex__auto" />
          <search-input
            v-model.trim="deviceName"
            class="l-flex__none c-sibling-item"
            placeholder="设备名称"
            @search="onSearch"
          />
          <button
            class="l-flex__none c-sibling-item o-button"
            @click="onSearch"
          >
            搜索
          </button>
        </div>
        <div
          v-if="isEmptySeach"
          class="c-tree__empty"
        >
          暂无设备
        </div>
        <template v-else>
          <div
            class="l-flex__none l-flex--row c-tree__title c-tree__content u-pointer"
            @click="onAllToggle"
          >
            <span class="l-flex__auto">全部设备</span>
            <el-checkbox
              :value="isAll"
              :indeterminate="isIndeterminate"
              class="l-flex__none c-tree__checkbox"
            />
          </div>
          <div class="l-flex__auto l-flex--col u-overflow-y--auto">
            <div
              v-for="group in groups"
              :key="group.id"
              class="l-flex__none"
            >
              <div
                v-if="!onlyOneGroup"
                class="c-tree__content u-pointer"
                @click="onGroupToggle(group)"
              >
                <i
                  class="c-tree__expand el-icon-arrow-right"
                  :class="{ expand: group.expand }"
                />
                <span class="c-tree__label">{{ group.name }}</span>
                <el-checkbox
                  v-model="group.all"
                  class="l-flex__none"
                  :indeterminate="group.indeterminate"
                  :disabled="group.empty"
                  @change="onGroupAllChange(group)"
                  @click.native.stop
                />
              </div>
              <div v-show="onlyOneGroup || group.expand">
                <div
                  v-if="group.empty"
                  class="c-tree__empty--content"
                >
                  暂无设备
                </div>
                <div
                  v-for="device in group.list"
                  :key="device.id"
                  class="c-tree__content u-pointer"
                  :class="{ sub: !onlyOneGroup }"
                  @click="onDeviceToggle(group, device)"
                >
                  <span class="c-tree__label">{{ device.name }} {{ isGroupTab ? device.resolutionRatio : '' }}</span>
                  <el-checkbox
                    :value="device.checked"
                    class="l-flex__none c-tree__checkbox"
                  />
                </div>
              </div>
            </div>
          </div>
        </template>
      </template>
    </template>
  </div>
</template>

<script>
import { getDeviceTree } from '@/api/device'

export default {
  name: 'DeviceGroupTree',
  data () {
    return {
      loading: false,
      error: false,
      active: 'group',
      deviceName: '',
      isEmpty: true,
      isAll: false,
      isIndeterminate: false,
      groups: []
    }
  },
  computed: {
    isGroupTab () {
      return this.active === 'group'
    },
    isEmptySeach () {
      return !this.groups.some(({ empty }) => !empty)
    },
    onlyOneGroup () {
      if (this.isGroupTab) {
        return this.groups.length < 2
      }
      return false
    }
  },
  watch: {
    active: {
      handler () {
        this.getDevices()
      },
      immediate: true
    }
  },
  methods: {
    emitChange () {
      this.$emit(
        'change',
        this.isAll || this.isIndeterminate
          ? [
            ...new Set(
              this.groups.reduce(
                (arr, group) => arr.concat(
                  group.all
                    ? group.list
                    : group.indeterminate
                      ? group.list.filter(device => device.checked)
                      : []
                ),
                []
              )
            )
          ]
          : []
      )
    },
    onAllToggle () {
      this.isAll = !this.isAll
      this.isIndeterminate = false
      const checked = this.isAll
      this.groups.forEach(group => {
        if (!group.empty) {
          group.all = checked
          group.indeterminate = false
          group.list.forEach(device => {
            device.checked = checked
          })
        }
      })
      this.emitChange()
    },
    onGroupToggle (group) {
      group.expand = !group.expand
    },
    onGroupAllChange (group) {
      group.indeterminate = false
      const checked = group.all
      group.list.forEach(device => {
        device.checked = checked
      })
      this.isAll = !this.groups.some(group => !group.empty && !group.all)
      this.isIndeterminate = !this.isAll && (group.all || group.indeterminate || this.groups.some(group => group.all || group.indeterminate))
      this.emitChange()
    },
    onDeviceChange (group, { checked }) {
      group.all = !group.list.some(device => !device.checked)
      if (group.all) {
        group.indeterminate = false
        this.isAll = !this.groups.some(group => !group.empty && !group.all)
        this.isIndeterminate = !this.isAll && this.groups.some(group => group.all || group.indeterminate)
      } else {
        group.indeterminate = checked || group.list.some(device => device.checked)
        this.isAll = false
        this.isIndeterminate = checked || group.indeterminate || this.groups.some(group => group.all || group.indeterminate)
      }
      this.emitChange()
    },
    onDeviceToggle (group, device) {
      device.checked = !device.checked
      this.onDeviceChange(group, device)
    },
    getDevices () {
      this.loading = true
      this.error = false
      this.getDevicesByActive().then(
        data => {
          this.$groups = data
          const { length } = data
          if (length === 0 || !data.some(({ list }) => list.length)) {
            this.isEmpty = true
          } else {
            this.isEmpty = false
            this.onSearch()
          }
        },
        () => {
          this.error = true
        }
      ).finally(() => {
        this.loading = false
      })
    },
    getDevicesByActive () {
      const key = `$${this.active}Cache`
      if (this[key]) {
        return Promise.resolve(this[key])
      }
      return getDeviceTree().then(({ data }) => {
        this.$groupCache = data
        if (__STAGING__) {
          const map = {}
          const cache = []
          const ids = {}
          data.forEach(({ list }) => {
            list.forEach(device => {
              const resolutionRatio = device.resolutionRatio
              if (!ids[device.id]) {
                if (!map[resolutionRatio]) {
                  map[resolutionRatio] = []
                  cache.push({
                    name: resolutionRatio,
                    list: map[resolutionRatio]
                  })
                }
                ids[device.id] = 1
                map[resolutionRatio].push(device)
              }
            })
          })
          this.$ratioCache = cache
        }
        return this[key]
      })
    },
    onSearch () {
      this.isAll = false
      this.isIndeterminate = false
      const regx = this.deviceName ? new RegExp(this.deviceName) : null
      this.groups = this.$groups.map(({ name, list }) => {
        if (regx) {
          list = list.filter(({ name }) => regx.test(name))
        }
        return {
          name,
          expand: false,
          empty: list.length === 0,
          all: false,
          indeterminate: false,
          list: list.map(({ id, name, resolutionRatio }) => {
            return {
              id, name, resolutionRatio,
              checked: false
            }
          })
        }
      })
      this.emitChange()
    },
    reset () {
      this.deviceName = ''
      this.onSearch()
    }
  }
}
</script>
