<script setup lang="ts">
import XFormTable from '@af-mobile-client-vue3/components/data/XCellList/index.vue'
// import { getRealKeyData } from '@af-mobile-client-vue3/utils/util'
import { executeStrFunctionByContext } from '@af-mobile-client-vue3/utils/runEvalFunction'
import {
  showDialog,
  Col as VanCol,
  Row as VanRow,
} from 'vant'

import { computed, inject, nextTick, onBeforeMount, ref, watch } from 'vue'

const props = withDefaults(defineProps<Props>(), {
  showImgInCell: false,
  config: () => ({}),
  serverName: '',
  env: 'prod',
  display: true,
  useOssForImg: false,
  noTopBorder: false,
})

// Emits
const emit = defineEmits<{
  (e: 'update:configData', value: any): void
  (e: 'change', value: any): void
  (e: 'updateImg', value: any): void
  (e: 'selectRow', selectedRowKeys: any[], selectedRows: any[]): void
  (e: 'slotRendered'): void
  (e: 'listClick', value: any): void
}>()

// import { getMicroData, getWindow, isMicroAppEnv, microDispatch } from '@af-mobile-client-vue3/utils/microAppUtils'
// import { isInAModal } from '@af-mobile-client-vue3/utils/microAppUtils'

// 定义isInAModal变量（原来从微应用工具中导入，现在手动定义）
const isInAModal = ref(false)

// 动态导入组件
// const XAddNativeForm = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XAddNativeForm/XAddNativeForm.vue'))
// const XFormGroup = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XFormGroup/XFormGroup.vue'))
// const XTreePro = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XTree/XTreePro.vue'))
// const XHisEditor = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/his/XHisEditor/XHisEditor.vue'))
// const XTab = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XTab/XTab.vue'))
// const XReport = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XReport/XReport.vue'))
// const XButtons = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XButtons/XButtons.vue'))
// const XLabelSelect = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XLabelSelect/XLabelSelect.vue'))
// const XConversation = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XConversation/XConversation.vue'))
// const XCheckList = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XCheckList/XCheckList.vue'))
// const XCardSet = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XCardSet/XCardSet.vue'))
// const XCollapse = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XCollapse/XCollapse.vue'))
// const XHDescriptions = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/his/XHDescriptions/XHDescriptions.vue'))
// const XSidebar = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/his/XSidebar/XSidebar.vue'))
// const XList = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/his/XList/XList.vue'))
// const XInput = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XInput/XInput.vue'))
// const XTimeLine = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XTimeline/XTimeline.vue'))
// const XRadio = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/his/XRadio/XRadio.vue'))
// const XCalendar = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/common/XCalendar/XCalendar.vue'))
// const XTimeSelect = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/his/XTimeSelect/XTimeSelect.vue'))
// const XCheckbox = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/his/XCheckbox/XCheckbox.vue'))
// const XTitle = defineAsyncComponent(() => import('@af-mobile-client-vue3/components/his/XTitle/XTitle.vue'))

// 组件映射表 - 将kebab-case的组件名映射到实际组件对象
const componentMap: Record<string, any> = {
  'x-form-table': XFormTable,
}

// 可用的插槽组件列表
const slotComponents = [
  'x-form-table',
  'x-add-native-form',
  'x-tree-pro',
  'x-his-editor',
  'x-tab',
  'x-form-group',
  'x-report',
  'x-buttons',
  'x-label-select',
  'x-conversation',
  'x-check-list',
  'x-cardSet',
  'x-collapse',
  'x-h-descriptions',
  'x-sidebar',
  'x-list',
  'x-input',
  'x-time-line',
  'x-radio',
  'x-calendar',
  'x-time-select',
  'x-checkbox',
  'x-title',
]

// 类型定义
interface ComponentRef {
  init: (config: any) => void
  refresh?: () => void
}

interface MixinData {
  businessType?: string
  files?: any[]
  images?: any[]
  [key: string]: any
}

interface InjectFunctions {
  getMixinData: () => MixinData
  getSelectedId: () => string | number
  getSelectedData: () => any
  getOutEnv: () => string
  getConfigByName: (configName: string, serviceName: string, callback: (config: any) => void, isDev?: boolean) => void
  runLogic: (config: any, selectedId?: any, serviceName?: string) => Promise<any>
  getComponentByName: (name: string) => ComponentRef | undefined
  registerComponent: (name: string, component: ComponentRef | undefined) => void
}

interface UploadConfig {
  type: string
  accept: string[]
  resUploadStock: number
  pathKey: string
  resUploadMode?: string
}

interface GutterItem {
  xs: number
  sm: number
  md: number
  lg: number
}

type Gutter = [number, GutterItem]

