<template>
  <div
    class="c-grid-form medium c-event"
    :class="{ row: !vertical, col: vertical }"
  >
    <div class="c-grid-form__label required">播放内容</div>
    <div class="c-event__option c-event__program u-pointer">
      <div
        class="c-event__name has-padding--h"
        @click="onChoose"
      >
        <div class="u-ellipsis">{{ msg }}</div>
      </div>
    </div>
    <div class="c-grid-form__label">播放方式</div>
    <div>
      <el-select
        v-model="eventOptions.freq"
        class="c-event__option"
        @change="onEventTypeChanged"
      >
        <el-option
          v-for="option in freqOptions"
          :key="option.value"
          :label="option.label"
          :value="option.value"
        />
      </el-select>
    </div>
    <template v-if="isOnce">
      <div class="c-grid-form__label required">生效时间</div>
      <el-date-picker
        v-model="eventOptions.start"
        class="c-event__option"
        type="datetime"
        placeholder="请选择生效时间"
        value-format="yyyy-MM-dd HH:mm:ss"
        :picker-options="pickerOptions"
        @change="onDateTimeChange('start')"
      />
      <div class="c-grid-form__label">失效时间</div>
      <el-date-picker
        v-model="eventOptions.until"
        class="c-event__option"
        type="datetime"
        :disabled="!eventOptions.start"
        placeholder="请选择失效时间"
        value-format="yyyy-MM-dd HH:mm:ss"
        :picker-options="endPickerOptions"
        @change="onDateTimeChange('until')"
      />
    </template>
    <template v-if="isWeekly">
      <div class="c-grid-form__label c-grid-form__auto required">每周</div>
      <el-checkbox-group
        v-model="eventOptions.byDay"
        class="c-grid-form__auto l-flex--row c-event__option"
        size="mini"
        fill="#1c5cb0"
      >
        <el-checkbox-button
          v-for="week in weeks"
          :key="week.value"
          :label="week.value"
        >
          {{ week.label }}
        </el-checkbox-button>
      </el-checkbox-group>
      <div class="c-grid-form__label required">开始时间</div>
      <el-time-picker
        v-model="eventOptions.startTime"
        class="c-event__option"
        placeholder="请选择开始时间"
        value-format="HH:mm:ss"
        :clearable="false"
      />
      <div class="c-grid-form__label required">结束时间</div>
      <el-time-picker
        v-model="eventOptions.endTime"
        class="c-grid-form__info c-event__option"
        data-info="结束时间小于等于开始时间为跨天播放"
        placeholder="请选择结束时间"
        value-format="HH:mm:ss"
        :clearable="false"
      />
      <div class="c-grid-form__label required">生效日期</div>
      <el-date-picker
        v-model="eventOptions.start"
        class="c-event__option"
        type="date"
        placeholder="请选择生效日期"
        value-format="yyyy-MM-dd HH:mm:ss"
        :picker-options="pickerOptions"
        @change="onDateTimeChange('start')"
      />
      <div class="c-grid-form__label">失效日期</div>
      <el-date-picker
        v-model="eventOptions.until"
        class="c-grid-form__info c-event__option"
        data-info="失效日期当天不触发"
        type="date"
        :disabled="!eventOptions.start"
        placeholder="请选择失效日期"
        value-format="yyyy-MM-dd HH:mm:ss"
        :picker-options="endPickerOptions"
        @change="onDateTimeChange('until')"
      />
    </template>
    <template v-if="isCount">
      <div class="c-grid-form__label">次数</div>
      <el-input-number
        v-model="eventOptions.count"
        :min="1"
        :max="99999999"
        :step="1"
        step-strictly
      />
      <div class="c-grid-form__label required">开始时间</div>
      <el-date-picker
        v-model="eventOptions.start"
        class="c-event__option"
        type="datetime"
        placeholder="请选择生效时间"
        value-format="yyyy-MM-dd HH:mm:ss"
        :picker-options="pickerOptions"
      />
      <template v-if="untilDate">
        <div class="c-grid-form__label required">结束时间</div>
        <el-date-picker
          :value="untilDate"
          class="c-event__option"
          type="datetime"
          disabled
        />
      </template>
    </template>
    <event-target-dialog
      ref="eventTargetDialog"
      v-bind="$attrs"
      @choosen="onChoosen"
    />
  </div>
</template>

