<template>
  <el-form
    ref="formRef"
    :model="model"
    :rules="rules"
    :label-width="labelWidth"
    :label-position="labelPosition"
    class="form-layout-form"
  >
    <div class="form-items-container" :class="columns > 0 ? `form-layout-${columns}col` : ''">
      <template v-for="(item, index) in normalizedFormItems" :key="item.prop">
        <FormItem
          :item="item"
          :model-value="model[item.prop]"
          @update:model-value="
            async (value) => {
              if (item.onChange && typeof item.onChange === 'function') {
                const result = await item.onChange(value);
                if (result === false) {
                  return;
                }
              }
              model[item.prop] = value;
            }
          "
        >
          <template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
            <slot :name="slotName" v-bind="slotProps" />
          </template>
        </FormItem>
        <span
          v-if="
            columns > 0 &&
            index > 0 &&
            (index + 1) % columns === 0 &&
            index < normalizedFormItems.length - 1
          "
          class="form-item-break"
        />
      </template>
    </div>
  </el-form>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue';
import FormItem from './FormItem.vue';
import type { FormLayoutProps } from '../types/FormLayout.d';

defineOptions({
  name: 'FormLayout',
});

const props = withDefaults(defineProps<FormLayoutProps>(), {
  formItems: () => [],
  rules: () => ({}),
  labelWidth: '120px',
  labelPosition: 'right',
  showLabelColon: true,
  columns: 0,
});

const formRef = ref<InstanceType<typeof import('element-plus').ElForm> | null>(null);

const normalizedFormItems = computed(() =>
  (props.formItems || []).map((item) => ({
    ...item,
    labelSuffix: item.labelSuffix ?? (props.showLabelColon ? '：' : ''),
  }))
);

const validate = (callback) => {
  if (formRef.value) {
    return formRef.value.validate(callback);
  }
};

const validateField = (props, callback) => {
  if (formRef.value) {
    return formRef.value.validateField(props, callback);
  }
};

const resetFields = () => {
  if (formRef.value) {
    formRef.value.resetFields();
  }
};

const clearValidate = (props) => {
  if (formRef.value) {
    formRef.value.clearValidate(props);
  }
};

const scrollToField = (prop) => {
  if (formRef.value) {
    formRef.value.scrollToField(prop);
  }
};

defineExpose({
  formRef,
  validate,
  validateField,
  resetFields,
  clearValidate,
  scrollToField,
});
</script>

<style scoped lang="scss">
.form-layout-form {
  width: 100%;

  .form-items-container {
    display: flex;
    flex-wrap: wrap;
    column-gap: 16px;
    row-gap: 16px;

    .form-item-break {
      flex-basis: 100%;
      width: 0;
      height: 0;
      margin: 0;
      padding: 0;
      border: none;
    }
  }

  :deep(.el-form-item) {
    margin-bottom: 0;
    justify-content: flex-start;
    flex: 0 0 auto;

    .el-form-item__content {
      justify-content: flex-start;
      text-align: left;
    }
  }
}
</style>
