<template>
  <!-- select -->
  <el-select
    v-if="col.component === 'select'"
    :value="value"
    v-bind="cellBind"
    :placeholder="cellBind.placeholder || placeholder"
    v-on="mergedEvents('change', 'clear')"
  >
    <el-option
      v-for="opt in options"
      :key="String(opt.value)"
      :label="opt.label"
      :value="opt.value"
    />
  </el-select>
  <!-- checkbox-group -->
  <el-checkbox-group
    v-else-if="col.component === 'checkbox'"
    :value="value"
    v-bind="cellBind"
    v-on="mergedEvents('change')"
  >
    <el-checkbox
      v-for="opt in options"
      :key="String(opt.value)"
      :label="opt.value"
    >{{ opt.label }}</el-checkbox>
  </el-checkbox-group>
  <!-- radio-group -->
  <el-radio-group
    v-else-if="col.component === 'radio'"
    :value="value"
    v-bind="cellBind"
    v-on="mergedEvents('change')"
  >
    <el-radio
      v-for="opt in options"
      :key="String(opt.value)"
      :label="opt.value"
    >{{ opt.label }}</el-radio>
  </el-radio-group>
  <!-- date-range -->
  <el-date-picker
    v-else-if="col.component === 'date-range'"
    :value="value"
    type="daterange"
    range-separator="至"
    start-placeholder="开始日期"
    end-placeholder="结束日期"
    value-format="yyyy-MM-dd"
    v-bind="cellBind"
    :placeholder="cellBind.placeholder || placeholder"
    v-on="mergedEvents('change')"
  />
  <!-- api-select -->
  <ApiSelect
    v-else-if="col.component === 'api-select'"
    :value="value"
    v-bind="cellBind"
    :placeholder="cellBind.placeholder || placeholder"
    v-on="mergedEvents('change')"
  />
  <!-- tree-select -->
  <TreeSelect
    v-else-if="col.component === 'tree-select'"
    :value="value"
    v-bind="cellBind"
    :placeholder="cellBind.placeholder || placeholder"
    v-on="mergedEvents('change')"
  />
  <!-- 其余 el-* 组件（input / input-number / formatted-number / date-picker / switch / cascader） -->
  <component
    v-else
    :is="cellComp"
    :value="value"
    v-bind="cellBind"
    :placeholder="cellBind.placeholder || placeholder"
    v-on="mergedEvents('input', 'change')"
  />
</template>

<script setup lang="ts">
import { computed, nextTick } from 'vue'
import ApiSelect from '../ProForm/ApiSelect.vue'
import TreeSelect from '../ProForm/TreeSelect.vue'
import FormattedNumberInput from '../ProForm/FormattedNumberInput.vue'
import type { ProTableFormColumn, ProTableFormColumnChild, ProTableFormActionType } from '../types'

const props = defineProps<{
  col: ProTableFormColumn | ProTableFormColumnChild
  value: unknown
  /** 当前行数据，用于 componentProps 动态求值 */
  row?: Record<string, unknown>
  /** 当前行索引 */
  index?: number
  size?: 'medium' | 'small' | 'large'
  placeholder?: string
  /** ProTableForm 操作实例 */
  formActionType?: ProTableFormActionType
}>()

const emit = defineEmits<{ (e: 'update', v: unknown): void }>()

const options = computed<Array<{ label: string; value: unknown }>>(() => {
  const staticProps = typeof props.col.componentProps === 'function'
    ? {} : (props.col.componentProps ?? {})
  const opts = staticProps.options
  return Array.isArray(opts) ? opts : []
})

const cellComp = computed(() => {
  const map: Record<string, string> = {
    'input': 'el-input',
    'input-number': 'el-input-number',
    'date-picker': 'el-date-picker',
    'switch': 'el-switch',
    'cascader': 'el-cascader',
  }
  if (props.col.component === 'formatted-number') return FormattedNumberInput
  return map[props.col.component as string] || 'el-input'
})

/**
 * componentProps 求值结果缓存（仅在 props 变化时重新计算）。
 * cellBind 和 cellEvents 都从同一个缓存中读取，保证求值只发生一次，
 * 避免同一渲染周期中生成两份不同的 handler 闭包导致双重触发。
 */
const componentPropsResult = computed<{
  bind: Record<string, unknown>
  /** 用户 componentProps 中的事件处理器（onXxx → xxx），尚未与 emit 合并 */
  userEvents: Record<string, (...args: unknown[]) => unknown>
}>(() => {
  let raw: Record<string, unknown> = {}

  if (typeof props.col.componentProps === 'function') {
    const row = props.row ?? {} as Record<string, unknown>
    const formActionType = props.formActionType as ProTableFormActionType
    raw = props.col.componentProps({
      row,
      value: props.value,
      index: props.index,
      column: props.col as never,
      formActionType,
    })
  } else {
    raw = props.col.componentProps ?? {}
  }

  const bind: Record<string, unknown> = {}
  const userEvents: Record<string, (...args: unknown[]) => unknown> = {}

  for (const [key, val] of Object.entries(raw)) {
    if (/^on[A-Za-z]/.test(key) && typeof val === 'function') {
      const eventName = key[2].toLowerCase() + key.slice(3)
      userEvents[eventName] = val as (...args: unknown[]) => unknown
    } else {
      bind[key] = val
    }
  }

  return { bind, userEvents }
})

/** v-bind 的属性（排除 onXxx 事件） */
const cellBind = computed<Record<string, unknown>>(() => {
  void props.value  // 追踪响应式
  void props.row    // 追踪响应式
  void props.formActionType // 追踪响应式

  const base: Record<string, unknown> = { size: props.size, ...componentPropsResult.value.bind }
  if (props.col.component === 'formatted-number') {
    return { integerDigits: 5, decimalPlaces: 6, rounding: 'round', inputLimit: true, ...base }
  }
  if (['select', 'checkbox', 'radio'].includes(props.col.component as string)) {
    const { options: _opts, ...rest } = base
    void _opts
    return rest
  }
  return base
})

/** componentProps 中的事件处理器（onXxx → xxx） */
const cellEvents = computed<Record<string, (...args: unknown[]) => unknown>>(() => {
  void props.value  // 追踪响应式
  void props.row    // 追踪响应式
  void props.formActionType // 追踪响应式
  return componentPropsResult.value.userEvents
})

/**
 * 合并 cellEvents 与内部 emit('update')。
 * componentProps 的 handler 先执行（可调用 formActionType.setModelValue 做联动），再 emit('update') 更新行值。
 * clear 事件特殊处理：用户 handler 先执行，再 emit(undefined) 清空值。
 */
const mergedEvents = (...internalEvents: Array<'input' | 'change' | 'clear'>) => {
  const handlers: Record<string, (...args: unknown[]) => void> = {}
  for (const internalEvent of internalEvents) {
    const userHandler = cellEvents.value[internalEvent]
    handlers[internalEvent] = (arg: unknown) => {
      // if (userHandler) userHandler(arg)
      emit('update', internalEvent === 'clear' ? undefined : arg)
      nextTick(()=>{
        if (userHandler) userHandler(arg)
      })
    }
  }
  return handlers
}
</script>