// Props
interface Props {
  columns: any[]
  showImgInCell?: boolean
  config?: Record<string, any>
  serverName?: string
  env?: string
  configData: Record<string, any>
  display?: boolean
  useOssForImg?: boolean
  noTopBorder?: boolean
}

// 注入依赖
const openDialog = inject('openDialog')
const emitEvent = inject('emitEvent')
const registerComponent = inject('registerComponent') as InjectFunctions['registerComponent']
const setColSpanByName = inject('setColSpanByName')
const setGlobalData = inject('setGlobalData')
const getGlobalData = inject('getGlobalData')
const getComponentByName = inject('getComponentByName') as InjectFunctions['getComponentByName']
const runLogicInject = inject('runLogic') as InjectFunctions['runLogic']
const getMixinData = inject('getMixinData', () => ({})) as InjectFunctions['getMixinData']
const getSelectedId = inject('getSelectedId', () => '') as InjectFunctions['getSelectedId']
const getSelectedData = inject('getSelectedData', () => ({})) as InjectFunctions['getSelectedData']
const getOutEnv = inject('getOutEnv', () => '') as InjectFunctions['getOutEnv']
const currUser = inject('currUser')
const isWidget = inject('isWidget', false)
const getConfigByNameInject = inject('getConfigByName', () => {}) as InjectFunctions['getConfigByName']

// 状态
const gutter = ref([8, 8])
const maxColSpan = ref(12)
const uploadConfig = ref<UploadConfig>({
  type: 'image',
  accept: ['image/jpeg', 'image/png', 'image/gif'],
  resUploadStock: 9,
  pathKey: 'cs',
  resUploadMode: 'single',
})
const mixinData = ref<MixinData>({})
const flexItemBodyState = ref({
  padding: '24px',
})
const slotRendered = ref(0)

// Refs
const trGroupRefs = ref(new Map())
const dynamicComponentRefs = ref(new Map<string, ComponentRef>())

// 计算属性
const allSlotSum = computed(() => {
  let sum = 0
  props.columns.forEach((item) => {
    if (Array.isArray(item)) {
      item.forEach((cell) => {
        if (cell.type === 'slot') {
          sum++
        }
      })
    }
    else if (item.type && item.type === 'slot') {
      sum++
    }
  })
  return sum
})

// Methods
function setTrGroupRef(el: any, key: string) {
  if (el)
    trGroupRefs.value.set(key, el)
}

function setDynamicComponentRef(el: any, key: string) {
  if (el)
    dynamicComponentRefs.value.set(key, el)
}

function listClick(data: any) {
  emit('listClick', data)
}

function calculateColSpan(cell: any) {
  return Array.isArray(cell)
    ? cell[0][0]?.colSpan * 2
    : (cell?.colSpan ?? cell?.def?.colSpan ?? 1) * 2
}

function calcTDBorder(cellNoBorder = false) {
  if (cellNoBorder)
    return 'tdNoBorder'

  return props.noTopBorder ? 'tdWithNoTopBorder' : 'tdWithBorder'
}

function determineCellStyle(cell: any) {
  if (!cell.style)
    return {}
  return cell.style
}

function getEventHandlers(cell: any) {
  const handlers: Record<string, Function> = {}
  if (!cell?.events || cell?.events?.length === 0)
    return handlers

  cell.events.forEach((event: any) => {
    handlers[event.type] = async (...args: any[]) => {
      console.info('Event handled:', event.type, args)
      let func = event.customFunction
      if (func && func.startsWith('function'))
        func = func.replace('function', 'async function')

      const result = await executeStrFunctionByContext(null, func, args)
      if (result instanceof Promise) {
        result.then((res) => {
          if (!res)
            return
          let messageType = 'success'

          if (res?.name) {
            const waitRefreshRef = getComponentByName?.(res.name)
            if (waitRefreshRef)
              waitRefreshRef.refresh()
            else
              console.warn(`未找到组件${res.name}无法刷新`)
          }

          if (res?.messageType)
            messageType = res.messageType

          if (res?.message) {
            showDialog({
              message: res.message,
            })
          }
        })
      }
    }
  })

  return handlers
}

function getComponentName(queryParamsName: string, serviceName: string, componentName: string) {
  // 从映射表中获取组件，如果没有则返回原始组件名
  return componentMap[componentName] || componentName
}

