<script setup lang="tsx">
import { Form, FormSchema } from '@/components/Form'
import { useForm } from '@/hooks/web/useForm'
import { PropType, watch, ref } from 'vue'
import { useValidator } from '@/hooks/web/useValidator'
import { ElText, ElLoading, ElTooltip, ElMessage } from 'element-plus'
import { Icon } from '@/components/Icon'
import { getClassConfig, configSave } from '@/api/system/config'
import { upImage } from '@/api/system/admin'
import { BaseButton } from '@/components/Button'
import { UpImgButtom } from '@/components/UpFile'
const validator = useValidator()
const props = defineProps({
  loadData: {
    type: Boolean,
    default: false
  },
  id: {
    type: Number as PropType<number>,
    default: () => null
  }
})
const configData = ref<any[]>([])
watch(
  () => props.loadData,
  async (val) => {
    if (val) {
      const { data } = await getClassConfig({ id: props.id })
      configData.value = data.info
      initData(data.info)
      emit('success')
    }
  },
  {
    deep: true,
    immediate: true
  }
)
const emit = defineEmits(['success'])
const formSchema = ref<FormSchema[]>([])
const rules = ref<any>({})
const initData = async (array) => {
  try {
    // 加强类型检查
    if (!Array.isArray(array) || array.length === 0) return

    const schemaList: FormSchema[] = []
    const MIME_TYPES = {
      audioVideo: 'audio/mpeg,.wma,.wav,video/mp4,.amr,.key,.xlsx,.xls,.apk,application/pdf'
    }

    /**
     * 根据配置项更新输入框类型和属性
     *
     * @param {Object} schema - 表单架构对象，用于定义输入框的类型和其他属性
     * @param {Object} item - 配置项对象，包含输入框的类型和描述信息
     */
    const handleInputType = (schema, item) => {
      // 更新输入框的类型
      schema.componentProps.type = item.configuration.input_type
      // 设置输入框的占位符，优先使用配置项中的描述信息，如果没有则拼接提示信息
      schema.componentProps.placeholder = item.desc || `请输入${item.info}`
      // 如果输入框类型为多行文本域，则设置其自动调整大小的属性
      if (item.configuration.input_type === 'textarea') {
        schema.componentProps.autosize = { minRows: 2, maxRows: 10 }
      }
    }

    /**
     * 配置组类型项目的处理函数
     *
     * 该函数用于配置Vue表单中组类型项目的schema属性它主要负责更新组件的选项和表单项的标签
     *
     * @param {Object} schema - 表单项的schema对象，用于定义表单的结构和属性
     * @param {Object} item - 包含配置信息的项目对象，包括选项、信息和描述
     */
    const handleGroupType = (schema, item) => {
      // 更新组件的选项
      schema.componentProps.options = item.configuration.options

      // 配置表单项的标签，包括项目信息和一个工具提示，用于提供额外的描述信息
      schema.formItemProps = {
        slots: {
          label: () => (
            <div class="flex items-center">
              <span>{item.info}</span>
              <ElTooltip class="box-item" effect="dark" content={item.desc} placement="top-start">
                <Icon class="ml-5px" icon={'vi-ep:info-filled'}></Icon>
              </ElTooltip>
            </div>
          )
        }
      }
    }

    /**
     * 处理上传类型的函数
     * 根据配置项初始化上传组件的属性和行为
     * @param {Object} schema - 组件的架构对象，用于定义组件的属性和行为
     * @param {Object} item - 配置项对象，包含上传类型和其他配置信息
     */
    const handleUploadType = (schema, item) => {
      // 根据配置项初始化schema的value属性
      if (Array.isArray(item.value)) {
        schema.value = item.value.map((rr) => rr.filepath)
      } else {
        schema.value = []
      }

      // 禁用自动上传
      schema.componentProps.autoUpload = false

      // 根据上传类型配置默认插槽内容
      if ([1, 2].includes(item.configuration.upload_type)) {
        schema.formItemProps.slots.default = (data) => {
          return (
            <>
              <UpImgButtom
                tip={item.desc}
                v-model={data[schema.field]}
                num={item.configuration.upload_type == 1 ? 1 : 5}
              />
            </>
          )
        }
      }

      // 配置音频视频上传类型
      if (item.configuration.upload_type === 3) {
        schema.componentProps.accept = MIME_TYPES.audioVideo
        schema.componentProps.limit = 1

        // 初始化上传按钮
        initializeSlots(schema.componentProps, 'trigger', () => <BaseButton>上传文件</BaseButton>)

        // 处理超出文件数限制的情况
        schema.componentProps.onExceed = async (files) => {
          if (!files || files.length === 0) return
          const res = await upFromImage(files[0])
          setValues({
            [schema.field]: [
              {
                name: files[0].name,
                url: res.data.src
              }
            ]
          })
        }

        // 处理文件选择变化
        schema.componentProps.on = {
          change: async (val) => {
            if (!val || !val.raw) return
            const res = await upFromImage(val.raw)
            const form = await getFormData()
            const arr = form[schema.field].map((re, ind) =>
              ind < form[schema.field].length - 1
                ? re
                : {
                    name: val.name,
                    url: res.data.src
                  }
            )
            setValues({ [schema.field]: [...arr] })
          }
        }
      }

      // 初始化提示信息
      if (item.desc) {
        initializeSlots(schema.componentProps, 'tip', () => (
          <div>
            <ElText type="info" size="small">
              {item.desc}
            </ElText>
          </div>
        ))
      }
    }

    /**
     * 初始化或更新组件的插槽内容
     *
     * @param {Object} componentProps - 组件的属性对象，用于存储包括插槽在内的各种属性
     * @param {string} slotName - 插槽的名称，用于标识组件中的不同插槽
     * @param {*} slotContent - 插槽的内容，可以是任意类型，具体取决于插槽的用途
     */
    const initializeSlots = (componentProps, slotName, slotContent) => {
      // 将指定的插槽内容分配给组件属性对象的相应插槽名称下
      componentProps.slots[slotName] = slotContent
    }

    for (let ind = 0; ind < array.length; ind++) {
      const item = array[ind]
      const schema: FormSchema = {
        field: item.menu_name,
        label: item.info,
        hidden: !item.status,
        component: item.type,
        value: item.value,
        colProps: { span: 24 },
        componentProps: { placeholder: item.desc, slots: {} },
        formItemProps: { slots: {} }
      }

      // 设置默认配置
      item.configuration = item.configuration || {
        options: [],
        required: [],
        maxlength: 0,
        minlength: 0,
        input_type: 'text',
        upload_type: 1
      }

      switch (item.type) {
        case 'Input':
          handleInputType(schema, item)
          break
        case 'RadioGroup':
          schema.value = item.value ? item.value + '' : '0'
          handleGroupType(schema, item)
          break
        case 'CheckboxGroup':
          handleGroupType(schema, item)
          break
        case 'Select':
          schema.value = item.value ? item.value + '' : '0'
          handleGroupType(schema, item)
          break
        case 'Upload':
          handleUploadType(schema, item)
          break
      }

      const required = item.configuration.required
      if (required && required.length > 0) {
        const vali = required
          .filter((rule) => typeof validator[rule] === 'function')
          .map((rule) => validator[rule]())
        rules.value[item.menu_name] = vali
      }
      schemaList.push(schema)
    }
    formSchema.value = schemaList
  } catch (error) {
    console.error('Error in initData:', error)
    throw new Error('Failed to initialize data')
  }
}

