<template>
  <wrapper
    :vertical="false"
    fill
    margin
    padding
    background
  >
    <device-tree-single
      class="c-sibling-item c-sidebar auto-width u-font-size--sm"
      @change="onChange"
    />
    <schema-table
      v-if="deviceId"
      ref="table"
      class="c-sibling-item far"
      row-key="id"
      :schema="schema"
    />
    <table-dialog
      ref="contentDialog"
      size="medium"
      title="上播内容"
      :schema="contentSchema"
    />
    <asset-task-dialog
      ref="taskDialog"
      @view="onViewAsset"
      @confirm="onSubmitAssetTask"
    />
    <radio-table-dialog
      ref="contractTableDialog"
      title="新增合同任务"
      message="请选择合同"
      :schema="contractTableSchema"
      @confirm="onSubmitContractTask"
    />
    <preview-dialog ref="previewDialog" />
    <confirm-dialog
      ref="timeDialog"
      title="上播时间设置"
      @confirm="onConfirmTime"
    >
      <div class="c-grid-form auto u-align-self--center">
        <div class="c-grid-form__label">上播方式</div>
        <schema-select
          v-model="taskTime.type"
          class="u-width"
          :schema="taskTimeTypeSelectSchema"
        />
        <template v-if="taskTime.type === 2">
          <div class="c-grid-form__label">时段</div>
          <el-time-picker
            key="task-range-picker"
            v-model="taskTime.range"
            class="u-width"
            is-range
            format="HH:mm"
            value-format="HH:mm"
            :clearable="false"
          />
        </template>
        <template v-if="taskTime.type === 3">
          <div class="c-grid-form__label">时间点</div>
          <el-time-picker
            key="task-time-picker"
            v-model="taskTime.point"
            class="u-width"
            value-format="HH:mm:ss"
            :clearable="false"
          />
        </template>
      </div>
    </confirm-dialog>
  </wrapper>
</template>

<script>
import {
  TimeType,
  SCREEN_TIME_KEY,
  TaskFromType,
  TaskFromTypeInfo,
  AssetTag,
  AssetTagInfo,
  AssetType,
  AssetTypeInfo
} from '@/constant'
import {
  parseDuration,
  parseTaskTime,
  getTaskTimeInfo,
  transformToTaskTime,
  offsetDate,
  calculateDay,
  getAssetThumb
} from '@/utils'
import {
  getContract,
  getContracts
} from '@/api/asset'
import {
  getTasks,
  addTask,
  deleteTask,
  updateTask,
  getOrderDetail
} from '../api'
import AssetTaskDialog from './components/AssetTaskDialog.vue'

