import cloneDeep from 'lodash.clonedeep'
import scrollIntoView from 'scroll-into-view-if-needed'
import { message } from 'ant-design-vue'
// 把 form 相关的公共 API 拿出来，各种包装的 form 组件都自动拥有这个 API

const sdFormPublicMethodsNew = {
  methods: {
    /**
     * 获取单个字段的值
     * @param {string} name 字段名
     * @returns {any}
     * @public
     */
    getFieldValue(name) {
      return cloneDeep(this.model[name])
    },
    /**
     * 获取整个表单的值
     * @returns {object}
     * @public
     */
    getFieldsValue() {
      return cloneDeep(this.model)
    },
    /**
     * 设置单个字段的值
     * @param {string} name 字段名
     * @param {any} value 字段值
     * @public
     */
    setFieldValue(name, value) {
      this.$set(this.model, name, value)
    },
    /**
     * 设置多个字段的值
     * @param {object} values 字段名+值的map
     * @public
     */
    setFieldsValue(values) {
      for (const field in values) {
        this.setFieldValue(field, values[field])
      }
    },
    /**
     * 获取整个表单的值，并按照后台格式要求进项转换
     * @returns {object}
     * @public
     */
    getBackendValues() {
      const values = this.getFieldsValue()
      return this.initValues.map((field) => {
        let value = values[field.name]
        if (typeof value !== 'undefined') {
          if (value !== null) {
            const toBackendValue = this.fieldOptions[field.name]?.toBackendValue
            if (toBackendValue) value = toBackendValue(value)
          }
        } else {
          // value是undefined，尝试从默认值里面取（针对前端没渲染的字段）
          const defaultValue = field.attr?.defaultValue
          if (typeof defaultValue !== 'undefined') {
            value = defaultValue
          }
        }
        return {
          name: field.name,
          value,
        }
      })
    },
    /**
     * 获取整个表单的值，并转换为显示给最终用户的值
     * @returns {Promise<object>}
     * @public
     */
    getDisplayValues() {
      this.showExtraForm = true
      const modelValues = this.getFieldsValue()
      return new Promise((resolve) => {
        // 等extraForm通过v-if显示出来
        this.$nextTick(() => {
          const extraForm = this.$refs.extraForm
          // 把用户修改过的最新的值，设置进去
          extraForm.setFieldsValue(modelValues)
          // 等setFieldsValue的值反映到DOM节点上
          extraForm.$nextTick(() => {
            const values = {}
            for (const field in extraForm.fieldOptions) {
              values[field] = extraForm.fieldOptions[field]
                .getItemText?.(modelValues[field])
                ?.trim()
            }
            // 取完值以后，隐藏extraForm
            this.showExtraForm = false
            resolve(values)
          })
        })
      })
    },
    /**
     * 校验整个表单
     * @returns {Promise<boolean>}
     * @public
     */
    validateFields() {
      return this.$refs.form
        .validate()
        .catch((data) => {
          // 找到第一个校验错误的元素，把它滚动到可视区域
          const errorEl = this.$el.querySelector('.has-error')
          if (errorEl) {
            scrollIntoView(errorEl, {
              scrollMode: 'if-needed',
              block: 'nearest',
              skipOverflowHiddenElements: true,
            })
          }

          return Promise.reject(data)
        })
        .then(() => {
          const { formula, message: text } = this.formulaValidator?.[0] || {}
          if (formula) {
            return this.getValueByFormula(formula).then((flag) => {
              if (!flag) {
                message.error(text)
                return Promise.reject(text)
              } else {
                return true
              }
            })
          }
          return true
        })
    },
    /**
     * 校验单个字段
     * @param {string} field 字段名
     * @returns {Promise}
     * @public
     */
    validateField(field) {
      return new Promise((resolve, reject) => {
        if (!this.fields[field]) {
          reject(new Error(`没有找到${field}字段`))
        } else {
          if (!this.$refs.form.fields.some((item) => field === item.prop)) {
            // 只读的字段
            resolve(true)
            return
          }
          this.$refs.form.validateField(field, (errorMessage) => {
            if (!errorMessage) {
              resolve(true)
            } else {
              // 保持与ant design一致，返回errorMessage
              // eslint-disable-next-line prefer-promise-reject-errors
              reject(errorMessage)
            }
          })
        }
      })
    },
    /**
     * 重置表单
     * @public
     */
    resetFields() {
      return this.$refs.form.resetFields()
    },
    /**
     * 用户是否已修改数据
     * @public
     * @since 8.1.0.28
     */
    isDirty() {
      return this.initModelToBackendValue !== JSON.stringify(this.getBackendValues())
    },
  },
  provide() {
    return {
      SdFormContainer: this,
    }
  },
  sdMixinName: 'sdFormPublicMethodsNew',
  inject: {
    SdFormContainer: { default: null },
  },
  created() {
    if (this.$options.name !== 'SdForm') {
      // 如果不是 sdForm ，把当前mixin的所有方法，代理到内部的 form 引用上执行
      const sdFormPublicMethods = this.$options.mixins.find(
        (mixin) => mixin.sdMixinName === 'sdFormPublicMethodsNew'
      )
      for (const name in sdFormPublicMethods.methods) {
        this[name] = (...args) => {
          return (this.$refs.form || this.$refs.sdForm)[name](...args)
        }
      }
    }
    if (this.$options.name === 'SdForm') {
      if (!this.disableExtraForm) {
        // 如果当前是 sdForm ，把自己注册到上上层或上层的容器里
        const container = this.SdFormContainer?.SdFormContainer || this.SdFormContainer
        if (container && !container.SdForm) container.SdForm = this
        if (container) {
          container.$emit('sdFormReady')
        }
      }
    }
  },
}

export default sdFormPublicMethodsNew
