<template>
  <el-form-item
    ref="formItemRef"
    class="sel-form-item"
    :prop="code"
    :error="errorMessage"
    v-bind="formItemProps"
  >
    <template v-if="label" #label>
      <label class="sel-form-label">
        <span class="required" v-if="props.required||props?.rules&&hasRequired(props?.rules)">*</span>
        {{ label }}
        <template v-if="label && configOptions.labelSuffix">{{ configOptions.labelSuffix }}</template>
      </label>
    </template>
    <template v-if="type === 'slot'">
      <div :id="code"></div>
    </template>
    <template v-else-if="type === 'group'">
      <template v-if="props?.mode === 'array'">
        <s-grid v-bind="mergeGrid">
          <s-grid-item
            v-for="(child, index) in props.renderChildrenOrigin[0]" :key="index"
            v-show="itemVisible(modelData[child.code], child, group - 1)"
            v-bind="child.props?.gridItem||mergeGridItem"
          >
            <form-item
              v-if="itemVisible(modelData[child.code], child, group - 1)"
              :ref="setItemRefs"
              v-model="modelData[child.code]"
              v-bind="child"
              :keys="child.key"
            />
          </s-grid-item>
        </s-grid>
      </template>
      <template v-else>
        <s-grid v-bind="mergeGrid">
          <s-grid-item
            v-for="group in groupNumber"
            :key="group"
            v-bind="mergeGridItem"
            class="sel-form-group"
            :class="{
              'title-top': props?.titlePosition === 'top',
              'title-left': props?.titlePosition === 'left',
            }"
          >
            <div v-if="props?.title" class="sel-form-group-head">
              <span class="group-title-text">
                <template v-if="typeof props?.title === 'function'">{{ props?.title(group) }}</template>
                <template v-else>{{ props?.title }}</template>
              </span>
              <span
                class="sel-control-button add-button"
                v-if="props?.add && props?.button === 'in-title'"
                @click="addGroupItem"
                v-html="props?.addButtonText ||'+'"
              ></span>
              <span
                class="sel-control-button remove-button"
                v-if="props?.add && props?.button === 'in-title'"
                @click="removeGroupItem(group)"
                v-html="props?.removeButtonText ||'-'"
              ></span>
            </div>
            <span class="sel-control-button remove-button"
                  v-if="props?.add && props?.button === 'prefix'"
                  v-html="props?.addButtonText ||'+'"
                  @click="removeGroupItem(group)">
            </span>
            <span class="sel-control-button remove-button"
                  v-if="props?.add && props?.button === 'prefix'"
                  v-html="props?.removeButtonText ||'-'"
                  @click="removeGroupItem(group)">
            </span>
            <s-grid v-bind="mergeGrid">
              <s-grid-item
                v-for="(child, index) in props.renderChildrenOrigin[group - 1]"
                :key="index"
                v-show="itemVisible(modelData[child.code], child,index,group-1)"
                v-bind="child.props?.gridItem || mergeGridItem"
              >
                <form-item
                  v-if="itemVisible(modelData[child.code], child,index,group-1)"
                  :ref="setItemRefs"
                  v-model="modelData[child.code]"
                  v-bind="child"
                  :keys="child.key.replace('[i]', `[${group - 1}]`)"
                />
              </s-grid-item>
            </s-grid>
            <span
              class="sel-control-button add-button"
              v-if="props?.add && (props?.button === 'append' || !props?.button)"
              @click="addGroupItem"
              v-html="props?.addButtonText||'+'"
            >
            </span>
            <span
              class="sel-control-button remove-button"
              v-if="props?.add && (props?.button === 'append' || !props?.button)"
              v-html="props?.removeButtonText||'-'"
              @click="removeGroupItem(group)"
            ></span>
          </s-grid-item>
        </s-grid>
      </template>
    </template>
    <template v-else>
      <s-form-content
        :prefix="mergePrefix"
        :code="code"
        :keys="keys"
        :type="type"
        :options="options"
        :props="itemProps.props"
        :component="component"
        :errorMessage="errorMessage"
        @validateValue="validateValue"
      />
    </template>
  </el-form-item>
</template>
<script lang="ts" setup>
import { inject, ref, Ref, computed, getCurrentInstance, onMounted, provide } from 'vue'
import { cloneDeep, set } from 'lodash-es'
import { isFunction, randomCode, removeObjWithArr } from 'utils'
import SFormContent from 'pkg/components/Form/src/FormContent.vue'
import Schema from 'async-validator'
import { Op, FI } from 'pkg/components/Form/form.type'
import { useFormItemProps, useFormItemRefs, useMergeStyle } from '../../Form/hooks'

interface Props {
  value: any
  label: string
  prefix?: string
  code: string
  keys: Array<string> | string
  type: string
  options?: Array<Op>
  props?: any
  children?: Array<FI>
  style?: any
  component?: any
  show: any
}

const itemProps = withDefaults(defineProps<Props>(), {
  label: '',
  prefix: '',
  code: '',
  keys: '',
  type: '',
  options: () => ([]),
  props: () => ({}),
  style: () => ({}),
  children: () => ([])
})

const emits = defineEmits<{
  (e: 'change', value: any): void
  (e: 'update:value', value: any): void
}>()
const mergeGridItem = computed(() => {
  return Object.assign(configOptions?.gridItem, itemProps.props?.gridItem)
})

