
<template>
  <Col 
    v-if="isShow"
    :class="[
      'dynamic-form-item-wrapper',
      finalOptions?.nestObjectMargin !== false && item.nestObjectMargin !== false ? 'nest-with-margin' : '',
    ]"
    :data-dynamic-form-item="item.name"
    :data-dynamic-form-item-type="item.type"
    v-bind="{
      ...colProps,
      ...(item.colProps as {})
    }"
  >
    <!--对象组-->
    <DynamicFormCheckEmpty 
      v-if="item.type === 'object'" 
      :model="model"
      :modelWithDefault="finalModel"
      :suppressEmptyError="editmode || finalOptions?.suppressEmptyError || item.suppressEmptyError"
      :name="name"
      checkType="object"
    >
      <!--标题-->
      <DynamicFormItemNormal 
        v-if="item.label"
        :item="item"
        :parent="parent"
        :name="''"
        :rawModel="rawModel"
        :model="null"
        :noLabel="true"
        :disabled="disabled || evaluateCallback(item.disabled)"
      >
        <template #insertion>
          <span v-if="item.label" class="dynamic-form-object-title">{{ evaluateCallback(item.label) }}</span>
        </template>
      </DynamicFormItemNormal>
      <!--循环子条目-->
      <DynamicFormItemContainerFuckMp 
        v-for="(child, k) in item.children"
        :key="k"
        :item="child"
        :name="name+'.'+child.name"
        :rawModel="rawModel"
        :model="(finalModel as IDynamicFormObject)[child.name]"
        :parent="item"
        :parentModel="finalModel"
        :parentName="name"
        :isFirst="k === 0"
        :isLast="k === (item.children?.length || 0) - 1"
        @update:model="(v: unknown) => (model as IDynamicFormObject)[child.name] = v"
        :disabled="disabled || evaluateCallback(item.disabled)"
      />
    </DynamicFormCheckEmpty>
    <!--对象组-->
    <DynamicFormCheckEmpty 
      v-else-if="item.type === 'object-group'" 
      :model="model"
      :modelWithDefault="finalModel"
      :suppressEmptyError="editmode || finalOptions?.suppressEmptyError || item.suppressEmptyError"
      :name="name"
      checkType="object"
    >
      <FormGroup :title="evaluateCallback(item.label)" v-bind="(item.additionalProps as object)">
        <Row v-bind="item.rowProps">
          <!--循环子条目-->
          <DynamicFormItemContainerFuckMp 
            v-for="(child, k) in item.children" 
            :key="k"
            :item="child"
            :colProps="{ ...item.childrenColProps, ...child.colProps }"
            :name="name+'.'+child.name"
            :rawModel="rawModel"
            :model="((finalModel as IDynamicFormObject)[child.name] as IDynamicFormObject)"
            :parent="item"
            :parentModel="finalModel"
            :parentName="name"
            :isFirst="k === 0"
            :isLast="k === (item.children?.length || 0) - 1"
            @update:model="(v: unknown) => (model as IDynamicFormObject)[child.name] = v"
            :disabled="disabled || evaluateCallback(item.disabled)"
          />
        </Row>
      </FormGroup>
    </DynamicFormCheckEmpty>
    <!--扁平组-->
    <FormGroup v-else-if="item.type === 'flat-group'" :title="evaluateCallback(item.label)" v-bind="(item.additionalProps as object)">
      <Row v-bind="item.rowProps">
        <!--循环子条目-->
        <DynamicFormItemContainerFuckMp 
          v-for="(child, k) in item.children" 
          :colProps="{ ...item.childrenColProps, ...child.colProps }"
          :key="k"
          :item="child"
          :name="parentName ? `${parentName}.${child.name}` : child.name"
          :rawModel="rawModel"
          :model="((parentModel as IDynamicFormObject)[child.name])"
          :parent="item"
          :parentModel="parentModel"
          :parentName="parentName"
          :isFirst="k === 0"
          :isLast="k === (item.children?.length || 0) - 1"
          @update:model="(v: unknown) => (parentModel as IDynamicFormObject)[child.name] = v"
          :disabled="disabled || evaluateCallback(item.disabled)"
        >
          <template #formCeil="values">
            <slot name="formCeil" :data="values.data" />
          </template>
        </DynamicFormItemContainerFuckMp>
      </Row>
    </FormGroup>
    <!--扁平普通-->
    <DynamicFormItemNormal v-else-if="item.type === 'flat-simple'" 
      :item="item"
      :parent="parent"
      :name="name"
      :disabled="disabled || evaluateCallback(item.disabled)"
      :model="(finalModel as IDynamicFormObject)"
      :rawModel="rawModel"
      :parentModel="parentModel"
      :parentName="parentName"
    >
      <template #insertion>
        <Row v-bind="item.rowProps">
          <!--循环子条目-->
          <DynamicFormItemContainerFuckMp 
            v-for="(child, k) in item.children" 
            :key="k"
            :item="child"
            :colProps="{ ...item.childrenColProps, ...child.colProps }"
            :name="parentName ? `${parentName}.${child.name}` : child.name"
            :rawModel="rawModel"
            :model="((parentModel as IDynamicFormObject)[child.name])"
            :parent="item"
            :parentModel="parentModel"
            :parentName="parentName"
            :isFirst="k === 0"
            :isLast="k === (item.children?.length || 0) - 1"
            @update:model="(v: unknown) => (parentModel as IDynamicFormObject)[child.name] = v"
            :disabled="disabled || evaluateCallback(item.disabled)"
          >
            <template #formCeil="values">
              <slot name="formCeil" :data="values.data" />
            </template>
          </DynamicFormItemContainerFuckMp>
        </Row>
      </template>
    </DynamicFormItemNormal>
    <!--数组变量组-->
    <DynamicFormCheckEmpty 
      v-else-if="item.type === 'array-single'"
      :model="model"
      :modelWithDefault="finalModel"
      :suppressEmptyError="editmode || finalOptions?.suppressEmptyError || item.suppressEmptyError"
      :name="name"
      checkType="array"
    >
      <DynamicFormItemNormal 
        :item="item"
        :name="name"
        :disabled="disabled || evaluateCallback(item.disabled)"
        :model="(finalModel as IDynamicFormObject)"
        :rawModel="rawModel"
        :parentModel="parentModel"
        :parent="parent"
        :parentName="name"
      >
        <template #insertion>
          <FormArrayGroup
            :model="(finalModel as unknown as unknown[])"
            :item="item"
            :parent="parent"
            :name="name"
            :rawModel="rawModel"
            :isObject="false"
            :addCallback="item.newChildrenObject"
            :deleteCallback="item.deleteChildrenCallback"
            v-bind="(item.additionalProps as IDynamicFormObject)"
          >
            <template #addButton="props">
              <slot name="arrayButtonAdd" :onClick="props.onClick" />
            </template>
            <template #itemButton="props">
              <slot name="arrayButtons" 
                :onDeleteClick="props.onDeleteClick"
                :onUpClick="props.onUpClick"
                :onDownClick="props.onDownClick"
              />
            </template>
            <template #child="{ item, pitem, kname, model: child, onUpdateValue, isFirst, isLast }">
              <DynamicFormItemContainerFuckMp
                :item="item"
                :name="kname"
                :rawModel="rawModel"
                :model="child"
                :parent="pitem"
                :parentModel="model"
                :parentName="name"
                :disabled="disabled || evaluateCallback(item.disabled)"
                :isFirst="isFirst"
                :isLast="isLast"
                @update:model="(v: unknown) => onUpdateValue(v)"
              />
            </template>
          </FormArrayGroup>
        </template>
      </DynamicFormItemNormal>
    </DynamicFormCheckEmpty>
    <!--数组对象组-->
    <DynamicFormCheckEmpty 
      v-else-if="item.type === 'array-object'"
      :model="model"
      :modelWithDefault="finalModel"
      :suppressEmptyError="editmode || finalOptions?.suppressEmptyError || item.suppressEmptyError"
      :name="name"
      checkType="array"
    >
      <DynamicFormItemNormal  
        :item="item"
        :parent="parent"
        :name="name"
        :disabled="disabled || evaluateCallback(item.disabled)"
        :model="finalModel"
        :rawModel="rawModel"
        :parentModel="parentModel"
        :parentName="parentName"
        :isFirst="isFirst"
        :isLast="isLast"
      >
        <template #insertion>
          <FormArrayGroup
            :model="(finalModel as unknown as unknown[])"
            :item="item"
            :parent="parent"
            :name="name"
            :rawModel="rawModel"
            :isObject="true"
            :addCallback="item.newChildrenObject"
            :deleteCallback="item.deleteChildrenCallback"
            v-bind="(item.additionalProps as IDynamicFormObject)"
          >
            <template #addButton="props">
              <slot name="arrayButtonAdd" :onClick="props.onClick" />
            </template>
            <template #itemButton="props">
              <slot name="arrayButtons"
                :onDeleteClick="props.onDeleteClick"
                :onUpClick="props.onUpClick"
                :onDownClick="props.onDownClick"
              />
            </template>
            <template #child="{ item, pitem, kname, model: child, onUpdateValue, isFirst, isLast }">
              <DynamicFormItemContainerFuckMp
                :item="item"
                :name="kname"
                :rawModel="rawModel"
                :model="child"
                :parent="pitem"
                :parentModel="model"
                :parentName="name"
                :isFirst="isFirst"
                :isLast="isLast"
                :disabled="disabled || evaluateCallback(item.disabled)"
                @update:model="(v: unknown) => onUpdateValue(v)"
              />
            </template>
          </FormArrayGroup>
        </template>
      </DynamicFormItemNormal>
    </DynamicFormCheckEmpty>
    <!--正常条目-->
    <DynamicFormItemNormal
      v-else
      :item="item"
      :parent="parent"
      :name="name"
      :disabled="disabled || evaluateCallback(item.disabled)"
      :rawModel="rawModel"
      :parentModel="parentModel"
      :model="finalModel"
      :isFirst="isFirst"
      :isLast="isLast"
      @update:model="(v: unknown) => $emit('update:model', v)"
    >
      <template #formCeil="values">
        <slot name="formCeil" :data="values.data" />
      </template>
    </DynamicFormItemNormal>
  </Col>
