<template>
  <div class="fm-form-item" :data-id="widget.model" v-if="widget.key">
    <el-form-item 
      v-if="widget.type != 'divider' && widget.type != 'alert' && elementDisplay"
      :prop="fieldNode ? fieldNode + '.' + widget.model : widget.model"
      :rules="rules[ruleProp]"
      :class="{
        [widget.options && widget.options.customClass]: widget.options && widget.options.customClass?true: false,
        'no-label-form-item': widget.options.isLabelWidth && widget.options.labelWidth == 0,
        'fm-label-wrap': widget.options.labelWrap
      }"
      :label="(widget.options.hideLabel || (isTable && !isMobile)) ? '' : widget.name"
      :label-width="widget.options.hideLabel ? '0px' : (widget.options.isLabelWidth ? widget.options.labelWidth + 'px' : '')"
      :key="widget.key"
      :required="widget.options.required"
      ref="generateFormItem"
    >
      <div v-if="widget.options.tip" class="fm-item-tooltip" v-html="widget.options.tip.replace(/\n/g, '<br/>')"></div>
      <generate-element-item 
        :blanks="blanks"
        :is-table="isTable" 
        :table-name="tableName"
        :widget="widget" 
        :models="dataModels"
        :remote="remote"
        :edit="edit"
        :remote-option="remoteOption"
        :key="widget.key"
        :rules="rules"
        v-model="dataModel"
        :platform="platform"
        :preview="preview"
        :data-source-value="dataSourceValue"
        :event-function="eventFunction"
        :print-read="printRead"
        :container-key="containerKey"
        :is-subform="isSubform"
        :row-index="rowIndex"
        :sub-name="subName"
        :is-dialog="isDialog"
        :dialog-name="dialogName"
        ref="generateElementItem"
        :is-group="isGroup"
        :group="group"
        :field-node="fieldNode ? fieldNode + '.' + widget.model : widget.model"
      >
        
        <template v-slot:[blank.name]="scope" v-for="blank in blanks">
          <slot :name="blank.name" :model="scope.model"></slot>
        </template>
      </generate-element-item>
    </el-form-item>

    <el-form-item v-if="widget.type == 'divider' && elementDisplay" label-width="0">
      <el-divider 
        :content-position="widget.options.contentPosition"
        v-bind="widget.options.customProps"
        :ref="'fm-'+widget.model"
      >
        {{widget.name}}
      </el-divider>
    </el-form-item>

    <el-form-item v-if="widget.type == 'alert' && elementDisplay" label-width="0">
      <el-alert 
        :title="widget.options.title"
        :type="widget.options.type"
        :description="widget.options.description"
        :closable="widget.options.closable"
        :center="widget.options.center"
        :show-icon="widget.options.showIcon"
        :effect="widget.options.effect"
        :style="{width: widget.options.width}"
        v-bind="widget.options.customProps"
        :ref="'fm-'+widget.model"
      ></el-alert>
    </el-form-item>
  </div>
  
</template>

<script>
import GenerateElementItem from './GenerateElementItem'
import _ from 'lodash'
import {executeExpression, isExpression, extractExpression} from '../util/expression'