const mergeGrid = computed(() => {
  return Object.assign(configOptions?.grid, itemProps.props?.grid)
})
const formItemRef = ref()
const errorMessage: Ref<string> = ref('')
const groupNumber = computed(() => {
  return itemProps.props?.renderChildrenOrigin.length || 0
})
const useGroupChild: any = ref([])

const modelData: any = inject('modelData')
const setFormData: any = inject('setFormData')
const getFormData: any = inject('getFormData')
const configOptions: any = inject('options')
const itemVisible: any = inject('itemVisible')
const globalPrefix: any = inject('globalPrefix')
const globalProps: any = inject('globalProps')
const mergePrefix = computed(() => itemProps.prefix ?? globalPrefix.value)
const formItemProps = useFormItemProps(globalProps, itemProps)

const { mergeStyle, styled } = useMergeStyle(configOptions, itemProps.style)

onMounted(() => {
  styled.value(formItemRef.value.$el, mergeStyle.value)
})

/*
 * 获取循环的ref
 * */
const { formItemRefs, setItemRefs } = useFormItemRefs()

function hasRequired (rules) {
  return !!rules.find(item => item.required === true)
}

/*
 * 根据规则验证数值
 * */
function validateValue (val, trigger) {
  const allRules = itemProps.props?.rules
  const rules = trigger == 'all' ? allRules : allRules.filter(item => item.trigger === trigger)
  const useRules = cloneDeep(rules)
  if (useRules) {
    return new Promise(resolve => {
      let v = val
      const isNumberStr = new RegExp(/^[\d|\.]*$/)
      if (typeof v === 'string' && v.length > 0 && isNumberStr.test(v)) {
        useRules.forEach(item => {
          if (!item.type) item.type = 'number'
        })
        v = Number(v)
      }
      if (typeof v === 'number') {
        useRules.forEach(item => {
          if (!item.type) item.type = 'number'
        })
        v = Number(v)
      }

      const validator = new Schema({
        [itemProps.code]: useRules
      })
      validator.validate({ [itemProps.code]: v }, (errors: any, fields) => {
        if (errors) {
          errorMessage.value = errors[0].message
          resolve(false)
        } else {
          errorMessage.value = ''
          resolve(true)
        }
      })
    })
  } else {
    return new Promise(resolve => {
      errorMessage.value = ''
      resolve(true)
    })
  }
}
const getItem: any = inject('getItem')
const getItemValue: any = inject('getItemValue')

function visible () {
  let visible = true
  if (isFunction(itemProps.show)) {
    const params = {
      getItem,
      getItemValue,
      val: itemProps.value,
      index: itemProps.index,
      item: getItem({ code: itemProps.code })
    }
    visible = itemProps.show(params)
  }
  return visible
}

defineExpose({
  validateValue,
  visible,
  code: itemProps.code,
  childrenRefs: formItemRefs
})

/*
 * 新增分组
 * */
function addGroupItem () {
  const index = groupNumber.value
  let children: any[] = []
  if (itemProps.props?.mode === 'default') {
    children = cloneDeep(itemProps.children)
  } else {
    children = itemProps.props.renderChildren(index)
  }
  let obj = {}
  children.forEach((item: any) => {
    if (!item.code) {
      item.code = 'ele' + randomCode(18)
    }
    if (item.initValue) set(obj, item.key, item.initValue)
    if (item.initValue) set(modelData.value, item.code, item.initValue)
    item.key = `${ itemProps.keys }[${ index }].${ item.key }`
  })
  itemProps.props?.renderChildrenOrigin.push(children)
  const value = getFormData(itemProps.keys)
  value.push(obj)
  emits('update:value', value)
  setFormData(value, itemProps.keys)
}

/*
 * 删除分组
 * */
function removeGroupItem (index: number) {
  itemProps.props?.renderChildrenOrigin.map((item, i) => {
    if (i > index - 1) {
      item.forEach(child => {
        const result = /\[\d\]/.exec(child.key)?.[0]
        child.key = child.key.replace(result, `[${ i - 1 }]`)
      })
    }
  })
  removeObjWithArr(itemProps.props?.renderChildrenOrigin, itemProps.props?.renderChildrenOrigin[index - 1])
  removeGroupValue(itemProps.value, index)
}

if (itemProps.props?.renderChildrenOrigin) {
  provide('addGroupItem', addGroupItem)
  provide('removeGroupItem', removeGroupItem)
}

function removeGroupValue (value: any[], index: number) {
  value.splice(index - 1, 1)
  setFormData(value, itemProps.keys)
}
</script>
<style lang="scss">
.sel-form-group {
  border: 1px solid #ddd;
  padding: 20px;

  &.title-top {
    .sel-form-group-head {
      width: 100%;
    }

    .sel-grid {
      width: 100%;
    }
  }

  .sel-control-button {
    display: inline-block;
    border-radius: 2px;
    width: 18px;
    height: 18px;
    color: #666;
    border: none;
    text-align: center;
    line-height: 18px;
    padding: 0;
    margin: 2px;
    cursor: pointer;
    box-shadow: 0 0 1px #333;

    &:hover {
      background-color: #dddddd;
    }
  }
}
</style>