<script>
import {
  EventPriority,
  EventFreq,
  EventTarget
} from '@/constant'
import { getSchedule } from '@/api/calendar'
import { getProgram } from '@/api/program'
import {
  isMoreThanOneWeek,
  getNearestHitDate,
  isOverDay
} from '@/utils/event'
import { parseTime } from '@/utils'

const EventFreqCount = 'COUNT'

export default {
  name: 'EventPicker',
  props: {
    event: {
      type: Object,
      default: null
    },
    priority: {
      type: Number,
      default: EventPriority.NORMAL
    },
    vertical: {
      type: [Boolean, String],
      default: false
    }
  },
  data () {
    return {
      freqOptions: [
        { value: EventFreq.ONCE, label: '时段播放' },
        { value: EventFreq.WEEKLY, label: '重复播放' },
        { value: EventFreqCount, label: '按次播放' }
      ],
      weeks: [
        { value: '0', label: '日' },
        { value: '1', label: '一' },
        { value: '2', label: '二' },
        { value: '3', label: '三' },
        { value: '4', label: '四' },
        { value: '5', label: '五' },
        { value: '6', label: '六' }
      ],
      eventOptions: null,
      eventTarget: null
    }
  },
  computed: {
    isOnce () {
      return this.eventOptions.freq === EventFreq.ONCE
    },
    isWeekly () {
      return this.eventOptions.freq === EventFreq.WEEKLY
    },
    isCount () {
      return this.eventOptions.freq === EventFreqCount
    },
    pickerOptions () {
      return {
        disabledDate: this.isDisableDate
      }
    },
    endPickerOptions () {
      return {
        disabledDate: this.isDisableEndDate
      }
    },
    minDate () {
      const now = new Date()
      return new Date(now.getFullYear(), now.getMonth(), now.getDate())
    },
    msg () {
      return this.eventTarget ? this.eventTarget.name : '点击选择播放内容'
    },
    untilDate () {
      if (this.isCount && this.eventTarget) {
        const { start, count } = this.eventOptions
        const { duration } = this.eventTarget
        if (start && duration) {
          return new Date(start).getTime() + duration * count * 1000
        }
      }
      return null
    }
  },
  watch: {
    event: {
      handler () {
        this.init()
      },
      immediate: true
    }
  },
  methods: {
    isDisableDate (date) {
      return date < this.minDate
    },
    isDisableEndDate (date) {
      if (date < this.minDate) {
        return true
      }
      if (this.eventOptions.start) {
        if (this.isWeekly) {
          return date <= new Date(this.eventOptions.start)
        }
        return date < new Date(this.eventOptions.start)
      }
      return false
    },
    init () {
      const { freq, byDay, target, ...options } = {
        freq: EventFreq.ONCE,
        start: null,
        until: null,
        startTime: '00:00:00',
        endTime: '00:00:00',
        ...this.event
      }

      if (freq === EventFreq.ONCE && target?.duration) {
        const { start, until } = options
        this.eventOptions = {
          ...options,
          freq: EventFreqCount,
          count: (new Date(until) - new Date(start)) / target.duration / 1000,
          byDay: byDay ? byDay.split(',') : []
        }
      } else {
        this.eventOptions = {
          ...options,
          freq,
          count: 1,
          byDay: byDay ? byDay.split(',') : []
        }
      }

      this.eventTarget = target
    },
    onDateTimeChange (type) {
      const { start, until } = this.eventOptions
      if (start && until && start > until) {
        if (type === 'start') {
          this.eventOptions.until = start
        } else {
          this.eventOptions.start = until
        }
      }
    },
    onChoose () {
      this.$refs.eventTargetDialog.show()
    },
    onChoosen ({ value, done }) {
      done()
      this.eventTarget = value
      this.onCheckCount()
      this.$emit('choosen', value)
    },
    onEventTypeChanged () {
      this.onCheckCount()
      if (this.isCount) {
        this.eventOptions.until = null
      }
    },
    onCheckCount () {
      if (this.eventTarget && this.isCount) {
        this.getDuration(this.eventTarget).then(
          duration => {
            this.eventTarget = {
              ...this.eventTarget,
              duration
            }
          },
          ({ isCancel }) => {
            if (!isCancel) {
              this.$message({
                type: 'wanring',
                message: '暂无节目时长，将使用默认值（1分钟）'
              })
              this.eventTarget = {
                ...this.eventTarget,
                duration: 60
              }
            }
          }
        )
      }
    },
    getDuration ({ duration, type, id }) {
      if (duration === 0) {
        return Promise.reject()
      }
      if (!duration) {
        const loading = this.$showLoading()
        switch (type) {
          case EventTarget.RECUR:
            return getSchedule(id)
              .then(({ events }) => events.reduce((total, { spend }) => total + spend, 0))
              .finally(() => {
                this.$closeLoading(loading)
              })
          default:
            return getProgram(id)
              .then(({ data }) => Number(data.duration))
              .finally(() => {
                this.$closeLoading(loading)
              })
        }
      }
      return Promise.resolve(duration)
    },
    isEventTargetMatchEventFreq () {
      if (this.eventTarget && this.isCount) {
        return this.eventTarget.type === ''
      }
      return true
    },
    onError (message) {
      this.$message({
        type: 'warning',
        message
      })
      return null
    },
    isOnceSame () {
      const { freq, byDay, startTime, endTime } = this.eventOptions
      return freq === EventFreq.WEEKLY && byDay.length === 7 && startTime === '00:00:00' && endTime === '00:00:00'
    },
    createOnceEvent () {
      const { start, until } = this.eventOptions
      return {
        priority: this.priority,
        freq: EventFreq.ONCE,
        start, until
      }
    },
    createWeeklyEvent () {
      const { start, until, byDay, startTime, endTime } = this.eventOptions
      const byDayValue = byDay.join(',')
      const isOver = isOverDay({ startTime, endTime })
      const startWeek = new Date(start).getDay()
      const startDate = start.replace(/\d{2}:\d{2}:\d{2}$/, byDayValue.includes(startWeek) || isOver && byDayValue.includes((startWeek + 6) % 7) ? startTime : '00:00:00')
      const untilDate = until && until.replace(/\d{2}:\d{2}:\d{2}$/, isOver && byDayValue.includes((new Date(until).getDay() + 6) % 7) ? endTime : '00:00:00')
      const event = {
        priority: this.priority,
        freq: EventFreq.WEEKLY,
        start: startDate,
        until: untilDate,
        byDay: byDayValue,
        startTime,
        endTime
      }
      if (untilDate && !isMoreThanOneWeek(new Date(untilDate) - new Date(startDate)) && !getNearestHitDate(event, startDate, untilDate)) {
        return this.onError('有效日期内无法触发')
      }
      return event
    },
    createCountEvent () {
      const { start, count } = this.eventOptions
      const { duration } = this.eventTarget
      return {
        priority: this.priority,
        freq: EventFreq.ONCE,
        start,
        until: parseTime(new Date(start).getTime() + duration * count * 1000, '{y}-{m}-{d} {h}:{i}:{s}')
      }
    },
    createEventTarget () {
      const { duration, ...eventTarget } = this.eventTarget
      if (this.isCount) {
        return { ...eventTarget, duration }
      }
      return { ...eventTarget }
    },
    createEvent () {
      if (this.isWeekly && !this.isOnceSame()) {
        return this.createWeeklyEvent()
      }
      if (this.isCount) {
        return this.createCountEvent()
      }
      return this.createOnceEvent()
    },
    getValue () {
      if (!this.eventTarget) {
        return this.onError('请选择播放内容')
      }
      const { start, until } = this.eventOptions
      if (this.isOnce) {
        if (!start) {
          return this.onError('请选择生效时间')
        }
        if (start === until) {
          return this.onError('生效时间与失效时间不能一样')
        }
      }
      if (this.isWeekly) {
        const { byDay, startTime, endTime } = this.eventOptions
        if (!byDay.length) {
          return this.onError('请选择生效星期')
        }
        if (!startTime) {
          return this.onError('请选择开始时间')
        }
        if (!endTime) {
          return this.onError('请选择结束时间')
        }
        if (!start) {
          return this.onError('请选择生效日期')
        }
        if (until && start.split(' ')[0] === until.split(' ')[0]) {
          return this.onError('生效日期与失效日期不能一样')
        }
      }
      if (this.isCount) {
        if (!start) {
          return this.onError('请选择生效时间')
        }
      }
      if (until && new Date(until) <= Date.now()) {
        return this.onError('结束时间小于当前时间，请配置有效的生效时间')
      }
      return {
        ...this.createEvent(),
        target: this.createEventTarget()
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.c-event {
  &.row &__option {
    width: 100%;
  }

  &__program {
    position: relative;
    height: 40px;
    color: $blue;
    font-size: 14px;
    line-height: 1;
    border-radius: $radius--mini;
    border: 1px solid #dcdfe6;

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

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