<template>
  <wrapper
    class="c-step"
    fill
    margin
    padding
    background
  >
    <div class="l-flex__none l-flex--row c-step__header">
      <button
        class="l-flex__none c-sibling-item o-button"
        :class="{ hidden: active === 0 }"
        @click="onPresent"
      >
        上一步
      </button>
      <el-steps
        :active="active"
        class="l-flex__fill"
        finish-status="success"
        align-center
      >
        <el-step title="选择设备" />
        <el-step title="选择内容" />
      </el-steps>
      <button
        class="l-flex__none c-sibling-item o-button"
        :class="{ hidden: hideNext }"
        @click="onNext"
      >
        {{ btnMsg }}
      </button>
    </div>
    <div class="l-flex__fill l-flex">
      <device-tree
        v-show="active === 0"
        ref="tree"
        class="l-flex__fill"
        exact
        checkbox
        check-on-click-node
        @change="onChange"
      />
      <template v-if="active > 0">
        <div class="l-flex--col c-sibling-item far c-step__column">
          <div class="l-flex__none c-sibling-item--v u-font-size--sm u-bold">设备</div>
          <div class="l-flex__fill c-sibling-item--v near u-overflow-y--auto">
            <div
              v-for="device in selectedDevices"
              :key="device.id"
              class="c-sibling-item--v u-font-size--sm"
            >
              {{ device.name }}
            </div>
          </div>
        </div>
        <div
          v-if="isCalendar"
          class="l-flex__fill l-flex--col c-step__column"
        >
          <div class="c-sibling-item--v has-bottom-padding--sm has-bottom-border">
            <div class="c-sibling-item--v u-font-size--sm u-bold">上播类型</div>
            <div class="l-flex--row c-sibling-item--v near">
              <el-select
                v-model="eventOptions.type"
                class="c-sibling-item"
                @change="onChangeType"
              >
                <el-option
                  v-for="option in typeOptions"
                  :key="option.value"
                  :label="option.label"
                  :value="option.value"
                />
              </el-select>
              <div
                class="l-flex--row c-sibling-item far has-active u-ellipsis"
                @click="onView"
              >
                {{ currentTarget }}
              </div>
            </div>
          </div>
          <schema-table
            class="c-sibling-item--v"
            :schema="schema"
            row-key="id"
            :current-row-key="selectedId"
            highlight-current-row
            @row-click="onClickRow"
          />
        </div>
        <div class="l-flex__none l-flex--col c-step__column large">
          <div class="c-sibling-item--v u-font-size--sm u-bold">上播配置</div>
          <div class="c-sibling-item--v u-font-size--sm">上播类型</div>
          <el-select
            v-model="eventOptions.type"
            class="c-sibling-item--v near u-width--sm"
            @change="onChangeType"
          >
            <el-option
              v-for="option in typeOptions"
              :key="option.value"
              :label="option.label"
              :value="option.value"
            />
          </el-select>
          <template v-if="!isDefaultPlayback">
            <div class="c-sibling-item--v u-font-size--sm">优先级</div>
            <el-select
              v-model="priority"
              class="c-sibling-item--v near u-width--sm"
            >
              <el-option
                v-for="option in priorityOptions"
                :key="option.value"
                :label="option.label"
                :value="option.value"
              />
            </el-select>
          </template>
          <div class="c-sibling-item--v">
            <div
              class="l-flex--row inline u-font-size--sm has-active"
              @click="onAddEvent"
            >
              <span class="c-sibling-item">播放时段</span>
              <i class="c-sibling-item near el-icon-circle-plus-outline" />
            </div>
          </div>
          <schema-table
            ref="timeTable"
            class="c-sibling-item--v near"
            :schema="timeSchema"
          />
        </div>
        <event-target-picker
          ref="eventTargetPicker"
          class="l-flex__fill c-step__column"
          :event-target="eventTarget"
          :ratio="ratio"
        />
      </template>
    </div>
    <event-frequency-config-dialog
      ref="eventFrequencyConfigDialog"
      @confirm="onConfirmEventFrequency"
    />
    <confirm-dialog
      ref="conflictDialog"
      title="冲突提醒"
      cancel-text="重新编辑"
      confirm-text="覆盖"
      append-to-body
      @confirm="onCover"
    >
      <div
        v-for="conflict in conflicts"
        :key="conflict.key"
      >
        {{ conflict.info }}
      </div>
    </confirm-dialog>
    <material-dialog ref="materialDialog" />
  </wrapper>
</template>

<script>
import {
  State,
  ScheduleType,
  EventTarget,
  EventTargetInfo,
  PublishType,
  PublishTargetType,
  EventPriority,
  EventPriorityInfo,
  EventFrequency
} from '@/constant'
import {
  toDateStr,
  getConflict,
  getEventDescription
} from '@/utils/event'
import { getSchedules } from '@/api/calendar'
import { publish } from '@/api/platform'
import EventFrequencyConfigDialog from '../components/EventFrequencyConfigDialog.vue'

