<template>
  <wrapper
    fill
    margin
  >
    <div class="l-flex__none l-flex--row c-sibling-item--v c-count">
      <div
        class="l-flex__none c-count__title u-color--black u-bold has-active u-ellipsis"
        @click="onChooseDepartment"
      >
        <i
          v-if="loading"
          class="el-icon-loading"
        />
        {{ group.name }}
      </div>
      <div class="l-flex__none c-count__item u-color--black u-bold u-text--center">
        <div>总数</div>
        <i
          v-if="monitor.loading"
          class="el-icon-loading"
        />
        <div v-else>{{ monitor.total }}</div>
      </div>
      <div class="l-flex__none c-count__item u-color--success dark u-bold u-text--center">
        <div>● 在线</div>
        <i
          v-if="monitor.loading"
          class="el-icon-loading"
        />
        <div v-else>{{ monitor.online }}</div>
      </div>
      <div class="l-flex__none c-count__item u-color--error dark u-bold u-text--center">
        <div>● 离线</div>
        <i
          v-if="monitor.loading"
          class="el-icon-loading"
        />
        <div v-else>{{ monitor.offline }}</div>
      </div>
      <div class="l-flex__none c-count__item u-color--info u-bold u-text--center">
        <div>● 未启用</div>
        <i
          v-if="monitor.loading"
          class="el-icon-loading"
        />
        <div v-else>{{ monitor.inactive }}</div>
      </div>
      <i
        class="el-icon-refresh o-icon md u-color--blue has-active"
        @click="onRefresh"
      />
    </div>
    <div
      v-if="__PLACEHOLDER__"
      class="l-flex__none c-sibling-item--v far c-cards"
    >
      <card
        class="c-cards__item"
        type="info"
        title="总次数"
        tip="100"
      />
      <card
        class="c-cards__item"
        type="safety"
        title="安全异常"
        desc="累计异常数：30"
      />
      <card
        class="c-cards__item"
        type="performance"
        title="性能异常"
        desc="累计异常数：30"
        count="3"
      />
      <card
        class="c-cards__item"
        type="log"
        title="日志异常"
        desc="累计异常数：30"
        count="10"
      />
      <card
        class="c-cards__item"
        type="date"
        title="即将空闲排期"
        count="100"
      />
    </div>
    <div
      ref="deviceContainer"
      class="l-flex__auto l-grid--info c-sibling-item--v far u-overflow-y--auto"
    >
      <device
        v-for="item in deviceOptions.list"
        :key="item.id"
        :device="item"
        :observer="observerDom"
        :flag="item.flag"
      />
    </div>
    <div
      v-if="!deviceOptions.loaded"
      class="c-sibling-item--v far u-text--center"
    >
      <i class="el-icon-loading" />
    </div>
    <department-drawer
      ref="departmentDrawer"
      @change="onGroupChanged"
      @loaded="onGroupLoaded"
    />
  </wrapper>
</template>

<script>
import {
  subscribe,
  unsubscribe
} from '@/utils/mqtt'
import { ScreenshotCache } from '@/utils/cache'
import {
  getDevicesByQuery,
  getDeviceStatisticsByPath
} from '@/api/device'
import Card from './components/Card'
import Device from './components/Device'

