<template>
  <div class="render-form" data-weiling-mobile-ui-bc-render-form>
    <div
      v-for="item in filterList"
      :class="formItemClass"
      :key="item.prop"
      :style="formItemStyle(item)"
      v-show="item.visible !== false"
    >
      <div class="label" v-if="item.labelVisible">
        <template v-if="item.labelSlot">
          <slot :name="item.labelSlot"></slot>
        </template>
        <template v-else>
          {{ item.label }}
        </template>
      </div>
      <div :class="contentClass">
        <Suspense v-if="!item.slot">
          <component
            :is="componentName[item.type]"
            v-bind="{ ...item }"
            :labelPosition="labelPosition"
            v-on="item['event'] || {}"
            v-model="formData[item.prop]"
            v-if="!item.slot"
          />
        </Suspense>
        <slot :name="item.slot" />
      </div>
    </div>
  </div>
</template>

<script lang="ts">
export default {
  name: "BCRenderForm",
};
</script>

<script lang="ts" setup>
import { ref, computed, markRaw, defineAsyncComponent, watchEffect } from "vue";

const componentDict = {
  input: markRaw(
    defineAsyncComponent(() => import("./components/RfInput/index.vue")),
  ),
  select: markRaw(
    defineAsyncComponent(() => import("./components/RfSelect/index.vue")),
  ),
  date: markRaw(
    defineAsyncComponent(() => import("./components/RfDateSelect/index.vue")),
  ),
  content: markRaw(
    defineAsyncComponent(() => import("./components/RfContent/index.vue")),
  ),
  textarea: markRaw(
    defineAsyncComponent(() => import("./components/RfTextArea/index.vue")),
  ),
  picSelect: markRaw(
    defineAsyncComponent(() => import("./components/RfPicSelect/index.vue")),
  ),
  mulSelect: markRaw(
    defineAsyncComponent(() => import("./components/RfMulSelect/index.vue")),
  ),
  colorSelect: markRaw(
    defineAsyncComponent(() => import("./components/RfColorSelect/index.vue")),
  ),
  selectInput: markRaw(
    defineAsyncComponent(() => import("./components/RfSelectInput/index.vue")),
  ),
};

type TComponentType = typeof componentDict;

type TLabelPosition = "top" | "left";

type Props = {
  list: any;
  data: any;
  space?: string;
  needBorder?: boolean;
  labelPosition?: TLabelPosition;
  backgroundColor?: string;
};
const props = withDefaults(defineProps<Props>(), {
  list: null,
  data: null,
  space: "0px",
  needBorder: true,
  labelPosition: "left",
  backgroundColor: "#fff",
});

const formData = ref({});

const componentName = ref<TComponentType>(componentDict);

const filterList = computed(() => {
  return props.list.map((res) => {
    return {
      labelVisible: true,
      ...res,
    };
  });
});

const contentClass = computed(() => {
  return {
    content: true,
  };
});

const formItemStyle = computed(() => {
  return (item) => {
    return {
      "margin-bottom": item.marginBottom + "px",
    };
  };
});

const formItemClass = computed(() => {
  return {
    "render-form-item": true,
    border: props.needBorder,
    [`render-form-${props.labelPosition}`]: true,
  };
});

const labelPositionClass = computed(() => {
  return props.labelPosition === "left" ? "flex" : "block";
});

watchEffect(() => {
  formData.value = props.data;
});
</script>

<style lang="scss">
.render-form[data-weiling-mobile-ui-bc-render-form] {
  .render-form-item + .render-form-item {
    margin-top: v-bind(space);
  }

  .render-form-item {
    font-size: j(14);
    display: v-bind(labelPositionClass);
    background-color: v-bind(backgroundColor);
    align-items: center;

    .render-form-top {
      padding: j(15) j(15) j(5) j(15);
    }

    .label {
      color: #646566;
      min-width: j(100);
    }

    .content {
      flex: 1;
      min-height: $form-height;
      @extend %flex-middle;
    }

    &:not(:last-child) {
      &.border {
        @include halfBorder("bottom", $border-color);
      }
    }
  }
}
</style>
