import sdFormItemMixin from './sd-form-item-mixin'

function compareTime(h1, m1, s1, h2, m2, s2) {
  const result = h1 * 10000 + m1 * 100 + s1 > h2 * 10000 + m2 * 100 + s2
  return result
}

function getDisabledDate(start, end, reverse) {
  // 开始日期小于结束日期，不需要限制时间范围
  if (
    start
      .clone()
      .startOf('day')
      .valueOf() <
    end
      .clone()
      .startOf('day')
      .valueOf()
  )
    return {}

  const h1 = start.hours()
  const m1 = start.minutes()
  const s1 = start.seconds()
  const h2 = end.hours()
  const m2 = end.minutes()
  const s2 = end.seconds()

  const hours = []
  const minutes = []
  const seconds = []
  if (reverse) {
    for (let h = 0; h < 24; h++) {
      if (compareTime(h1, m1, s1, h, m2, s2)) hours.push(h)
    }
    for (let m = 0; m < 60; m++) {
      if (compareTime(h1, m1, s1, h2, m, s2)) minutes.push(m)
    }
    for (let s = 0; s < 60; s++) {
      if (compareTime(h1, m1, s1, h2, m2, s)) seconds.push(s)
    }
  } else {
    for (let h = 0; h < 24; h++) {
      if (compareTime(h, m1, s1, h2, m2, s2)) hours.push(h)
    }
    for (let m = 0; m < 60; m++) {
      if (compareTime(h1, m, s1, h2, m2, s2)) minutes.push(m)
    }
    for (let s = 0; s < 60; s++) {
      if (compareTime(h1, m1, s, h2, m2, s2)) seconds.push(s)
    }
  }

  return {
    disabledHours: () => hours,
    disabledMinutes: () => minutes,
    disabledSeconds: () => seconds,
  }
}

