<template>
  <div :class="groups.length ? 'XFormGroupClass' : ''">
    <a-empty v-if="loadingErr" description="配置走丢了" />
    <a-spin v-else tip="正在努力加载..." :spinning="spinning" wrapperClassName="heigth100">
      <a-row :gutter="24" style="height: 100%">
        <a-col :span="3" v-if="showLeftTab && groups.length">
          <a-tabs tab-position="left" v-model="activeTab" @change="scrollToGroup">
            <template v-for="(item, index) in groups">
              <a-tab-pane
                :tab="item.describe"
                :key="index"
                v-if="item.describe && (formShow[`show${item.groupName}`] || formShow[`show${item.slotName}`])"
              ></a-tab-pane>
            </template>
          </a-tabs>
        </a-col>
        <a-col :span="showLeftTab ? 21 : 24" class="formGroupContext" ref="formGroupContext">
          <div class="group-item" :ref="`group-${index}`" :key="index" v-for="(item, index) in groups">
            <a-row
              :style="{ marginTop: index === 0 ? '' : '8px' }"
              v-if="formShow[`show${item.groupName}`] || formShow[`show${item.slotName}`]"
            >
              <a-col :span="5">
                <x-title v-if="showDot === true || showDot === 'true'" :title="item.describe" :dot="true" />
                <span v-else class="xFormGroupTitle">{{ item.describe }}</span>
              </a-col>
            </a-row>
            <div v-show="formShow[`show${item.slotName}`]">
              <template v-if="item.formGroupType === 'slot'">
                <slot :name="item.slotName" :data="allFormData" :index="index">
                  <a-empty :description="`[${item.describe}:${item.slotName}]插槽没有使用`" />
                </slot>
              </template>
            </div>
            <x-add-native-form
              @x-form-item-emit-func="(func, data, value) => emitFunc(func, data, value)"
              v-if="item.formGroupType !== 'slot' && formShow[`show${item.groupName}`]"
              :ref="`nativeForm-${index}`"
              :key="`nativeForm-${index}`"
            />
          </div>
        </a-col>
      </a-row>
    </a-spin>
  </div>
</template>

<script>
import { throttle } from 'lodash'
import XAddNativeForm from '@vue2-client/base-client/components/common/XAddNativeForm/XAddNativeForm.vue'
import XTitle from '@vue2-client/base-client/components/his/XTitle/XTitle.vue'

// 常量定义
const SCROLL_CONSTANTS = {
  OFFSET_TOP: 205, // 滚动激活区域顶部偏移（像素）
  OFFSET_BOTTOM: 200, // 滚动激活区域底部偏移（像素）
  THROTTLE_DELAY: 100 // 滚动事件节流延迟（毫秒）
}