async function onComponentMounted(h: any, cell: any, cellIndex: number) {
  slotRendered.value += 1
  if (slotRendered.value >= allSlotSum.value)
    emit('slotRendered')

  if (getMixinData && getMixinData())
    mixinData.value = getMixinData()

  if (cell.slotRef)
    registerComponent?.(cell.slotRef, dynamicComponentRefs.value.get(`dynamicComponent_${cell.slotRef || cellIndex}`))

  console.log(`插槽组件已经初始化 slotType ${cell.slotType}，ref= dynamicComponent_${cell.slotRef || cellIndex} ， serviceName = ${cell.serviceName}`)

  const shouldInit = cell.shouldInit ?? true
  if (shouldInit) {
    if (cell.slotType === 'x-add-native-form')
      initAddNativeForm(cell, cellIndex)
    else if (cell.slotType === 'x-form-group')
      initFormGroup(cell, cellIndex)
    else if (cell.slotType === 'x-buttons')
      initButtons(cell, cellIndex)
    else if (cell.slotType === 'x-label-select')
      initLabelSelect(cell, cellIndex)
    else if (cell.slotType === 'x-report')
      initReport(cell, cellIndex)
    else if (cell.slotType === 'x-conversation')
      initConversation(cell, cellIndex)
    else if (cell.slotType === 'x-check-list')
      initCheckList(cell, cellIndex)
  }
}

// 初始化各种组件的方法
async function initAddNativeForm(cell: any, cellIndex: number) {
  getConfigByNameInject(cell.slotConfig, cell.serviceName, async (res: any) => {
    let param = { ...mixinData.value }
    let selectedId
    if (res.paramLogicName) {
      if (getSelectedId) {
        selectedId = getSelectedId()
        if (typeof selectedId !== 'object')
          selectedId = { selectedId }
      }
      param = Object.assign(param, await runLogicInject(res.paramLogicName, selectedId, cell.serviceName))
    }

    const componentRef = dynamicComponentRefs.value.get(`dynamicComponent_${cell.slotRef || cellIndex}`)
    if (componentRef) {
      componentRef.init({
        serviceName: cell.serviceName,
        configName: cell.slotConfig,
        formItems: res.formJson,
        showSubmitBtn: !isInAModal.value,
        businessType: param.businessType || '新增',
        layout: res.xAddFormLayout,
        primaryKey: res.primaryKey,
        ...res,
        fixedAddForm: param,
        modifyModelData: {
          files: param.files,
          images: param.images,
        },
      })
    }
  })
}

async function initFormGroup(cell: any, cellIndex: number) {
  getConfigByNameInject(cell.slotConfig, cell.serviceName, (res: any) => {
    const param = { ...mixinData.value }
    const componentRef = dynamicComponentRefs.value.get(`dynamicComponent_${cell.slotRef || cellIndex}`)
    if (componentRef) {
      componentRef.init({
        ...res,
        serviceName: cell.serviceName,
        showSubmitBtn: !isInAModal.value,
        businessType: param.businessType || '新增',
        modifyModelData: param,
        showLeftTab: true,
      })
    }
  })
}

async function initButtons(cell: any, cellIndex: number) {
  getConfigByNameInject(cell.slotConfig, cell.serviceName, (res: any) => {
    const componentRef = dynamicComponentRefs.value.get(`dynamicComponent_${cell.slotRef || cellIndex}`)
    if (componentRef) {
      componentRef.init({
        ...res,
        serviceName: cell.serviceName,
      })
    }
  })
}

async function initLabelSelect(cell: any, cellIndex: number) {
  getConfigByNameInject(cell.slotConfig, cell.serviceName, (res: any) => {
    const componentRef = dynamicComponentRefs.value.get(`dynamicComponent_${cell.slotRef || cellIndex}`)
    if (componentRef) {
      componentRef.init({
        ...res,
        serviceName: cell.serviceName,
      })
    }
  })
}

async function initReport(cell: any, cellIndex: number) {
  const param = { ...mixinData.value }
  const componentRef = dynamicComponentRefs.value.get(`dynamicComponent_${cell.slotRef || cellIndex}`)
  if (componentRef)
    componentRef.init(param)
}

async function initConversation(cell: any, cellIndex: number) {
  getConfigByNameInject(cell.slotConfig, cell.serviceName, (res: any) => {
    const componentRef = dynamicComponentRefs.value.get(`dynamicComponent_${cell.slotRef || cellIndex}`)
    if (componentRef) {
      componentRef.init({
        serviceName: cell.serviceName,
        ...res,
      })
    }
  })
}

async function initCheckList(cell: any, cellIndex: number) {
  getConfigByNameInject(cell.slotConfig, cell.serviceName, (res: any) => {
    const componentRef = dynamicComponentRefs.value.get(`dynamicComponent_${cell.slotRef || cellIndex}`)
    if (componentRef) {
      componentRef.init({
        serviceName: cell.serviceName,
        ...res,
      })
    }
  })
}

function recalculateItem(item: any[]) {
  const totalColSpan = item.reduce((sum, cell) => {
    return sum + (cell._isManualColSpan ? 0 : (cell.colSpan || 1))
  }, 0)
  return item.map((cell) => {
    if (cell._isManualColSpan)
      return cell
    const newColSpan = Math.round((cell.colSpan || 1) / totalColSpan * 12)
    return {
      ...cell,
      colSpan: newColSpan,
      _isAutoCalculated: true,
    }
  })
}

