<template>
  <div class="l-flex__fill l-flex">
    <div class="l-flex__none c-takeover-debug u-overflow-y--auto">
      <div
        v-for="message in messages"
        :key="message.id"
      >
        {{ message.info }}
      </div>
    </div>
    <div
      v-loading="loading"
      class="l-flex__fill l-flex--col"
    >
      <div
        v-if="!loading && !valid"
        class="l-flex--col center"
      >
        <button
          v-if="online"
          class="o-button"
          @click="createClient"
        >
          连接设备
        </button>
        <div
          v-else
          class="u-color--info"
        >
          设备未上线
        </div>
      </div>
      <template v-if="valid">
        <div class="l-flex--row c-sibling-item--v">
          <button
            class="c-sibling-item o-button"
            @click="onAddAsset"
          >
            <i class="o-button__icon el-icon-circle-plus-outline" />
            缓存资源
          </button>
          <button
            class="c-sibling-item o-button"
            @click="onAddWeb"
          >
            <i class="o-button__icon el-icon-circle-plus-outline" />
            缓存网页
          </button>
        </div>
        <el-tabs
          v-model="active"
          class="c-sibling-item--v c-tabs has-bottom-padding"
        >
          <el-tab-pane
            name="loaded"
            label="已下载"
          />
          <el-tab-pane
            label="下载中"
            name="loading"
          />
          <el-tab-pane
            label="异常"
            name="error"
          />
        </el-tabs>
        <div class="l-flex__fill l-grid--info mini u-overflow-y--auto">
          <asset-card
            v-for="asset in list"
            :key="asset.keyName"
            :asset="asset"
            @play="onPlay"
            @reload="onReload"
            @del="onDel"
          />
        </div>
        <confirm-dialog
          ref="assetsDialog"
          title="资源列表"
          size="lg fixed"
          append-to-body
          @confirm="onSaveAssets"
        >
          <div class="l-flex__fill l-flex">
            <directory-tree
              class="c-sibling-item c-sidebar u-width--md"
              @change="onAssetDirectoryChanged"
            />
            <grid-table
              ref="gridTable"
              :schema="assetSchema"
            >
              <grid-table-item v-slot="item">
                <media-card
                  class="o-card"
                  :asset="item"
                  @click="onToggleGrid"
                >
                  <el-checkbox
                    v-model="item.selected"
                    class="o-card__checkbox"
                  />
                  <i
                    class="o-card__icon el-icon-video-play has-active"
                    @click.stop="onView(item)"
                  />
                </media-card>
              </grid-table-item>
            </grid-table>
          </div>
        </confirm-dialog>
        <confirm-dialog
          ref="webDialog"
          title="网页配置"
          @confirm="onSaveWeb"
        >
          <div class="c-grid-form sm u-align-self--center">
            <span class="c-grid-form__label u-required">名称：</span>
            <el-input
              v-model.trim="web.name"
              clearable
            />
            <span class="c-grid-form__label u-required">网址：</span>
            <el-input
              v-model.trim="web.keyName"
              clearable
            />
          </div>
        </confirm-dialog>
        <preview-dialog ref="previewDialog" />
      </template>
    </div>
  </div>
</template>

<script>
import {
  State,
  AssetType,
  AssetTypeInfo,
  AssetTag,
  AssetTagInfo
} from '@/constant'
import { getAssetsByQuery } from '@/api/asset'
import {
  Topic,
  MediaType,
  MediaStatus,
  takeOver
} from './takeover'
import AssetCard from './components/AssetCard'