export default {
  name: 'Dashboard',
  components: {
    Card,
    Device
  },
  data () {
    return {
      monitor: { loading: true },
      deviceOptions: {
        list: [],
        loaded: false
      },
      loading: true,
      group: {}
    }
  },
  created () {
    this.$timer = -1
    subscribe([
      '+/+/online',
      '+/+/offline',
      '+/+/calendar/update'
    ], this.onMessage)
  },
  beforeDestroy () {
    ScreenshotCache.clear()
    clearTimeout(this.$timer)
    this.monitor = { loading: true }
    unsubscribe([
      '+/+/online',
      '+/+/offline',
      '+/+/calendar/update'
    ], this.onMessage)
    if (this.$observer) {
      this.$observer.disconnect()
      this.$observer = null
    }
  },
  methods: {
    observerDom (el) {
      if (!this.$observer) {
        this.$observer = new IntersectionObserver(entries => {
          console.log('observer')
          entries.forEach(entry => {
            const inst = entry.target.__vue__
            if (inst && inst.intoView && inst.outView) {
              if (entry.isIntersecting) {
                inst.intoView()
              } else {
                inst.outView()
              }
            } else {
              const device = this.deviceOptions.map?.[entry.target.dataset.id]
              if (device) {
                if (entry.isIntersecting) {
                  !device.flag && (device.flag = Date.now())
                } else {
                  device.flag && (device.flag = 0)
                }
              }
            }
          })
        }, {
          root: this.$refs.deviceContainer,
          threshold: [0.25]
        })
      }
      this.$observer.observe(el)
    },
    onMessage (topic) {
      if (!this.deviceOptions.loaded) {
        return
      }
      const result = /^\d+\/(\d+)\/(online|offline|calendar\/update)$/.exec(topic)
      if (!result) {
        return
      }
      const deviceId = result[1]
      const status = result[2]
      const device = this.deviceOptions.map?.[deviceId]
      if (device) {
        if (status === 'calendar/update') {
          device.flag = -Date.now()
          return
        }
        const onlineStatus = device.onlineStatus === 1 ? 'online' : 'offline'
        if (status === onlineStatus) {
          return
        }
        this.refreshDevices()
      }
    },
    onGroupLoaded () {
      this.loading = false
    },
    onGroupChanged ({ path, name }) {
      if (!this.group || this.group.path !== path) {
        this.group = { path, name }
        this.refreshDevices(true)
      }
    },
    onChooseDepartment () {
      this.$refs.departmentDrawer.show().then(visible => {
        this.loading = !visible
      })
    },
    onRefresh () {
      this.refreshDevices()
    },
    refreshDevices (force) {
      if (!force && this.monitor.loading) {
        return
      }
      const monitor = {
        loading: true,
        total: '-',
        online: '-',
        offline: '-',
        inactive: '-'
      }
      this.monitor = monitor
      clearTimeout(this.$timer)
      this.deviceOptions = { loaded: false }
      this.$observer?.disconnect()
      getDeviceStatisticsByPath(this.group.path).then(({ data }) => {
        const { deactivatedTotal, notConnectedTotal, offLineTotal, onLineTotal, total } = data
        monitor.total = total
        monitor.online = onLineTotal
        monitor.offline = offLineTotal + notConnectedTotal
        monitor.inactive = deactivatedTotal
      }).finally(() => {
        monitor.loading = false
        if (!this.monitor.loading) {
          this.getDevices(this.monitor.total - this.monitor.inactive)
        }
      })
    },
    sort (a, b) {
      if (a.onlineStatus === b.onlineStatus) {
        return a.createTime <= b.createTime ? 1 : -1
      }
      return a.onlineStatus === 1 ? -1 : 1
    },
    getDevices (total) {
      if (!total || total === '-') {
        this.deviceOptions = { list: [], loaded: true }
        return
      }
      const options = { list: [], loaded: false }
      this.deviceOptions = options
      getDevicesByQuery({
        pageNum: 1,
        pageSize: total,
        activate: 1,
        org: this.group.path
      }, { custom: true }).then(
        ({ data }) => {
          const map = {}
          options.list = data.sort(this.sort).map(device => {
            map[device.id] = device
            device.flag = 0
            return device
          })
          options.loaded = true
          options.map = map
        },
        ({ isCancel }) => {
          if (!isCancel && !this.monitor.loading) {
            this.$timer = setTimeout(total => {
              this.getDevices(total)
            }, 2000, total)
          }
        }
      )
    }
  }
}
</script>

<style lang="scss" scoped>
.c-count {
  justify-content: space-between;
  padding: $spacing--xs $spacing;
  border-radius: $radius;
  background-color: #fff;

  &__title {
    width: 200px;
  }

  &__item > div:first-child {
    margin-bottom: 10px;
  }
}

.c-cards {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-column-gap: $spacing;

  &__item {
    min-width: 0;
  }
}
</style>
