<template>
<div class="honjo-form-render">
<el-form :model="form" ref="fm" v-bind="options" :disabled="false">
  <template v-for="row in controls">
    <form-control :key="row.key" :def="row" v-if="exists(row)"></form-control>
  </template>
</el-form>
</div>
</template>

<script lang="ts">

import { Vue, Component, Prop, Ref, Provide } from 'vue-property-decorator'
import { FormDef, FormOptions, ControlDef } from './type'
import FormControl from './form-control/index.vue'

@Component({
  components: { FormControl }
})
export default class HonjoFormRender extends Vue {
  @Prop() def!: FormDef

  @Prop({ default: () => ({}) }) form!: Record<string | number, any>

  @Ref() fm!: any

  @Provide() getForm () {
    return this.form
  }

  @Provide() getDisabled () {
    return !!this.options?.disabled
  }

  @Provide() getFormRender () {
    return this
  }

  @Provide() exists (row: ControlDef, rowForm?: Record<string, any>): boolean {
    const vm = this as any
    if (!row.dependOn) return true
    if (typeof row.dependOn === 'string') {
      // eslint-disable-next-line no-new-func
      const fn = new Function('form', 'rowForm', `return ${row.dependOn}`)
      const has = fn(this.form, rowForm) as any
      if (Object.prototype.toString.call(has) === '[object Object]') {
        if (has.notDel !== true) {
          handleRemove(has)
        }
        return has.show
      } else {
        handleRemove(has)
        return has
      }
    } else {
      const has = row.dependOn({ form: this.form, rowForm }) as any
      if (Object.prototype.toString.call(has) === '[object Object]') {
        if (has.notDel !== true) {
          handleRemove(has)
        }
        return has.show
      } else {
        handleRemove(has)
        return has
      }
    }

    function handleRemove (has: boolean) {
      if (has) return
      const r = row as any
      if (rowForm && r.model) delete rowForm[r.model]
      else if (vm.form && r.model) delete vm.form[r.model]
    }
  }

  get options (): FormOptions {
    return Object.assign(new FormOptions(), this.def?.options || {})
  }

  get controls (): ControlDef[] {
    return this.def?.controls || []
  }

  // public
  public validate (): Promise<boolean> {
    return this.fm.validate()
  }

  /**
   * 清除校验
   */
  public clearValidate () {
    this.fm.clearValidate()
  }

  public reset () {
    this.fm.resetFields()
  }

  public submit (validate: boolean): Promise<Record<string | number, any>> {
    if (validate === false) {
      return Promise.resolve(JSON.parse(JSON.stringify(this.form)))
    } else {
      return this.validate().then(valid => {
        return valid ? Promise.resolve(JSON.parse(JSON.stringify(this.form))) : Promise.reject(new Error('验证失败'))
      })
    }
  }
}
</script>

<style lang="scss">
@import "./style/index.scss";

</style>