</template>

<script lang="ts" setup>
import { inject, type Ref, toRefs, computed, provide } from 'vue';
import type { Rules } from 'async-validator';
import type { IDynamicFormItem, IDynamicFormItemCallback, IDynamicFormObject, IDynamicFormOptions, IDynamicFormRef, IEvaluateCallback } from '..';
import DynamicFormItemNormal, { type FormCeilProps } from '../DynamicFormControl.vue';
import FormGroup from '../group/FormGroup.vue';
import FormArrayGroup from '../group/FormArrayGroup.vue';;
import Col, { type ColProps } from '@/components/layout/grid/Col.vue';
import Row from '@/components/layout/grid/Row.vue';
import DynamicFormCheckEmpty from './DynamicFormCheckEmpty.vue';
import DynamicFormItemContainerFuckMp from './DynamicFormItemContainerFuckMp.vue';

/**
 * 动态表单条目包装组件，处理基础类型分支、数据传入、回调处理、事件传递。
 */

export interface DynamicFormItemContainerProps {
  item: IDynamicFormItem;
  name: string;
  disabled?: boolean;
  model?: any;
  rawModel?: IDynamicFormObject;
  parent?: IDynamicFormItem;
  parentModel?: unknown;
  parentName?: string;
  colProps?: ColProps;
  isFirst?: boolean;
  isLast: boolean;
 }

