<!--
 * @Description:
 * @Author: ZCY
 * @Date:
-->
<script setup lang="ts">
import { getCurrentInstance, onMounted, ref, useSlots, watch } from 'vue';
import type { FieldChange, FormConfig } from './types';
import UForm from './UForm.vue';

const props = withDefaults(
  defineProps<{
    // steps
    current: number;
    steps: { title: string; description: string }[];
    status?: 'wait' | 'process' | 'finish' | 'error';
    previousText?: string;
    finishedText?: string;
    nextText?: string;
    direction?: string;
    initial?: number;
    labelPlacement?: string;
    responsive?: boolean;
    // form
    value: Record<string, any>;
    config: FormConfig[];
    size?: 'large' | 'small' | 'default';
    labelCol?: {
      span?: number;
      offset?: number;
    };
    // 预览模式
    preview?: boolean;
    layout?: 'horizontal' | 'vertical' | 'inline';
    rules?: object;
  }>(),
  {
    // modal
    current: 0,
    steps: () => [],
    direction: 'horizontal',
    labelPlacement: 'horizontal',
    initial: 0,
    status: 'process',
    previousText: 'previous',
    finishedText: 'done',
    nextText: 'next',
    responsive: true,
    // form
    config: () => [],
    size: 'default',
    layout: 'horizontal',
    value: () => ({})
  }
);
const slots = useSlots();
const ctx = getCurrentInstance();

const itemRefs: any[] = [];
const setItemRef = (el: any) => {
  if (el) {
    itemRefs.push(el);
  }
};

const current = ref(props.current);
const steps = ref(props.steps);

const stepFormConfigs = computed(() => {
  const stepsId: Record<any, any[]> = {};
  props.config.forEach(item => {
    if (item.step !== undefined) {
      if (!stepsId[item.step]) {
        stepsId[item.step] = [item];
      } else {
        stepsId[item.step].push(item);
      }
    }
  });
  const data = Object.entries(stepsId);
  console.log(data);
  return data;
});

const onNext = (e: Event) => {
  const fieldNames: (string | undefined)[] = config.value
    .filter(item => item.step !== undefined && +item.step === current.value)
    .map(i => i.field);
  validator(fieldNames).then(() => {
    if (current.value < steps.value.length - 1) {
      current.value++;
      onStep();
      ctx?.emit('next', e);
    } else {
      ctx?.emit('finished', e);
    }
  });
};

const onPrevious = (e: Event) => {
  current.value--;
  onStep();
  ctx?.emit('previous', e);
};

const onStep = () => {
  // config.value.forEach(item => {
  //   if (item.step !== undefined && +item.step === current.value) {
  //     formRef.value?.updateConfig(item.field, 'isHidden', false);
  //   } else {
  //     return formRef.value?.updateConfig(item.field, 'isHidden', true);
  //   }
  // });
};

const value = ref(props.value);
const config = ref(props.config);

const validator = async (args?: any) => {
  const promises: Promise<boolean>[] = [];
  itemRefs.forEach(item => {
    promises.push(item.formRef?.validate(args));
  });
  try {
    const res = await Promise.all(promises);
    return !res.includes(false);
  } catch (e: any) {
    if (!e?.errorFields?.length) {
      return Promise.resolve(true);
    } else {
      return Promise.reject(e);
    }
  }
};

const resetFields = (args?: any) => {
  itemRefs.forEach(item => {
    item.formRef?.resetFields(args);
  });
};

const onFieldChange = (val: FieldChange) => {
  ctx?.emit(`${val.field}Change`, val);
  ctx?.emit('fieldChange', val);
  ctx?.emit('update:value', val.fields);
};

watch(
  () => props.value,
  () => {
    value.value = props.value;
  },
  {
    deep: true
  }
);
watch(
  () => props.current,
  () => {
    current.value = props.current;
  },
  {
    deep: true
  }
);
watch(
  () => props.config,
  () => {
    config.value = props.config;
  },
  {
    deep: true
  }
);
defineExpose({
  resetFields,
  validate: validator
});

onMounted(onStep);
</script>

<template>
  <div class="u-step-form" :style="{ flexDirection: direction === 'vertical' ? 'row' : 'column' }">
    <a-steps
      v-model:current="current"
      :direction="direction"
      :label-placement="labelPlacement"
      :responsive="responsive"
      :initial="initial"
    >
      <a-step v-for="item in steps" :key="item.title" :title="item.title" :description="item.description" />
    </a-steps>
    <div class="u-step-form-wrapper">
      <div class="u-step-form-content">
        <template
          v-for="stepConfig in stepFormConfigs"
          :key="stepConfig"
        >
          <UForm
            v-if="+stepConfig[0] === current"
            :ref="setItemRef"
            v-model:value="value"
            :config="stepConfig[1]"
            :size="size"
            :layout="layout"
            :rules="rules"
            :preview="preview"
            :label-col="labelCol"
            @field-change="onFieldChange"
          >
            <template v-for="(item, key) in slots" :key="key" #[key]="slotProps">
              <slot :name="key" v-bind="slotProps" />
            </template>
          </UForm>
        </template>
      </div>
      <slot
        name="action"
        :data="value"
        :next="onNext"
        :previous="onPrevious"
        :validate="validator"
        :reset="resetFields"
      >
        <div class="u-step-form-action">
          <a-button v-if="current > initial" @click="onPrevious">
            {{ previousText }}
          </a-button>
          <a-button type="primary" @click="onNext">
            {{
              current < steps.length - 1 ? nextText : finishedText
            }}
          </a-button>
        </div>
      </slot>
    </div>
  </div>
</template>

<style scoped>
.u-step-form{display:flex;flex-direction:column;position:relative}.u-step-form .ant-steps-vertical{width:auto}.u-step-form-action{display:flex;gap:5px;padding:0 12px;width:100%}.u-step-form-content{padding:12px}.u-step-form-wrapper{flex:1;position:relative;width:100%}
</style>