export default {
  name: 'XFormGroup',
  components: {
    XAddNativeForm,
    XTitle
  },
  props: {
    showDot: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      formList: [],
      groups: [],
      modifyModelData: {},
      serviceName: '',
      showLeftTab: false,
      showSubmitBtn: false,
      loading: false,
      allFormData: {},
      businessType: {},
      formShow: {},
      env: 'dev',
      spinning: true,
      loadingErr: false,
      activeTab: 0,
      extData: {},
      // 创建节流函数实例
      throttledOnScroll: null
    }
  },
  mounted() {},
  created() {
    // 在组件创建时初始化节流函数
    this.throttledOnScroll = throttle(this.handleScroll, SCROLL_CONSTANTS.THROTTLE_DELAY)
  },
  beforeDestroy() {
    const formGroupContext = this.$refs.formGroupContext?.$el
    if (formGroupContext && formGroupContext.removeEventListener) {
      // 移除节流后的滚动事件监听器
      formGroupContext.removeEventListener('scroll', this.throttledOnScroll)
    }
    // 取消未执行的节流函数
    if (this.throttledOnScroll && this.throttledOnScroll.cancel) {
      this.throttledOnScroll.cancel()
    }
  },
  provide() {
    return {
      inXFormGroup: true,
      formGroupContext: this,
      formDataChange: this.handleFormDataChange
    }
  },
  methods: {
    setRef(refName, refValue) {
      if (!this.$refs[refName]) {
        this.$refs[refName] = refValue
      }
    },
    /**
     * 初始化表单组
     * @param {Object} options - 初始化配置
     * @param {Array<FormGroup>} options.groups - 表单组数据
     * @param {Object} options.modifyModelData - 修改模式的初始数据
     * @param {string} options.serviceName - 服务名称
     * @param {'dev'|'prod'|'test'} options.env - 运行环境
     * @param {boolean} options.showLeftTab - 是否显示左侧导航
     * @param {'新增'|'修改'} options.businessType - 业务类型
     * @param {Object} options.formShow - 表单显示状态控制
     * @param {Object} options.extData - 扩展数据，用于表单内函数使用
     * @returns {void}
     *
     * @typedef {Object} FormGroup
     * @property {string} groupName - 表单组名称
     * @property {string} describe - 表单组描述
     * @property {'slot'|'form'} formGroupType - 表单组类型
     * @property {string} [slotName] - 插槽名称（当 formGroupType 为 'slot' 时必填）
     * @property {Array} [formJson] - 表单配置（当 formGroupType 为 'form' 时必填）
     */
    init({
      groups,
      modifyModelData = {},
      serviceName = process.env.VUE_APP_SYSTEM_NAME,
      env = 'prod',
      showLeftTab = false,
      businessType = '新增',
      formShow = {},
      extData = {}
    }) {
      Object.assign(this, { groups, modifyModelData, serviceName, env, showLeftTab, businessType, formShow, extData })
      this.initView()
      this.$nextTick(() => {
        const formGroupContext = this.$refs.formGroupContext?.$el
        if (formGroupContext && formGroupContext.addEventListener) {
          // 使用节流后的滚动处理函数
          formGroupContext.addEventListener('scroll', this.throttledOnScroll)
        }
      })
    },
    // 初始化组件
    initView() {
      this.spinning = true
      const promises = []
      for (let i = 0; i < this.groups.length; i++) {
        promises.push(this.initData(i))
      }
      Promise.all(promises)
        .then(() => {
          this.spinning = false
        })
        .catch(() => {
          this.loadingErr = true
          this.spinning = false
        })
    },
    getNativeFormRef(group) {
      if (!group) {
        console.warn('getNativeFormRef(group) group is required')
        return null
      }
      return this.groups
        .map((item, index) => {
          if (
            item.groupName === group &&
            this.$refs[`nativeForm-${index}`] &&
            this.$refs[`nativeForm-${index}`].length
          ) {
            return this.$refs[`nativeForm-${index}`][0]
          } else {
            return null
          }
        })
        .filter(ref => ref !== null)
    },
    getNativeForm(group) {
      const formref = this.getNativeFormRef(group)
      return formref.length ? formref[0].form : null
    },
    /**
     * 更新指定表单组的字段值
     * @param {string} groupName - 表单组名称
     * @param {object} values - 要更新的字段值对象
     * @returns {boolean} 是否更新成功
     * @example
     * this.$refs.formGroup.updateGroupValues('groupB', { b1: 'value1', b2: 'value2' })
     */
    updateGroupValues(groupName, values) {
      if (!groupName || !values) {
        console.warn('[XFormGroup] updateGroupValues 参数不完整')
        return false
      }

      const formRefs = this.getNativeFormRef(groupName)

      // 如果表单已经存在且已初始化
      if (formRefs && formRefs.length > 0) {
        const nativeFormRef = formRefs[0]

        try {
          // 使用 XAddNativeForm 的 setForm 方法
          if (typeof nativeFormRef.setForm === 'function') {
            nativeFormRef.setForm(values)

            // 同步更新 allFormData
            this.$set(this.allFormData, groupName, {
              ...this.allFormData[groupName],
              ...values
            })

            return true
          }
        } catch (error) {
          console.error(`[XFormGroup] 更新表单组 ${groupName} 失败:`, error)
          return false
        }
      }

      // 表单不存在，则给 modifyModelData 中对应的组赋值
      if (!this.modifyModelData[groupName]) {
        this.$set(this.modifyModelData, groupName, {})
      }

      this.$set(this.modifyModelData, groupName, {
        ...this.modifyModelData[groupName],
        ...values
      })

      console.info(`[XFormGroup] 表单组 ${groupName} 尚未初始化，已将数据保存到 modifyModelData`)
      return true
    },
    /**
     * 获取指定表单组的当前值
     * @param {string} groupName - 表单组名称
     * @returns {object} 表单数据
     * @example
     * const values = this.$refs.formGroup.getGroupValues('groupA')
     */
    getGroupValues(groupName) {
      if (!groupName) {
        console.warn('[XFormGroup] getGroupValues 需要提供 groupName')
        return {}
      }

      return this.allFormData[groupName] || {}
    },
    /**
     *
     * @param index
     * @param defaultForm 控制展示表表单项的时候可以出动传递默认值
     */
    initData(index, defaultForm = {}) {
      // 定义当前表单配置
      const res = this.groups[index]
      const showKey = res?.formGroupType === 'slot' ? `show${res.slotName}` : `show${res.groupName}`
      if (typeof this.formShow[showKey] === 'undefined') {
        this.$set(this.formShow, showKey, true)
      }
      if (!this.formShow[showKey]) {
        return
      }

      // 如果是插槽组件
      if (res?.formGroupType === 'slot') {
        // 组织插槽表单的结果
        this.allFormData[res.slotName] = {}
        return
      }
      // 组织native表单存储的结果
      this.allFormData[res.groupName] = {}
      this.formList.push(res)
      let modifyModelData = {
        data: defaultForm
      }
      if (this.modifyModelData[res.groupName]) {
        modifyModelData = {
          data: Object.assign(this.modifyModelData[res.groupName], defaultForm),
          files: this.modifyModelData[res.groupName].files,
          images: this.modifyModelData[res.groupName].images
        }
      }
      const params = {
        layout: res.xAddFormLayout,
        formItems: res.formJson,
        showSubmitBtn: false,
        serviceName: this.serviceName,
        fixedAddForm: modifyModelData.data,
        modifyModelData: modifyModelData,
        businessType: this.businessType,
        env: this.env,
        groupName: res.groupName,
        extData: this.extData,
        ...res
      }
      params.showSubmitBtn = false
      this.$nextTick(() => {
        this.$refs[`nativeForm-${index}`][0].init(params)
      })
    },
    scrollToGroup(index) {
      const groupElement = this.$refs[`group-${index}`][0]
      if (groupElement) {
        groupElement.scrollIntoView({ behavior: 'smooth' })
      }
    },
    /**
     * 控制表单组的显示/隐藏
     * @param {string} func - 'x-form-show' 显示 | 'x-form-no-show' 隐藏
     * @param {string} name - 表单组名称（groupName 或 slotName）
     * @param {object} defaultForm - 默认表单数据
     */
    xFormShow(func, name, defaultForm = {}) {
      if (name) {
        this.groups.forEach((item, index) => {
          if (name === item.groupName) {
            this.$set(this.formShow, `show${item.groupName}`, func === 'x-form-show')

            if (func === 'x-form-show') {
              // 显示表单组
              // 判断表单是否已经存在，如果已经存在就不再执行 initData
              const formRefs = this.getNativeFormRef(item.groupName)
              const isFormInitialized = formRefs && formRefs.length > 0

              if (!isFormInitialized) {
                console.warn('xFormShow', index, defaultForm)
                this.initData(index, defaultForm)
              } else {
                // 表单已存在，如果有 defaultForm 则更新值
                if (Object.keys(defaultForm).length > 0) {
                  this.updateGroupValues(item.groupName, defaultForm)
                }
              }
            } else if (func === 'x-form-no-show') {
              // 隐藏表单组时，清理数据
              this.clearGroupData(item.groupName)
            }
          } else if (name === item.slotName) {
            this.$set(this.formShow, `show${item.slotName}`, func === 'x-form-show')

            if (func === 'x-form-show') {
              // 显示插槽表单组
              // 插槽类型的表单组，判断是否已经初始化过
              const hasInitialized = this.allFormData[item.slotName] !== undefined

              if (!hasInitialized) {
                this.initData(index, defaultForm)
              }
            } else if (func === 'x-form-no-show') {
              // 隐藏插槽表单组时，清理数据
              this.clearGroupData(item.slotName)
            }
          }
        })
      }
    },
    /**
     * 清理表单组数据
     * 在表单组隐藏时，移除 modifyModelData 和 allFormData 中的数据
     * @param {string} groupName - 表单组名称
     */
    clearGroupData(groupName) {
      if (!groupName) return

      // 清理 allFormData
      if (this.allFormData[groupName]) {
        this.$delete(this.allFormData, groupName)
      }

      // 清理 modifyModelData
      if (this.modifyModelData[groupName]) {
        this.$delete(this.modifyModelData, groupName)
      }

      console.info(`[XFormGroup] 已清理表单组 ${groupName} 的数据`)
    },
    // xfromitem 一路传递上来的事件
    emitFunc(func, data, value) {
      if (func === 'x-form-show' || func === 'x-form-no-show') {
        this.xFormShow(func, data, value)
      } else {
        try {
          this.$emit(func, data, value)
        } catch (error) {
          console.error(error)
        }
        this.$emit('x-form-item-emit-func', func, data, value)
      }
    },
    // 提交表单
    asyncSubmit() {
      return this.onSubmit()
    },
    async onSubmit() {
      let pass = true
      const promises = this.groups.map((item, index) => {
        const nativeFormRef = this.$refs[`nativeForm-${index}`] ? this.$refs[`nativeForm-${index}`][0] : undefined
        if ((item.groupName || item.slotName) && nativeFormRef && typeof nativeFormRef.asyncSubmit === 'function') {
          // 如果 ref 存在 asyncSubmit 方法，则调用 asyncSubmit 方法
          return nativeFormRef
            .asyncSubmit()
            .then(res => {
              this.allFormData[item.slotName || item.groupName] = res.realForm
            })
            .catch(_err => {
              pass = false
              this.scrollToGroup(index)
            })
        } else {
          console.warn(item.groupName + '未找到组件，或者组件没有 asyncSubmit 方法')
          // 如果 ref 不存在或没有 asyncSubmit 方法，则返回一个已解决的 Promise
          return Promise.resolve()
        }
      })

      try {
        await Promise.all(promises)

        if (pass) {
          return Promise.resolve(this.allFormData)
        } else {
          this.$message.error('请检查表单填写是否正确')
          return Promise.reject(new Error('Form validation failed'))
        }
      } catch (error) {
        return Promise.reject(new Error('An unexpected error occurred'))
      }
    },
    /**
     * 处理滚动事件，计算当前激活的表单组
     * 注意：此方法会被 throttle 包装，实际使用的是 this.throttledOnScroll
     */
    handleScroll() {
      const formGroupContext = this.$refs.formGroupContext?.$el
      if (!formGroupContext) return

      const groupItems = formGroupContext.querySelectorAll('.group-item')
      if (!groupItems || groupItems.length === 0) return

      let activeIndex = this.activeTab

      // 遍历所有表单组项，找到当前滚动位置对应的表单组
      groupItems.forEach((item, index) => {
        const rect = item.getBoundingClientRect()
        // 使用常量替代魔术数字
        if (rect.top <= SCROLL_CONSTANTS.OFFSET_TOP && rect.bottom > SCROLL_CONSTANTS.OFFSET_BOTTOM) {
          activeIndex = index
        }
      })

      // 只在 activeIndex 变化时更新，减少不必要的渲染
      if (this.activeTab !== activeIndex) {
        this.activeTab = activeIndex
      }
    },
    /**
     * 处理表单数据变化
     * @param {string} groupName 表单组名称
     * @param {object} formData 表单数据
     */
    handleFormDataChange(groupName, formData) {
      if (!groupName) {
        // 兼容非 XFormGroup 场景，直接返回
        return
      }
      // 更新 allFormData
      this.$set(this.allFormData, groupName, formData)
      // 抛出表单组数据
      this.$emit('x-form-group-data-change', groupName, formData)
      // 触发其他表单的刷新
      this.$nextTick(() => {
        this.groups.forEach((item, index) => {
          if (item.groupName && item.groupName !== groupName) {
            const nativeFormRef = this.$refs[`nativeForm-${index}`]?.[0]
            if (nativeFormRef && typeof nativeFormRef.refreshShowFunc === 'function') {
              nativeFormRef.refreshShowFunc()
            }
          }
        })
      })
    }
  }
}
</script>
<style lang="less" scoped>
.XFormGroupClass {
  height: 100%;

  .heigth100 {
    height: 100%;

    :deep(.ant-spin-container) {
      height: 100%;
    }
  }

  .xFormGroupTitle {
    font-size: 15px;
    font-weight: bold;
    color: @primary-color;
  }

  .formGroupContext {
    height: 100%;
    overflow-y: scroll;
  }
}
</style>