const sdFormItemInputMixin = {
  mixins: [sdFormItemMixin],
  created() {
    if (Array.isArray(this.name)) return
    // 是否隐藏的处理
    this.processHidden()
    // 中文字段名的处理
    if (this.label) {
      this.SdFormContext.labels[this.name] = this.label
      this.SdFormContext.labels = { ...this.SdFormContext.labels }
    }

    // 字段各种选项的处理
    if (!this.fieldOption.props) this.fieldOption.props = {}
    this.fieldOption.dynamicProps = {}
    this.fieldOption.on = { ...this.fieldOption.on, ...this.$listeners }
    if (this.parseBackendValue) {
      this.fieldOption.parseBackendValue = this.parseBackendValue
      this.SdFormContext.parseBackendValue(this.name)
    }
    if (this.toBackendValue) this.fieldOption.toBackendValue = this.toBackendValue
    if (this.component) this.fieldOption.component = this.component
    if (this.componentForDisplay) this.fieldOption.componentForDisplay = this.componentForDisplay

    if (this.getDisplayValue) {
      this.fieldOption.getDisplayValue = this.getDisplayValue
    }
    const field = this.field

    if (!this.fieldOption.getItemText) {
      this.fieldOption.getItemText = this.getItemText
    }

    // 获取字段的默认值
    const initValue = field.value
    if (typeof initValue === 'undefined' || initValue === null) {
      const defaultValueInSlot = this.$slots.default?.[0]?.componentOptions?.propsData.defaultValue
      if (typeof defaultValueInSlot !== 'undefined') {
        this.$set(this.model, this.name, defaultValueInSlot)
      } else {
        const defaultValueInProp = this.inputProps?.defaultValue
        if (typeof defaultValueInProp !== 'undefined') {
          this.$set(this.model, this.name, defaultValueInProp)
        } else {
          let defaultValueFromBackend = field.attr?.defaultValue
          if (typeof defaultValueFromBackend !== 'undefined' && defaultValueFromBackend !== null) {
            if (this.fieldOption.parseBackendValue) {
              defaultValueFromBackend = this.fieldOption.parseBackendValue(defaultValueFromBackend)
            }
            this.$set(this.model, this.name, defaultValueFromBackend)
          }
        }
      }
    }

    // 处理两个组件组成的范围
    if (this.rangeAfter) {
      const pairItemOption = this.SdFormContext.fieldOptions[this.rangeAfter]
      switch (this.field.dataType) {
        case 'number': {
          this.fieldOption.on.blur = () => {
            const val = parseFloat(this.model[this.name])
            pairItemOption.props.max = isNaN(val) ? undefined : val
          }
          pairItemOption.on.blur = () => {
            const val = parseFloat(this.model[this.rangeAfter])
            this.fieldOption.props.min = isNaN(val) ? undefined : val
          }
          break
        }
        case 'date': {
          // 结束日期不能小于开始日期
          this.fieldOption.props.disabledDate = (endValue) => {
            const startValue = this.model[this.rangeAfter]
            if (!endValue || !startValue) {
              return false
            }
            return startValue.valueOf() > endValue.valueOf()
          }

          this.fieldOption.props.disabledTime = (endValue) => {
            const startValue = this.model[this.rangeAfter]
            if (!endValue) {
              // 日期比较时过程中，比较的值是空,这时直接点选择时间会造成时间无法限制，这种情况下让它日期先等于被比较值，这样时间就可以限制选择（空值情况下日期选择面板本身默认选中的就是被比较的那天）
              endValue = startValue
            }
            if (!endValue || !startValue) {
              return false
            }
            return getDisabledDate(startValue, endValue, true)
          }

          // 处理结束日期选择器的打开、关闭
          const endDateOpenChange = (open) => {
            if (open && !this.model[this.name]) {
              // 选择结束日期时如果没有默认值，把开始日期座位面板打开的默认值，否则相同的日期可能无法选择
              this.fieldOption.props.defaultPickerValue = this.model[this.rangeAfter]
            } else {
              this.fieldOption.props.defaultPickerValue = undefined
            }
            this.fieldOption.props.open = open
            this.SdFormContext.fieldOptions = { ...this.SdFormContext.fieldOptions }
          }
          this.fieldOption.on.openChange = endDateOpenChange

          // 开始日期不能大于结束日期
          pairItemOption.props.disabledDate = (startValue) => {
            const endValue = this.model[this.name]
            if (!startValue || !endValue) {
              return false
            }
            return startValue.valueOf() > endValue.valueOf()
          }

          pairItemOption.props.disabledTime = (startValue) => {
            const endValue = this.model[this.name]
            if (!startValue) {
              startValue = endValue
            }
            if (!startValue || !endValue) {
              return false
            }
            return getDisabledDate(startValue, endValue)
          }

          // 开始日期修改了值，自动打开结束日期的选择器
          pairItemOption.on.openChange = (open) => {
            if (!open) endDateOpenChange(true)
          }
          break
        }
        default:
          break
      }

      this.SdFormContext.fieldOptions = { ...this.SdFormContext.fieldOptions }
    }
  },
  watch: {
    hidden() {
      this.processHidden()
    },
  },
  methods: {
    processHidden() {
      if (Array.isArray(this.name)) return {}
      // 只处理prop传过来的hidden，计算的隐藏会触发rulesComputed重复计算
      this.$set(this.SdFormContext.hiddenStatus, this.name, this.hidden)
    },
    getItemText() {
      let domNode
      if (this.$options.name === 'SdFormItemTdInput') {
        domNode = this.$el
      } else {
        domNode = this.$el.querySelector('.ant-form-item-control-wrapper')
      }
      return domNode.innerText
    },
  },
  computed: {
    model() {
      return this.SdFormContext.model
    },
    displayValue() {
      const value = this.model[this.name]
      if (typeof value !== 'undefined' && value !== null && this.fieldOption.getDisplayValue) {
        let result = this.fieldOption.getDisplayValue(this.model[this.name], {
          field: this.field,
          inputProps: this.fieldProps,
        })
        // 空字符串替换为空格，否则在模板里写 displayValue || value 有问题
        if (result === '') result = ' '
        return result
      }
    },
    fieldOption() {
      if (Array.isArray(this.name)) return {}
      const fieldOption = this.SdFormContext.fieldOptions[this.name]
      if (fieldOption) {
        return fieldOption
      }
      throw new Error(`前端页面包含字段${this.name}，但是接口并没有返回该字段`)
    },
    fieldProps() {
      // 把动态prop 和 静态prop 合并
      const dynamicProps = {}
      for (const key in this.fieldOption.dynamicProps) {
        dynamicProps[key] = this.fieldOption.dynamicProps[key]()
      }
      return { ...this.fieldOption.props, ...this.inputProps, ...dynamicProps }
    },
    inputSlots() {
      // 把input-开头的slot，转发给内部的组件
      const slots = []
      for (const slot in this.$scopedSlots) {
        if (slot.startsWith('input-')) {
          slots.push(slot.replace(/^input-/, ''))
        }
      }
      return slots
    },
    fieldDescription() {
      if (this.field.attrFD?.popoverDescription) return ''
      return this.field.attrFD?.description
    },
  },
  provide() {
    return {
      SdFormItemContext: this,
    }
  },
}
export default sdFormItemInputMixin