const DEFAULT_PLAYBACK = 'DEFAULT_PLAYBACK'

export default {
  name: 'DeployDevice',
  components: {
    EventFrequencyConfigDialog
  },
  data () {
    return {
      active: 0,
      ratio: '',
      selectedDevices: [],
      priority: EventPriority.INSERTED,
      priorityOptions: [
        { value: EventPriority.SCHEDULING, label: EventPriorityInfo[EventPriority.SCHEDULING] },
        { value: EventPriority.INSERTED, label: EventPriorityInfo[EventPriority.INSERTED] },
        { value: EventPriority.EMBEDDED, label: EventPriorityInfo[EventPriority.EMBEDDED] },
        { value: EventPriority.EMERGENT, label: EventPriorityInfo[EventPriority.EMERGENT] }
      ],
      eventOptions: null,
      typeOptions: [
        { value: PublishTargetType.EVENT, label: '事件' },
        // { value: PublishTargetType.CALENDAR, label: '排期' },
        { value: DEFAULT_PLAYBACK, label: '默认播放' }
      ],
      schema: {
        list: getSchedules,
        condition: { type: ScheduleType.COMPLEX, status: State.AVAILABLE },
        filters: [
          { key: 'name', type: 'search', placeholder: '名称' }
        ],
        cols: [
          { render: ({ id }, h) => h(
            'span',
            { staticClass: `el-radio__input ${id === this.selectedId ? 'is-checked' : ''}` },
            [h('span', { staticClass: 'el-radio__inner' })]
          ), width: 60, align: 'center' },
          { prop: 'name', label: '名称' },
          { prop: 'resolutionRatio', label: '分辨率' },
          { type: 'invoke', render: [
            { label: '查看', on: this.onView }
          ] }
        ]
      },
      timeSchema: {
        nonPagination: true,
        props: {
          size: 'small'
        },
        list: this.getEvents,
        cols: [
          { prop: 'time', label: '生效时间', 'show-overflow-tooltip': false },
          { type: 'invoke', render: [
            { label: '移除', on: this.removeEventProxy }
          ], width: 60 }
        ]
      },
      events: [],
      eventTarget: this.createEventTarget(),
      conflicts: []
    }
  },
  computed: {
    hideNext () {
      switch (this.active) {
        case 0:
          return this.selectedDevices.length === 0
        case 1:
          return this.isCalendar ? !this.selectedId : false
        default:
          return false
      }
    },
    isCalendar () {
      return this.eventOptions?.type === PublishTargetType.CALENDAR
    },
    isEvent () {
      return this.eventOptions?.type === PublishTargetType.EVENT
    },
    isDefaultPlayback () {
      return this.eventOptions?.type === DEFAULT_PLAYBACK
    },
    btnMsg () {
      return this.active < 1 ? '下一步' : '发布'
    },
    selectedId () {
      return this.eventOptions?.target?.id
    },
    currentTarget () {
      return this.eventOptions?.target?.name
    }
  },
  methods: {
    onPresent () {
      if (this.active > 0) {
        this.active = 0
      }
    },
    onNext () {
      switch (this.active) {
        case 0:
          if (this.checkDevices()) {
            this.active += 1
          }
          break
        case 1:
        case 2:
          this.publish().then(() => {
            this.active = 0
            this.$refs.tree.reset()
            this.eventOptions = null
            this.priority = EventPriority.INSERTED
            this.events = []
            this.eventTarget = this.createEventTarget()
          })
          break
        default:
          break
      }
    },
    onChange (devices) {
      this.selectedDevices = devices
    },
    createEventOptions (type) {
      return {
        type,
        target: null
      }
    },
    checkDevices () {
      const devices = this.selectedDevices
      const length = devices.length
      if (!length) {
        this.$message({
          type: 'warning',
          message: '请选择目标设备'
        })
        return false
      }
      const ratio = devices[0].resolutionRatio
      if (devices.some(device => device.resolutionRatio !== ratio)) {
        this.ratio = ''
        // this.$confirm(
        //   '上播内容可能无法完全适配，继续下一步？',
        //   '选择的设备分辨率不一致',
        //   { type: 'warning' }
        // ).then(() => {
        //   this.eventOptions = this.createEventOptions(PublishTargetType.EVENT)
        //   this.active += 1
        // })
        // return false
      } else {
        this.ratio = ratio
      }
      this.eventOptions = this.createEventOptions(PublishTargetType.EVENT)
      return true
    },
    onChangeType (type) {
      this.eventOptions = this.createEventOptions(type)
    },
    onClickRow (row) {
      this.eventOptions.target = row
    },
    onView ({ id }) {
      this.$refs.materialDialog.showSchedule(id)
    },
    createEventTarget () {
      return { type: EventTarget.ASSETS }
    },
    getEvents () {
      return Promise.resolve(({ data: this.events }))
    },
    onAddEvent () {
      this.$refs.eventFrequencyConfigDialog.show()
    },
    onConfirmEventFrequency ({ value, done }) {
      const conflicts = new Map()
      if (this.events.length) {
        this.events.forEach(eventProxy => {
          value.forEach(event => {
            const date = getConflict(event, eventProxy.origin)
            if (date) {
              conflicts.set(eventProxy.key, {
                key: eventProxy.key,
                info: `与 ${eventProxy.time} 有冲突`
              })
            }
          })
        })
      }
      if (conflicts.size) {
        this.conflicts = [...conflicts.values()]
        this.$conflictOptions = { value, done }
        this.$refs.conflictDialog.show()
        return
      }
      this.onAdded(value, done)
    },
    onCover (closeCb) {
      this.conflicts.forEach(this.removeEventProxy)
      const { value, done } = this.$conflictOptions
      this.$conflictOptions = null
      closeCb()
      this.onAdded(value, done)
    },
    onAdded (value, done) {
      this.events = [
        ...value.map(event => {
          return {
            key: `${Date.now()}_${Math.random().toString(16).slice(2)}`,
            origin: event,
            time: getEventDescription(event)
          }
        }),
        ...this.events
      ]
      this.$refs.timeTable?.pageTo(1)
      done()
    },
    removeEventProxy (eventProxy) {
      if (eventProxy) {
        const { key } = eventProxy
        const index = this.events.findIndex(event => event.key === key)
        if (~index) {
          this.events.splice(index, 1)
          return index
        }
      }
      return -1
    },
    getPublishTarget () {
      if (!this.events.length) {
        this.$message({
          type: 'warning',
          message: '请添加上播时段'
        })
        return Promise.reject('invalid event, no time')
      }
      if (this.isCalendar) {
        const { id, name, resolutionRatio } = this.eventOptions.target
        return Promise.resolve({
          publishType: PublishType.PROGRAM_TO_DEVICE,
          targetList: [{
            type: PublishTargetType.CALENDAR,
            detail: id
          }],
          name,
          resolutionRatio
        })
      }
      const eventTarget = this.$refs.eventTargetPicker.getValue()
      if (!eventTarget) {
        return Promise.reject('invalid event, no target')
      }
      const { detail } = this.$refs.eventTargetPicker.getSnapshot()
      const type = PublishTargetType.EVENT
      const priority = this.isDefaultPlayback ? EventPriority.SHIM : this.priority
      return Promise.resolve({
        publishType: eventTarget.type === EventTarget.ASSETS
          ? PublishType.ASSET_TO_DEVICE
          : PublishType.PROGRAM_TO_DEVICE,
        targetList: this.isDefaultPlayback
          ? [{
            type,
            detail: {
              priority,
              freq: EventFrequency.ONCE,
              start: `${toDateStr(new Date())} 00:00:00`,
              target: eventTarget
            }
          }]
          : this.events.map(({ origin }) => {
            return {
              type,
              detail: {
                priority,
                ...origin,
                target: eventTarget
              }
            }
          }),
        name: detail?.name || EventTargetInfo[eventTarget.type],
        resolutionRatio: detail?.resolutionRatio
      })
    },
    publish () {
      return this.getPublishTarget().then(
        ({ publishType, targetList, name, resolutionRatio }) => this.$prompt(
          `<p>发布后需审核生效，操作完成后请通知相关人员进行审核</p>${resolutionRatio && (!this.ratio || resolutionRatio !== this.ratio) ? '<p class="u-color--error">上播内容与设备分辨率不一致，可能无法完全适配</p>' : ''}<br/><p class="u-color--black u-font-size--sm u-bold">编单名称</p>`,
          '操作确认',
          {
            dangerouslyUseHTMLString: true,
            closeOnClickModal: false,
            inputPlaceholder: '发布内容的简单描述',
            inputValue: name,
            inputPattern: /^.{1,30}$/,
            inputErrorMessage: '请用1~30个字符进行描述',
            confirmButtonText: '发布',
            cancelButtonText: '取消'
          }
        ).then(
          ({ value }) => publish(
            publishType,
            this.selectedDevices.map(device => device.id),
            targetList,
            {
              programCalendarName: value,
              resolutionRatio: resolutionRatio || '自适应',
              remark: EventPriorityInfo[this.priority]
            }
          )
        )
      )
    }
  }
}
</script>

<style lang="scss" scoped>
.o-schedule-button {
  position: relative;
  width: 217px;
  height: 40px;
  color: $blue;
  font-size: 14px;
  line-height: 1;
  border-radius: $radius--sm;
  border: 1px solid #dcdfe6;

  &:hover {
    border-color: #c0c4cc;
  }

  &__label {
    display: inline-flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    width: 100%;
    height: 100%;
  }
}
</style>