const props = withDefaults(defineProps<DynamicFormItemContainerProps>(), {
  isFirst: false,
  isLast: false,
});
const containerTypes = ['object', 'object-group', 'array-single','group-array','flat-simple','flat-group'];
const isContainer = computed(() => props.item.type && containerTypes.includes(props.item.type));

defineEmits([	'update:model' ]);
defineSlots<{
  formCeil(props: {
    data: FormCeilProps;
  }): any,
  arrayButtonAdd(props: {
    onClick: () => void;
  }): any,
  arrayButtons(props: {
    onDeleteClick: () => void;
    onUpClick: () => void;
    onDownClick: () => void;
  }): any,
}>()

const propsP = toRefs(props);
const finalOptions = inject<Ref<IDynamicFormOptions>>('finalOptions'); 
const globalParams = inject<Ref<IDynamicFormObject>>('globalParams');
const formRef = inject<IDynamicFormRef>('formRef');
const editmode = inject('editmode', false);
const formName = inject('formName', '')

//判断是否显示当前条目
const isShow = computed(() => props.item.show === undefined || evaluateCallback(props.item.show));

//处理默认值
const finalModel = computed(() => {
  const val = props.model
  if (val !== undefined && val !== null)
    return props.model;
  if (props.item.defaultValue) {
    if (typeof props.item.defaultValue === 'function')
      return props.item.defaultValue();
    return props.item.defaultValue;
  }
  return null;
});

//处理回调函数
function evaluateCallback<T>(val: T|IDynamicFormItemCallback<T>) {
  if (typeof val === 'object' && typeof (val as IDynamicFormItemCallback<T>).callback === 'function')
    return (val as IDynamicFormItemCallback<T>).callback(
      finalModel.value, 
      propsP.rawModel.value,
      propsP.parentModel?.value,
      {
        item: propsP.item.value,
        form: formRef!,
        formGlobalParams: globalParams?.value || {},
        formRules: (finalOptions?.value.formRules ?? {}) as Record<string, Rules>,
        isFirst: propsP.isFirst.value,
        isLast: propsP.isLast.value,
      }
    );
  return val as T;
}

provide<IEvaluateCallback>('evaluateCallback', evaluateCallback);

defineOptions({
  name: 'DynamicFormItemContainer',
  options: {
    virtualHost: true,
    styleIsolation: 'shared',
  }
})
</script>

<style lang="scss">
.dynamic-form-item-wrapper {
  position: relative;
}
</style>