export default {
  name: 'AdOrderTask',
  components: {
    AssetTaskDialog
  },
  data () {
    const canEdit = this.$store.getters.isOperator
    const canAudit = this.$store.getters.isGroupAdmin

    return {
      deviceId: '',
      schema: {
        buttons: canEdit
          ? [
            { type: 'add', label: '素材任务', on: this.onAddAssetTask },
            { type: 'add', label: '合同任务', on: this.onAddContractTask }
          ]
          : null,
        list: this.getTasks,
        transform: this.transform,
        cols: [
          { prop: 'type', type: 'refresh', width: 80 },
          { prop: 'name' },
          { label: '上刊日期', 'min-width': 220, render: (data, h) => canEdit && data.allowed && data.from === TaskFromType.ASSET
            ? h('el-date-picker', {
              staticClass: 'o-date-picker',
              props: {
                value: [data.startDate, data.endDate],
                type: 'daterange',
                rangeSeparator: '至',
                valueFormat: 'yyyy-MM-dd',
                editable: false,
                clearable: false
              },
              on: {
                input: val => this.onDateEdit(data, val)
              }
            })
            : `${data.startDate} 至 ${data.endDate}`, align: 'center' },
          { label: '上播时间', render: (data, h) => canEdit && data.allowed && data.from === TaskFromType.ASSET
            ? h('div', {
              staticClass: 'o-date-picker jc',
              on: {
                click: () => this.onEditTime(data)
              }
            }, data.range)
            : data.range, 'min-width': 120, align: 'center' },
          { label: '上播时长(s)', render: (data, h) => canEdit && this.canEditDuration(data)
            ? h('edit-input', {
              staticClass: 'border',
              props: {
                value: `${data.duration}`,
                align: 'center'
              },
              on: {
                edit: val => this.onSimpleEdit(data, 'duration', val)
              }
            })
            : data.duration, 'min-width': 100, align: 'center' },
          { label: '上播次数', render: (data, h) => canEdit && data.allowed && data.from === TaskFromType.ASSET
            ? h('edit-input', {
              staticClass: 'border',
              props: {
                value: `${data.count}`,
                align: 'center'
              },
              on: {
                edit: val => this.onSimpleEdit(data, 'count', val)
              }
            })
            : data.count, align: 'center' },
          { label: '审核次数', render: (data, h) => canAudit && data.allowed
            ? h('edit-input', {
              staticClass: 'border',
              props: {
                value: `${data.auditCount}`,
                align: 'center'
              },
              on: {
                edit: val => this.onAuditEdit(data, val)
              }
            })
            : '-', align: 'center' },
          { prop: 'tag', type: 'tag', on: canAudit && this.onAudit },
          { type: 'invoke', render: [
            { label: '查看', allow: ({ allowed }) => allowed, on: this.onViewTask },
            { label: '删除', allow: ({ from }) => from !== TaskFromType.ORDER, on: this.onDel }
          ], width: 92 }
        ]
      },
      contentSchema: {
        list: this.getContentAssets,
        cols: [
          { prop: 'tagType', label: '文件', width: 100, align: 'center' },
          { prop: 'fileType', label: '', width: 80 },
          { prop: 'file', label: '', type: 'asset', on: this.onViewAsset },
          { prop: 'adDuration', label: '上播时长', align: 'center' },
          { type: 'invoke', render: [
            { label: '查看', allow: ({ file }) => !!file, on: this.onViewAsset }
          ] }
        ]
      },
      contractTableSchema: {
        condition: { name: '' },
        list: getContracts,
        transform: this.transformContract,
        filters: [
          { key: 'name', type: 'search', placeholder: '合同名称' }
        ],
        cols: [
          { prop: 'name', label: '名称' },
          { prop: 'dateRange', label: '上刊日期', 'width': 200 },
          { prop: 'timeRange', label: '上播时间' },
          { prop: 'count', label: '上播次数' },
          { prop: 'durationInfo', label: '上播时长' }
        ]
      },
      taskTimeTypeSelectSchema: {
        options: [
          { value: TimeType.SCREEN, label: '开机期间' },
          { value: TimeType.RANGE, label: '时段' },
          { value: TimeType.POINT, label: '时间点' }
        ]
      },
      taskTime: {}
    }
  },
  watch: {
    deviceId () {
      this.$refs.table?.pageTo(1)
    }
  },
  methods: {
    onChange ({ id }) {
      this.deviceId = id
    },
    getTasks (params) {
      return getTasks({
        deviceId: this.deviceId,
        ...params
      })
    },
    canEditDuration ({ allowed, from, fromInfo }) {
      return allowed && from === TaskFromType.ASSET && fromInfo?.type === AssetType.IMAGE
    },
    transform (task) {
      const { id, from, fromId, fromInfo, startDate, startTime, endTime, day, duration, count, auditCount, enable } = task
      const allowed = this.isValidTask(from, fromInfo)
      return {
        id,
        from,
        fromId,
        fromInfo,
        type: this.getDataType(task),
        name: this.getDataName(task),
        startDate,
        endDate: offsetDate(startDate, day),
        startTime,
        endTime,
        range: getTaskTimeInfo({ startTime, endTime }),
        count,
        duration,
        auditCount,
        enable,
        tag: allowed
          ? this.getEnableTag(enable)
          : {
            type: 'danger',
            label: '异常',
            msg: '源数据丢失'
          },
        allowed
      }
    },
    isValidTask (from, fromInfo) {
      switch (from) {
        case TaskFromType.ORDER:
          return true
        default:
          return !!fromInfo
      }
    },
    getDataType ({ from, fromInfo }) {
      if (from === TaskFromType.ASSET && fromInfo) {
        return AssetTypeInfo[fromInfo.type]
      }
      return TaskFromTypeInfo[from]
    },
    getDataName ({ from, fromInfo }) {
      switch (from) {
        case TaskFromType.ORDER:
          return '自助广告'
        default:
          return fromInfo?.name || '-'
      }
    },
    getEnableTag (enable) {
      return {
        type: enable ? 'success' : 'primary',
        label: enable ? '已审核' : '待审核'
      }
    },
    transformContract (contract) {
      contract.durationInfo = parseDuration(contract.duration)
      contract.dateRange = `${contract.startDate} 至 ${offsetDate(contract.startDate, contract.day)}`
      contract.timeRange = getTaskTimeInfo(contract)
      return contract
    },
    onViewTask (task) {
      switch (task.from) {
        case TaskFromType.ORDER:
          getOrderDetail(task.fromId).then(({ data }) => {
            this.showContentDialog(data.assets.map(this.transformOrderAsset))
          })
          break
        case TaskFromType.ASSET:
          this.onViewAsset({
            file: {
              type: task.fromInfo.type,
              url: task.fromId
            }
          })
          break
        case TaskFromType.CONTRACT:
          getContract(task.fromId).then(({ data }) => {
            this.showContentDialog(data.assets.map(this.transformContractAsset))
          })
          break
        default:
          break
      }
    },
    showContentDialog (assets) {
      if (assets.length === 1) {
        assets[0].adDuration = '独占'
      }
      this.$assets = assets
      this.$refs.contentDialog.show()
    },
    getContentAssets () {
      const assets = this.$assets
      return Promise.resolve({
        data: assets,
        totalCount: assets.length
      })
    },
    transformOrderAsset ({ keyName, type, adDuration, thumb }) {
      const isImage = type === AssetType.IMAGE
      return type
        ? {
          tagType: AssetTagInfo[AssetTag.AD],
          fileType: AssetTypeInfo[type],
          file: {
            type,
            url: keyName,
            thumb: isImage ? keyName : thumb,
            origin: !isImage
          },
          adDuration: parseDuration(adDuration)
        }
        : {
          tagType: '素材已删除',
          adDuration: parseDuration(adDuration)
        }
    },
    transformContractAsset ({ duration, minioData }) {
      if (minioData) {
        const { tag, type, keyName } = minioData
        return {
          tagType: AssetTagInfo[tag],
          fileType: AssetTypeInfo[type],
          file: {
            type,
            url: keyName,
            thumb: getAssetThumb(minioData)
          },
          adDuration: parseDuration(duration)
        }
      }
      return {
        tagType: '素材已删除',
        adDuration: parseDuration(duration)
      }
    },
    onViewAsset ({ file }) {
      this.$refs.previewDialog.show(file)
    },
    onDel ({ id, type, name }) {
      deleteTask(id, `${type} ${name}`).then(() => {
        this.$refs.table.decrease(1)
      })
    },
    onAddAssetTask () {
      this.$refs.taskDialog.show()
    },
    onSubmitAssetTask ({ value, done }) {
      this.addTask(value).then(done)
    },
    onAddContractTask () {
      this.$refs.contractTableDialog.show()
    },
    onSubmitContractTask ({ value, done }) {
      this.addTask({
        from: TaskFromType.CONTRACT,
        fromId: value.id,
        startDate: value.startDate,
        day: value.day,
        startTime: value.startTime,
        endTime: value.endTime,
        count: value.count,
        duration: value.duration
      }).then(done)
    },
    addTask (task) {
      return addTask({
        ...task,
        auditCount: task.count,
        deviceIdList: [this.deviceId],
        enable: false
      }).then(() => {
        this.$refs.table.pageTo(1)
      })
    },
    onAudit (task) {
      const { allowed, enable, startTime, endTime, duration, auditCount } = task
      if (!allowed) {
        return
      }
      if (!enable) {
        const totalDuration = duration * auditCount * 1000
        if (startTime && endTime && endTime !== SCREEN_TIME_KEY) {
          const remind = new Date(`2000-01-01 ${endTime}`) - new Date(`2000-01-01 ${startTime}`)
          if (remind < totalDuration) {
            this.$message({
              type: 'warning',
              message: '所选时段无法满足上播次数'
            })
            return
          }
        }
      }
      this.$confirm(
        enable ? '停止使用后将不可参与自动编单' : '启用后将可参与自动编单',
        enable ? '停用任务' : '启用任务',
        { type: 'warning' }
      ).then(() => {
        this.onUpdateEnable(task)
      })
    },
    onUpdateEnable (task) {
      const { id, enable } = task
      updateTask({
        id,
        enable: !enable
      }).then(() => {
        task.enable = !enable
        task.tag = this.getEnableTag(!enable)
      })
    },
    onSimpleEdit (task, key, { newVal, oldVal }) {
      if (!newVal || !/^\d+$/.test(newVal) || Number(newVal) < 1) {
        return
      }
      if (newVal !== oldVal) {
        task[key] = Number(newVal)
        updateTask({
          id: task.id,
          enable: false,
          [key]: newVal
        }).then(
          () => {
            if (task.enable) {
              task.enable = false
              task.tag = this.getEnableTag(false)
            }
          },
          () => {
            task[key] = oldVal
          }
        )
      }
    },
    onDateEdit (task, val) {
      const { id, enable, startDate, endDate } = task
      if (startDate !== val[0] || endDate !== val[1]) {
        const day = calculateDay(val[0], val[1]) + 1
        updateTask({
          id,
          enable: false,
          startDate: val[0],
          day
        }).then(
          () => {
            if (enable) {
              task.enable = false
              task.tag = this.getEnableTag(false)
            }
            task.startDate = val[0]
            task.endDate = val[1]
            task.day = day
          }
        )
      }
    },
    onAuditEdit (task, { newVal, oldVal }) {
      if (!newVal || !/^\d+$/.test(newVal) || Number(newVal) < 1) {
        return
      }
      if (newVal !== oldVal) {
        const auditCount = Number(newVal)
        if (task.from === TaskFromType.ORDER && auditCount < task.count) {
          this.$message({
            type: 'warning',
            message: '订单的审核次数不能小于上播次数'
          })
          return
        }
        if (task.from === TaskFromType.CONTRACT && auditCount < task.count) {
          this.$message({
            type: 'warning',
            message: '合同的审核次数不能小于上播次数'
          })
          return
        }
        task.auditCount = auditCount
        updateTask({
          id: task.id,
          enable: false,
          auditCount
        }).then(
          () => {
            if (task.enable) {
              task.enable = false
              task.tag = this.getEnableTag(false)
            }
          },
          () => {
            task.auditCount = oldVal
          }
        )
      }
    },
    onEditTime (task) {
      this.$task = task
      this.taskTime = parseTaskTime(task)
      this.$refs.timeDialog.show()
    },
    onConfirmTime (done) {
      const { id, enable, startTime, endTime } = this.$task
      const { startTime: targetStartTime, endTime: targetEndTime } = transformToTaskTime(this.taskTime)
      if (!targetStartTime) {
        this.$message({
          type: 'warning',
          message: '请选择上播时间'
        })
        return
      }
      if (startTime !== targetStartTime || endTime !== targetEndTime) {
        updateTask({
          id,
          enable: false,
          startTime: targetStartTime,
          endTime: targetEndTime
        }).then(
          () => {
            if (enable) {
              this.$task.enable = false
              this.$task.tag = this.getEnableTag(false)
            }
            this.$task.startTime = targetStartTime
            this.$task.endTime = targetEndTime
            this.$task.range = getTaskTimeInfo({ startTime: targetStartTime, endTime: targetEndTime })
            done()
          }
        )
      } else {
        done()
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.c-task {
  line-height: 1;
  border-radius: $radius--sm;
  border: 1px solid #dcdfe6;

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

  &__name {
    position: absolute;
    width: 100%;
    height: 100%;
  }
}

::v-deep .o-date-picker {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: auto;
  min-height: $height;
  padding: 3px 0;
  border: 1px solid $primary;
  border-radius: $radius--sm;
  background-color: $blue--light;

  &.jc {
    justify-content: center;
  }

  &:hover {
    border-color: $gray--dark;
  }

  .el-range-input {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
    background-color: $blue--light;
  }

  .el-range-separator {
    flex: 0 0 auto;
    width: auto;
    min-width: 0;
  }

  .el-input__icon {
    display: none;
  }
}
</style>