export default {
  components: {
    GenerateElementItem
  },
  props: ['widget', 'models', 'rules', 'remote', 'blanks', 'display', 'edit', 
    'remoteOption', 'platform', 'preview', 'containerKey', 'dataSourceValue', 'eventFunction', 
    'printRead', 'isSubform', 'rowIndex', 'subName', 'subHideFields', 'subDisabledFields', 
    'isDialog', 'dialogName', 'group', 'fieldNode', 'isGroup', 'isTable', 'isMobile', 'tableName'],
  data () {
    return {
      dataModel: Object.keys(this.models).includes(this.widget.model) ? this.models[this.widget.model] : _.cloneDeep(this.widget.options.defaultValue),
      dataModels: this.models
    }
  },
  computed: {
    ruleProp () {
      let currentProp = this.widget.model

      if (this.group) {
        currentProp = this.group + '.' + currentProp
      }

      return currentProp
    },
    currentOptions () {
      if (this.isTable || this.isSubform) {
        return {
          value: this.dataModel,
          fieldNode: this.fieldNode ? this.fieldNode + '.' + this.widget.model : this.widget.model,
          currentRef: this.$refs['generateElementItem']?.$refs[`fm-${this.widget.model}`],
          rowIndex: this.rowIndex,
          row: _.cloneDeep(this.models),
          field: this.widget.model,
          group: this.group
        }
      } else {
        return {
          value: this.dataModel,
          fieldNode: this.fieldNode ? this.fieldNode + '.' + this.widget.model : this.widget.model,
          currentRef: this.$refs['generateElementItem']?.$refs[`fm-${this.widget.model}`],
          field: this.widget.model,
          group: this.group
        }
      }
    },
    elementDisplay () {
      let curFullField = this.fieldNode ? this.fieldNode + '.' + this.widget.model : this.widget.model
      let curField = this.group ? this.group + '.' + this.widget.model : this.widget.model

      if (this.dynamicHideFields[curFullField] != undefined) {
        return !this.dynamicHideFields[curFullField]
      }

      if (this.dynamicHideFields[curField] != undefined) {
        return !this.dynamicHideFields[curField]
      }

      if (typeof this.widget.options.hidden === 'boolean') {
        return !this.widget.options.hidden
      } else {
        if (isExpression(this.widget.options.hidden)) {
          return  !executeExpression(extractExpression(this.widget.options.hidden), this.currentOptions, this.formContext)
        }
      }

      return true
    },
    groupNode () {
      return this.group ? this.group + '.' + this.widget.model : this.widget.model
    },
    elementNode () {
      return this.fieldNode ? this.fieldNode + '.' + this.widget.model : this.widget.model
    }
  },
  inject: {
    setSubformData: {
      default: () => {}
    },
    setDialogData: {
      default: () => {}
    },
    setGroupData: {
      default: () => {}
    },
    setTableData: {
      default: () => {}
    },
    onChange: {
      default: () => {}
    },
    dynamicValueData: {
      default: []
    },
    formContext: {
      default: {}
    },
    dynamicHideFields: {
      default: {}
    },
    generateFormItemContext: {
      default: () => {}
    },
    deleteFormItemContext: {
      default: () => {}
    },
    sendRequest: {
      default: () => {}
    }
  },
  created () {
    this.refreshDynamicValue()
  },
  mounted () {
    this.generateFormItemContext(this.elementNode, this)
  },
  beforeDestroy () {
    this.deleteFormItemContext(this.elementNode)
  },
  methods: {
    refreshDynamicValue (args) {
      return new Promise((resolve, reject) => {
        if (this.widget.options.isDynamicValue 
          && this.widget.options.dynamicValueType == 'datasource'
          && this.widget.options.dynamicValueDataSource) {

          let key = this.group ? this.group + '.' + this.widget.model + '.' + this.widget.options.dynamicValueDataSource
            : this.widget.model + '.' + this.widget.options.dynamicValueDataSource

          let curArgs = {...this.widget.options.dynamicValueArgs}

          for (let key in curArgs) {
            if (isExpression(curArgs[key])) {
              curArgs[key] = executeExpression(extractExpression(curArgs[key]), this.currentOptions, this.formContext)
            }
          }

          if (args && typeof args === 'object') {
            curArgs = {...curArgs, ...args}
          }

          let _data = this.dynamicValueData.find(item => item.key === key && _.isEqual(item.args, curArgs))

          if (_data) {

            if (this.widget.options.dynamicValueStruct) {
              try {
                this.dataModel = (new Function('data', `return data.${this.widget.options.dynamicValueStruct}`))(_data.value)
                resolve(this.dataModel)
              } catch (e) {reject(e)}
            } else {
              this.dataModel = _data.value
              resolve(this.dataModel)
            }
          } else {
            this.sendRequest(this.widget.options.dynamicValueDataSource, curArgs).then(resData => {
              if (this.widget.options.dynamicValueStruct) {
                try{
                  this.dataModel = (new Function('data', `return data.${this.widget.options.dynamicValueStruct}`))(resData)
                  resolve(this.dataModel)
                } catch (e) {reject(e)}
              } else {
                this.dataModel = resData
                resolve(this.dataModel)
              }
            })
          }
        }
        if (this.widget.options.isDynamicValue
        && this.widget.options.dynamicValueType == 'fx'
        && this.widget.options.dynamicValueFx) {
          
          let value = executeExpression(this.widget.options.dynamicValueFx, this.currentOptions, this.formContext)

          if (value !== null) {
            this.$nextTick(() => {
              this.dataModel = value
            })
          }

          resolve(value)
        }
      })
    },
  },
  watch: {
    dataModel: {
      deep: true,
      handler (val, oldValue) {
        if (JSON.stringify(val) == JSON.stringify(oldValue)) {
          return false
        }

        if (this.isTable) {
          this.setTableData(val, this.rowIndex, this.widget.model)
        } else if (this.isSubform) {
          this.setSubformData(val, this.rowIndex, this.widget.model)
        } else if (this.isDialog) {
          this.setDialogData(val, this.widget.model)
        } else if (this.isGroup) {
          this.setGroupData(val, this.widget.model)
        } else {
          this.onChange(val, this.widget.model)
        }

        // 执行 onChange 方法
        this.$nextTick(() => {
          this.eventFunction['onFormChange'] && this.eventFunction['onFormChange'](this.currentOptions)

          if (this.widget.events && this.widget.events.onChange) {
            let funcKey = this.widget.events.onChange
            
            this.eventFunction[funcKey](this.currentOptions)
          }
        })
      }
    },
    models: {
      deep: true,
      handler (val) {
        this.dataModels = val
        this.dataModel = Object.keys(val).includes(this.widget.model) ? val[this.widget.model] : _.cloneDeep(this.widget.options.defaultValue)
      }
    }
  }
}
</script>
