<template>
  <div :class="wrapClasses" :style="input.styles" :data-sign="sign">
    <!-- label -->
    <form-label v-if="input.label" :size="size" :input="input" :position="position" :label-width="labelWidth"></form-label>
    <!-- content -->
    <div class="uif-form-content">
      <div :class="borderClass">
        <!-- icon  -->
        <form-icon v-if="input.actionIcon || input.availableIcon" :input="input" @icon-click="handleIconClick"></form-icon>
        <!-- 后置 slot  -->
        <base-slot v-if="input.slot" :slot-name="input.slot" :attrs="{class: 'uif-form-item-icon'}" :params="input"></base-slot>
        <!-- inputs  -->
        <template v-for="(ipt, index) in inputs">
          <!-- 分割符  -->
          <div v-if="index > 0" class="uif-form-border-split" :key="`${ipt.name}_split`"></div>
          <!-- 主体  -->
          <form-block :input="ipt" :transfer="transfer" :size="size" :key="`${ipt.name}_block`"
                      v-bind="$attrs" v-on="$listeners" @focus="handleFocus" @blur="handleBlur"></form-block>
        </template>
      </div>
      <form-info :info="input.info"></form-info>
    </div>
    <!-- 外置 slot  -->
    <base-slot v-if="input.afterSlot" :slot-name="input.afterSlot" :attrs="{class: 'uif-form-after-slot'}" :params="input"></base-slot>
  </div>
</template>

<script>
import FormLabel from './form-label.vue'
import FormInfo from './form-info.vue'
import FormBlock from './form-block'
import FormIcon from './form-icon'
import BaseSlot from '@uif/hq/lib/components/base-slot'
import {parseInputs, hasInputRect, validate, getFormData, inputsSign, findInput} from '@uif/admin/lib/utils/form'
import {oneOf} from '@uif/hq/lib/utils/assist'
import {filter, some} from '@uif/hq/lib/utils/array'
import {addAttr, assign} from '@uif/hq/lib/utils/object'

export default {
  inheritAttrs: false,
  name: 'u-form-item',
  components: {
    FormLabel,
    FormBlock,
    FormIcon,
    FormInfo,
    BaseSlot
  },
  props: {
    input: {
      type: Object,
      default () {
        return {}
      }
    },
    position: {
      type: String,
      default: 'left'
    },
    labelWidth: {
      type: [Number, String],
      default: 130
    },
    autoValidate: {
      type: Boolean,
      default: true
    },
    // 是否强制 transfer
    transfer: {
      type: Boolean,
      default: false
    },
    size: {
      validator (value) {
        return oneOf(value, ['default', 'small'])
      },
      default: 'default'
    }
  },
  data () {
    return {
      formData: {},
      warning: null,
      warningTimer: 0 // 延迟，避免闪烁
    }
  },
  computed: {
    // input 转换成 inputs 数组
    inputs () {
      return filter(parseInputs(this.input), input => !input.hidden)
    },
    // 是否全部禁用
    isDisabled () {
      return !some(this.inputs, input => !input.disabled)
    },
    // 容器样式
    wrapClasses () {
      return [
        'uif-form-item',
        'uif-form-item-size-' + this.size,
        'uif-form-item-' + this.position,
        this.input.classes
      ]
    },
    borderClass () {
      const {info} = this.input
      const hasRect = hasInputRect(this.input)
      const classes = {
        'uif-form-border-rect': hasRect,
        'uif-form-border-rect-error': hasRect && info && info.type === 'error',
        'uif-form-border-rect-disabled': hasRect && this.isDisabled
      }
      addAttr(classes, 'uif-form-border-fix-' + this.input.type, !hasRect)
      return [
        'uif-form-border',
        'uif-form-border-size-' + this.size,
        classes
      ]
    },
    sign () {
      return this.inputs.reduce((sign, input) => sign + input['_sign'], '')
    }
  },
  created () {
    inputsSign(this.inputs)
  },
  mounted () {
  },
  methods: {
    // 获取formData
    getValue (original) {
      return assign(getFormData(this.inputs), original)
    },
    // 检查表单组
    check () {
      return new Promise((resolve, reject) => {
        validate(this.input).then(() => {
          resolve(this.getValue())
        }).catch((error) => reject(error))
      })
    },
    // 设置表单值
    // @formData {Object} input额外的参数
    set (name, value, formData) {
      findInput(this.inputs, name, (input) => {
        this.$set(input, 'value', value)
        if (formData) this.$set(input, 'formData', formData)
      })
    },
    handleIconClick (...arg) {
      this.$emit('icon-click', ...arg)
    },
    handleFocus (...arg) {
      const {info} = this.input
      if (info && info.type === 'error') {
        this.$set(this.input, 'info', null)
      }
      this.$emit('u-focus', ...arg)
    },
    handleBlur (name) {
      if (this.autoValidate) {
        const inputs = filter(this.inputs, ipt => ipt.name === name)
        validate(inputs, this.input, false)
      }
      this.$emit('u-blur', name)
    }
  }
}
</script>
