import { ElFormItem, ElTooltip } from 'element-plus'
import { h, toRef, computed, ref, unref, onErrorCaptured } from 'vue'
import { getInputComponent, getViewComponent, getH5InputComponent } from '../cip-form-input/util'
import { isEmpty, isEmptyObject, isInputEmpty } from '@cip/utils/util'
import { useWatchFieldDepend } from './hooks/use-field-depend'
import { useFieldValue, useSteamUpdateValues } from './hooks/use-model-change'
import { useRules } from './hooks/use-field-rules'
import { isHideLabel, getLabelWidth, UpdateModelQueue } from './util'
import './index.less'
import { useFormInject, useElFormInject } from '../hooks/use-form'
import { useCipConfig } from '@cip/components/hooks/use-cip-config'
export default {
  name: 'CipFormItem',
  props: {
    config: Object, // 字段配置信息
    fieldKey: String, // 字段名
    model: { // 字段所属model
      type: Object,
      default: () => ({})
    },
    readonly: Boolean, // 是否只读-即查看模式
    customSlots: Function,
    showTemplate: { // 是否展示模版值[注：表单设计中使用]
      type: Boolean,
      default: false
    },
    tableDependOnValues: Object,
    inTable: {
      type: Boolean,
      default: false
    },
    componentKey: String,
    grid: [Number, Boolean],
    tableData: Array,
    onSearch: Function // 供CipSearchForm使用
  },
  emits: ['update:model'],
  setup (props, context) {
    onErrorCaptured((e) => {
      // el-form-item 在onBeforeUnmount会访问el.value.firstElementChild 由于切换较快的原因会抱错
      process.env.NODE_ENV === 'development' && console.log(e)
      return false
    })
    // elForm组件实例
    const cipConfig = useCipConfig()
    const elForm = useElFormInject()
    const cipForm = useFormInject()
    const equipment = computed(() => {
      return unref(cipForm.equipment) || 'pc'
    })

    // 一般处于cip-table直接使用的情况下
    const notInForm = computed(() => {
      return isEmptyObject(elForm)
    })

    const updateModel = (value) => {
      // console.log('updateModel', value)
      // if (!notInForm.value) {
      //   // 因为延迟执行的问题，可能导致数据无法及时有效验证手动调用
      //   elForm.validateField([formItemConfig.value.ruleKey || props.fieldKey])
      // }
      context.emit('update:model', value)
    }

    const updateModelQueue = new UpdateModelQueue(() => props.model, updateModel)

    // FormItem及Input组件渲染模式 ['hidden','read','read-write']
    const status = computed(() => {
      // 为设置则默认开始可读可写模式
      const config = formItemConfig.value
      if (props.readonly) {
        if (config.readable === false) return 'hidden'
        return 'read'
      }
      if (isEmpty(config.readable) && isEmpty(config.writable)) {
        return 'read-write'
      }
      if (config.writable) {
        return 'read-write'
      } else if (config.readable) {
        return 'read'
      } else {
        return 'hidden'
      }
    })
    // Input组件实际使用的配置
    const formItemConfig = computed(() => {
      return runningConfig.value || props.config // handleFormConfig()
    })
    const model = toRef(props, 'model')
    const fieldKey = toRef(props, 'fieldKey')
    // 仅正对modelValue生效
    const changeEffect = computed(() => {
      return formItemConfig.value.changeEffect
    })

    // 3种数据更新方式并行
    // modelValue
    const [modelValue, updateModelValue] = useFieldValue(fieldKey, model, updateModelQueue, changeEffect)
    const otherKey = computed(() => formItemConfig.value?.otherKey)
    // otherValue
    const [otherValue, updateOtherValue] = useFieldValue(otherKey, model, updateModelQueue)

    const { values, streamUpdateModel, clearValues } = useSteamUpdateValues(fieldKey, otherKey, model, updateModel, changeEffect)
    // 监听依赖 触发响应事件
    const { changeCount, dependOnValues, outDependOnValues, runningConfig } = useWatchFieldDepend(props, context, { updateModelValue, updateOtherValue, clearValues })
    const readonly = toRef(props, 'readonly')
    // rules
    const { usingRules, rules } = useRules(formItemConfig, readonly, status, otherValue, dependOnValues, outDependOnValues)
    // Input组件是否展示标记(需要控制form-item内置的margin-bottom)
    const childStatus = ref(true)
    // FormItem label
    const formItemLabel = () => {
      // 隐藏label或者label为空时直接返回空字符串
      if (formItemConfig.value.hideLabel === true || isEmpty(formItemConfig.value.label)) return ''
      // 表单为只读模式下展示样式控制
      const labelId = formItemConfig.value.directory ? props.fieldKey : undefined
      const result = [h('span', { class: { 'is-readonly': props.readonly }, id: labelId }, [formItemConfig.value.label])]
      // 存在说明
      if (formItemConfig.value.description) {
        const descriptionComp = (
          <ElTooltip effect={formItemConfig.value.descriptionEffect || 'light'} placement={'top'}>
            {{
              content: () => formItemConfig.value.description,
              default: () => <i class={'el-icon-question'} style={'margin-left:2px;line-height: inherit;'} />
            }}
          </ElTooltip>
        )
        result.push(descriptionComp)
      }
      // 仅在正在使用rules的input中且required为true时展示必填标记
      if (usingRules.value && formItemConfig.value.required) {
        const requiredAsterisk = (<span class={'cip-danger-color'}>*</span>)
        result.unshift(requiredAsterisk)
      }
      // 有标签后缀的增加标签后缀
      if (elForm.labelSuffix) {
        result.push(elForm.labelSuffix)
      }
      return h('div', { style: { color: '#333333', ...formItemConfig.value.labelStyle } }, result) // result
    }
    const inlineErrorMessage = computed(() => {
      return props.inTable || cipForm.equipment === 'mobile'
    })
    // FormItem ErrorMessage
    const errorMessageNode = ({ error }) => {
      if (!inlineErrorMessage.value) return null
      return (
        <ElTooltip content={error}>
          <i class={'el-icon-warning cip-danger-color '} style={{ outline: 'none', border: 'none' }} />
        </ElTooltip>
      )
    }

    const labelPosition = computed(() => {
      // 依赖elForm实例数据总是在变换、故修改为有父组件cip-form下发数据
      if (!isEmpty(formItemConfig.value.labelPosition)) {
        return formItemConfig.value.labelPosition === 'top'
      }
      return unref(cipForm.labelPosition) === 'top'
    })
    const itemDisabled = computed(() => {
      return formItemConfig.value.importantDisabled !== undefined
        ? formItemConfig.value.importantDisabled
        : formItemConfig.value.disabled
    })
    const renderItemInput = () => {
      if (props.customSlots) {
        return props.customSlots({
          fieldKey: props.fieldKey,
          modelValue: modelValue.value,
          updateModel: updateModelValue, // 即将废弃，此处名字与实际功能不符合
          updateModelValue
        })
      }
      const type = formItemConfig.value.type || 'default'
      const componentProps = {
        key: props.componentKey,
        id: props.fieldKey,
        fieldKey: props.fieldKey,
        modelValue: modelValue.value,
        otherValue: otherValue.value,
        values: values.value,
        // model: model.value, // 即将废弃
        changeCount: changeCount.value,
        config: formItemConfig.value,
        usingRules: usingRules.value,
        rules: rules.value,
        dependOnValues: dependOnValues.value,
        outDependOnValues: outDependOnValues.value,
        disabled: itemDisabled.value,
        showTemplate: props.showTemplate,
        tableData: props.tableData,
        class: 'cip-form-item__input',
        onStatusChange: (status) => { // 子组件触发事件控制父组件是否显示
          childStatus.value = status
        },
        onSearch: props.onSearch
      }

      if (status.value === 'read-write') {
        const inputComponentProps = {
          ...componentProps,
          // 'onUpdate:modelValue': updateModelValue,
          // 'onUpdate:otherValue': updateOtherValue,
          'onStreamUpdate:model': streamUpdateModel
        }
        if (unref(cipForm.equipment) === 'mobile') {
          return h(getH5InputComponent(type), inputComponentProps)
        } else {
          return h(getInputComponent(type), inputComponentProps)
        }
      } else {
        // 根据cip-config配置给view的modelValue添加默认值
        if (isInputEmpty(componentProps.modelValue)) {
          if (props.inTable && cipConfig.table.defaultViewValue) {
            componentProps.modelValue = cipConfig.table.defaultViewValue
          }
          if (cipConfig.defaultViewValue) {
            componentProps.modelValue = cipConfig.defaultViewValue
          }
        }
        const viewRender = formItemConfig.value.formViewRender || formItemConfig.value.render
        if (viewRender) return viewRender(componentProps)
        return h(getViewComponent(type), componentProps)
      }
    }

    // FormItem
    const formItem = () => {
      return h(ElFormItem, {
        class: {
          'pos-top': labelPosition.value,
          // 'pos-top--padding': labelPositionTopPadding, 暂时关闭position === top时内容的缩进
          'hide-label': isHideLabel(formItemConfig.value),
          'content--end': formItemConfig.value.contentEnd
        },
        prop: formItemConfig.value.ruleKey || props.fieldKey, // 子表单内的输入框会生成一个ruleKey
        rules: rules.value,
        labelWidth: getLabelWidth(formItemConfig.value),
        inlineMessage: inlineErrorMessage.value
      }, {
        label: formItemLabel,
        error: errorMessageNode,
        default: renderItemInput
      })
    }
    const cipFormStyle = computed(() => {
      if (props.grid) {
        return { gridColumn: `span ${formItemConfig.value.span || 1}`, ...formItemConfig.value.itemStyle }
      } else {
        return (elForm.inline && !props.inTable) ? formItemConfig.value.style : formItemConfig.value.itemStyle
      }
    })
    return () => {
      if (status.value === 'hidden') return null
      if (props.inTable && status.value === 'read') return renderItemInput()
      // 父组件不存在form状态下的渲染方式 目前经为cip-table下直接渲染使用
      if (notInForm.value) return renderItemInput()
      return (
        <div
          style={cipFormStyle.value}
          class={[
            'cip-form-item',
            'el-form-item__wrapper',
            'ep-form-item__wrapper', // 支持namespace ep
            `cip-form-item--${equipment.value}`,
            {
              'cip-form-item--label-position-top': labelPosition.value,
              'cip-form-item--hidden': !childStatus.value || formItemConfig.value.hideItem,
              'cip-form-item--in-table': props.inTable,
              'cip-form-item--disabled': itemDisabled.value
            }
          ]}>
          {formItem()}
        </div>
      )
    }
  }
}