// 生命周期钩子
onBeforeMount(() => {
  if (props.useOssForImg)
    uploadConfig.value.resUploadMode = 'oss'
})

// 监听器
watch(() => props.columns, (newVal) => {
  console.log('columns变化:', JSON.parse(JSON.stringify(newVal)))
  nextTick(() => {
    // Vue 3 不需要$forceUpdate
  })
}, { deep: true, immediate: true })

// 暴露方法
defineExpose({
  // getWindow,
  // isMicroAppEnv,
  // microDispatch,
  // getMicroData,
  // getRealKeyData
})
</script>

<template>
  <VanRow type="flex" :gutter="gutter" :style="isWidget ? { margin: '0px' } : { 'margin-bottom': '.5rem' }">
    <template v-for="(cell, cellIndex) in columns" :key="cellIndex">
      <VanCol
        v-if="Array.isArray(cell) || !cell?.dontShowRow"
        :ref="(el) => setTrGroupRef(el, cell.slotRef || cellIndex)"
        :class="calcTDBorder(cell.noBoarder)"
        :span="calculateColSpan(cell)"
        :style="Array.isArray(cell) ? {} : determineCellStyle(cell)"
      >
        <div v-if="isWidget" id="report_widget">
          <!-- 插槽渲染111 -->
          <template v-if="Array.isArray(cell)">
            <!-- 处理 cell 是数组的情况 -->
            <div v-for="(item, index) in cell" :key="index">
              <XReportTrGroup
                :env="env"
                :columns="recalculateItem(item)"
                :config-data="configData"
                :config="config"
                :display="true"
              />
            </div>
          </template>
          <template v-else-if="cell.type === 'slot'">
            <template
              v-if="slotComponents.includes(cell.slotType)"
            >
              <component
                :is="getComponentName(cell.slotConfig, cell.serviceName, cell.slotType)"
                :ref="(el) => setDynamicComponentRef(el, cell.slotRef || cellIndex)"
                :service-name="cell.serviceName"
                :server-name="cell.serviceName"
                :query-params-name="cell.slotConfig"
                :config-name="cell.slotConfig"
                :count-visible="false"
                :env="env"
                v-on="getEventHandlers(cell)"
                @mounted="(h) => onComponentMounted(h, cell, cellIndex)"
              />
            </template>
          </template>
        </div>
        <div v-else class="flexItem" :bordered="false" :body-style="flexItemBodyState">
          <!-- 插槽渲染2222 -->
          <template v-if="Array.isArray(cell)">
            <!-- 处理 cell 是数组的情况 -->
            <div v-for="(item, index) in cell" :key="index">
              <XReportTrGroup
                :server-name="serverName"
                :env="env"
                :columns="recalculateItem(item)"
                :config-data="configData"
                :config="config"
                :display="true"
              />
            </div>
          </template>
          <template v-else-if="cell.type === 'slot'">
            <!-- 插槽渲染222 -->
            <template
              v-if="slotComponents.includes(cell.slotType)"
            >
              <component
                :is="getComponentName(cell.slotConfig, cell.serviceName, cell.slotType)"
                :ref="(el) => setDynamicComponentRef(el, cell.slotRef || cellIndex)"
                :service-name="cell.serviceName"
                :server-name="cell.serviceName"
                :query-params-name="cell.slotConfig"
                :config-name="cell.slotConfig"
                :count-visible="false"
                :env="env"
                v-on="getEventHandlers(cell)"
                @mounted="(h) => onComponentMounted(h, cell, cellIndex)"
                @list-click="listClick"
              />
            </template>
          </template>
        </div>
      </VanCol>
    </template>
  </VanRow>
</template>

<style scoped lang="less">
.inputsDiv {
  display: flex;
  justify-content: space-between;

  .inputsDivItem {
    display: flex;
    align-items: center;
    padding: 0 4px;
    white-space: nowrap;

    .inputsDivItemLabel {
      padding: 0 4px;
    }
  }
}

.tdNoBorder {
  border: none;
  //border-left: 1px solid #000;
  //border-right: 1px solid #000;
  padding: 8px;
}
// 手机端显示边框线很奇怪 先去掉
.tdWithBorder {
  border: none;
  //border: 1px solid #000;
  padding: 8px;
}

.tdWithNoTopBorder {
  border: none;
  //border-top-style: none;
  //border-left: 1px solid #000;
  //border-right: 1px solid #000;
  //border-bottom: 1px solid #000;
  padding: 8px;
}

.flexItem {
  border-radius: 8px;
  height: 100%;
}
</style>