const { formRegister, formMethods } = useForm()
const { setValues, getFormData, getElFormExpose } = formMethods
const upFromImage = async (files) => {
  const loading = ElLoading.service({
    lock: true,
    text: '上传中',
    background: 'rgba(0, 0, 0, 0.7)'
  })
  const res = await upImage({
    pid: 0,
    file: files,
    type: 0
  })
  if (!res) {
    ElMessage.error('上传失败')
  }
  loading.close()
  return res
}
const loading = ref(false)
const submit = async () => {
  loading.value = true
  const elForm = await getElFormExpose()
  const valid = await elForm?.validate().catch((err) => {
    console.log(err)
  })
  if (valid) {
    const formData = await getFormData()
    const res = await configSave(formData)
    if (res) {
      ElMessage.success('保存成功')
    }
  }
  setTimeout(() => {
    loading.value = false
  }, 500)
}
</script>

<template>
  <div
    v-loading="loading"
    element-loading-text="保存中"
    element-loading-background="rgba(255, 255, 255, 0.8)"
  >
    <Form
      v-if="formSchema.length > 0"
      :ref="`id_${id}`"
      :rules="rules"
      @register="formRegister"
      :schema="formSchema"
    />
    <BaseButton @click="submit">提交</BaseButton>
  </div>
</template>
<style lang="less" scoped>
:deep(.el-upload-list) {
  &.el-upload-list--picture-card {
    .el-upload-list__item {
      width: 80px;
      height: 80px;
    }
    .el-upload--picture-card {
      width: 80px;
      height: 80px;
    }
  }
}
</style>