export default {
  name: 'DeviceTakeOver',
  components: {
    AssetCard
  },
  props: {
    device: {
      type: Object,
      required: true
    },
    online: {
      type: [Boolean, String],
      default: false
    }
  },
  data () {
    return {
      loading: true,
      valid: false,
      messages: [],
      active: 'loaded',
      assets: [],
      sources: [],
      assetSchema: {
        list: this.getAssetsByQuery,
        transform: this.transformAsset,
        condition: { pageSize: 16, status: State.AVAILABLE, tag: AssetTag.AD, type: AssetType.IMAGE },
        filters: [
          { key: 'tag', type: 'select', options: [
            { value: AssetTag.AD, label: AssetTagInfo[AssetTag.AD] },
            { value: AssetTag.PUBLICITY, label: AssetTagInfo[AssetTag.PUBLICITY] },
            { value: AssetTag.LOCAL_PUBLICITY, label: AssetTagInfo[AssetTag.LOCAL_PUBLICITY] },
            { value: AssetTag.SHIM, label: AssetTagInfo[AssetTag.SHIM] }
          ] },
          { key: 'type', type: 'select', options: [
            { value: AssetType.IMAGE, label: AssetTypeInfo[AssetType.IMAGE] },
            { value: AssetType.VIDEO, label: AssetTypeInfo[AssetType.VIDEO] }
          ] },
          { key: 'originalName', type: 'search', placeholder: '资源名称' }
        ]
      },
      web: {}
    }
  },
  computed: {
    list () {
      switch (this.active) {
        case 'loaded':
          return this.assets.filter(({ status }) => status === MediaStatus.LOADED)
        case 'loading':
          return this.assets.filter(({ status }) => status === MediaStatus.WAITING || status === MediaStatus.LOADING)
        case 'error':
          return this.assets.filter(({ status }) => status === MediaStatus.ERROR)
        default:
          return this.assets
      }
    }
  },
  watch: {
    online: {
      handler (val) {
        if (val) {
          this.createClient()
        } else {
          this.destroyClient()
        }
      },
      immediate: true
    }
  },
  beforeDestroy () {
    this.destroyClient()
  },
  methods: {
    onAssetDirectoryChanged (directory) {
      this.$directoryOption = directory
      this.$refs.table?.getTable.pageTo(1)
    },
    getAssetsByQuery (params) {
      if (!this.$directoryOption) {
        return Promise.resolve({ data: [] })
      }
      const { root, id, group: { path } } = this.$directoryOption
      return getAssetsByQuery({
        ...params,
        ...(root
          ? { org: path }
          : { treeId: id, queryRelation: '1' })
      })
    },
    destroyClient () {
      this.loading = false
      if (this.valid) {
        this.$clientProxy.close()
      } else {
        this.$client?.end(true)
      }
    },
    onMessage (topic, payload, requestPayload) {
      switch (topic) {
        case Topic.PRELOAD:
          this.onReloadReply(requestPayload.assets)
          break
        case Topic.DEL:
          this.onDelReply(requestPayload.assets)
          break
        case Topic.PULL:
          this.onRefresh(payload.assets)
          break
        case Topic.DOWNLOAD:
          this.onDownload(payload)
          break
        default:
          break
      }
    },
    onCreated (proxy) {
      this.valid = true
      this.$client = null
      this.$clientProxy = proxy
      this.$clientProxy.pull()
    },
    onClose () {
      this.valid = false
      this.loading = false
      this.$client = null
      this.$clientProxy = null
    },
    onDebug (message) {
      this.messages.unshift({
        id: `${Date.now()}_${Math.random().toString().slice(2)}`,
        info: message
      })
    },
    createClient () {
      this.loading = true
      this.$client = takeOver(this.device, {
        onMessage: this.onMessage,
        onCreated: this.onCreated,
        onClose: this.onClose,
        debug: this.onDebug
      })
    },
    onRefresh (assets) {
      this.loading = false
      this.assets = assets
    },
    onPlay ({ type, name, keyName }) {
      this.$clientProxy.play({ type, name, keyName })
    },
    transformAsset ({ type, originalName, keyName, file, size, md5 }) {
      return {
        selected: false,
        type,
        name: originalName,
        keyName,
        size,
        md5,
        file
      }
    },
    onAddAsset () {
      this.$refs.assetsDialog.show()
    },
    onToggleGrid (asset) {
      asset.selected = !asset.selected
    },
    onSaveAssets (done) {
      const assets = this.$refs.gridTable.getData().filter(({ selected }) => selected).map(({ type, name, keyName, size, md5, file }) => {
        return {
          type, name, keyName, size, md5,
          thumb: file.thumb
        }
      })
      if (assets.length) {
        this.sources = this.sources.concat(assets)
        this.$clientProxy.preload(assets)
      }
      done()
    },
    onView ({ type, keyName }) {
      this.$refs.previewDialog.show({ type, url: keyName })
    },
    onAddWeb () {
      this.web = {
        name: '',
        keyName: ''
      }
      this.$refs.webDialog.show()
    },
    onSaveWeb (done) {
      const { name, keyName } = this.web
      if (!name) {
        this.$message({
          type: 'warning',
          message: '名称不能为空'
        })
        return
      }
      if (!keyName) {
        this.$message({
          type: 'warning',
          message: '网址不能为空'
        })
        return
      }
      this.$clientProxy.preload([{ type: MediaType.WEB, name, keyName }])
      done()
    },
    onReload (asset) {
      const { status, ...data } = asset
      this.$clientProxy.preload([data])
    },
    onReloadReply (assets) {
      assets.forEach(asset => {
        const targetKeyName = asset.keyName
        const index = this.assets.findIndex(({ keyName }) => targetKeyName === keyName)
        if (~index) {
          this.assets[index].status = MediaStatus.WAITING
        } else {
          this.assets.push({
            status: asset.type === MediaType.WEB ? MediaStatus.LOADED : MediaStatus.WAITING,
            ...asset
          })
        }
      })
    },
    onDel ({ name, keyName }) {
      this.onDebug(`删除${name}`)
      this.$clientProxy.del([keyName])
    },
    onDelReply (assets) {
      assets.forEach(keyName => {
        const index = this.assets.findIndex(asset => asset.keyName === keyName)
        if (~index) {
          this.assets.splice(index, 1)
        }
      })
    },
    onDownload ({ success, asset: { keyName } }) {
      const index = this.assets.findIndex(asset => asset.keyName === keyName)
      if (~index) {
        this.assets[index].status = success ? MediaStatus.LOADED : MediaStatus.ERROR
      } else if (!this.loading) {
        this.loading = true
        this.$clientProxy.pull()
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.c-takeover-debug {
  width: 200px;
  padding-right: $spacing;
  margin-right: $spacing;
  color: $black;
  font-size: 14px;
  line-height: 24px;
  word-break: break-word;
  border-right: 1px solid $border;
}

.o-card {
  &__checkbox {
    position: absolute;
    top: 10px;
    left: 10px;
    pointer-events: none;
    z-index: 9;
  }

  &__icon {
    position: absolute;
    top: 50%;
    left: 50%;
    padding: 2px;
    font-size: 24px;
    border-radius: 50%;
    background-color: rgba(#000, 0.4);
    transform: translate(-50%, -50%);
  }
}
</style>
