<template>
  <el-form-item
    v-if="shouldRender"
    v-show="shouldShow"
    :prop="schema.field"
    :required="schema.required"
    :rules="effectiveRules"
    :label-width="schema.labelWidth"
  >
    <template slot="label">
      <span>
        {{ schema.label }}<span v-if="showColon" class="ecp-pro-form-item__colon">:</span>
      </span>
      <el-tooltip
        v-if="schema.helpMessage"
        placement="top"
        effect="light"
        v-bind="schema.helpComponentProps || {}"
      >
        <template slot="content">
          <template v-if="Array.isArray(schema.helpMessage)">
            <div v-for="(msg, i) in schema.helpMessage" :key="i" class="ecp-pro-form-item__help-item">
              {{ msg }}
            </div>
          </template>
          <span v-else>{{ schema.helpMessage }}</span>
        </template>
        <i class="el-icon-question ecp-pro-form-item__help-icon" />
      </el-tooltip>
    </template>
    <!-- render 自定义渲染 -->
    <template v-if="schema.render">
      <component :is="renderComponent" />
    </template>
    <!-- slot 自定义插槽（由 ProForm 传入 default slot） -->
    <slot v-else-if="hasSlot" :model="formModel" :schema="schema" :field="schema.field" :values="formModel" />
    <!-- 默认组件渲染 -->
    <template v-else>
      <!-- 自定义 component：组件名或内联组件 -->
      <component :is="fieldWrapperComponent" v-bind="fieldWrapperProps">
        <component
          v-if="resolvedCustomComponent"
          :is="resolvedCustomComponent"
          :value="formModel[schema.field]"
          @input="setFieldValue"
          :placeholder="schema.placeholder || (autoPlaceholder ? `请输入${schema.label}` : undefined)"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
        />
        <el-input
          v-else-if="schema.component === 'input' || !schema.component"
          v-model="formModel[schema.field]"
          :placeholder="schema.placeholder || (autoPlaceholder ? `请输入${schema.label}` : undefined)"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
        />
        <el-input-number
          v-else-if="schema.component === 'input-number'"
          v-model="formModel[schema.field]"
          :placeholder="schema.placeholder"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
        />
        <FormattedNumberInput
          v-else-if="schema.component === 'formatted-number'"
          :value="formModel[schema.field]"
          :placeholder="schema.placeholder || (autoPlaceholder ? `请输入${schema.label}` : undefined)"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
          @input="setFieldValue"
        />
        <el-select
          class="ecp-pro-form-item__select"
          v-else-if="schema.component === 'select'"
          v-model="formModel[schema.field]"
          :placeholder="schema.placeholder || (autoPlaceholder ? `请选择${schema.label}` : undefined)"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
        >
          <el-option
            v-for="opt in (getOptions(effectiveComponentProps) || [])"
            :key="String(opt.value)"
            :label="opt.label"
            :value="opt.value"
          />
        </el-select>
        <ApiSelect
          v-else-if="schema.component === 'api-select'"
          ref="apiSelectRef"
          :value="formModel[schema.field]"
          :placeholder="schema.placeholder || (autoPlaceholder ? `请选择${schema.label}` : undefined)"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
          @input="setFieldValue"
        />
        <TreeSelect
          v-else-if="schema.component === 'tree-select'"
          :value="formModel[schema.field]"
          :placeholder="schema.placeholder || (autoPlaceholder ? `请选择${schema.label}` : undefined)"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
          @input="setFieldValue"
        />
        <el-date-picker
          v-else-if="schema.component === 'date-picker'"
          v-model="formModel[schema.field]"
          :placeholder="schema.placeholder || (autoPlaceholder ? `请选择${schema.label}` : undefined)"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
        />
        <el-date-picker
          v-else-if="schema.component === 'date-range'"
          v-model="formModel[schema.field]"
          type="daterange"
          range-separator="至"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
          value-format="yyyy-MM-dd"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
        />
        <el-switch
          v-else-if="schema.component === 'switch'"
          v-model="formModel[schema.field]"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
        />
        <el-cascader
          v-else-if="schema.component === 'cascader'"
          v-model="formModel[schema.field]"
          :placeholder="schema.placeholder || (autoPlaceholder ? `请选择${schema.label}` : undefined)"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
        />
        <el-checkbox-group
          v-else-if="schema.component === 'checkbox'"
          v-model="formModel[schema.field]"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
        >
          <el-checkbox
            v-for="opt in (getOptions(effectiveComponentProps) || [])"
            :key="String(opt.value)"
            :label="opt.value"
          >
            {{ opt.label }}
          </el-checkbox>
        </el-checkbox-group>
        <el-radio-group
          v-else-if="schema.component === 'radio'"
          v-model="formModel[schema.field]"
          v-bind="effectiveComponentProps"
          v-on="effectiveComponentListeners"
        >
          <el-radio
            v-for="opt in (getOptions(effectiveComponentProps) || [])"
            :key="String(opt.value)"
            :label="opt.value"
          >
            {{ opt.label }}
          </el-radio>
        </el-radio-group>
      </component>
    </template>
  </el-form-item>
</template>

<script setup lang="ts">
import { computed, useSlots, h, ref, onMounted, onUnmounted } from 'vue'
import ApiSelect from './ApiSelect.vue'
import FormattedNumberInput from './FormattedNumberInput.vue'
import TreeSelect from './TreeSelect.vue'
import type { ProFormSchema, RenderCallbackParams } from '../types'
import { normalizeTooltipConfig } from '../utils/tooltip'

const BUILT_IN_COMPONENTS: Set<string> = new Set([
  'input', 'select', 'api-select', 'tree-select', 'date-picker', 'date-range', 'input-number',
  'formatted-number',
  'switch', 'cascader', 'checkbox', 'radio',
])

const props = defineProps<{
  schema: ProFormSchema
  formModel: Record<string, unknown>
  formDisabled?: boolean
  autoPlaceholder?: boolean
  colon?: boolean
  formActionType?: import('../types').FormActionType
  onFieldChange?: (field: string, value: unknown) => void
  /** 自定义组件映射（由 ProForm 传入） */
  customComponents?: Record<string, unknown>
  /** 注册字段实例（由 ProForm 传入） */
  registerFieldInstance?: (field: string, instance: Record<string, unknown> | null) => void
}>()

/** ApiSelect 组件实例 ref */
const apiSelectRef = ref<Record<string, unknown> | null>(null)

onMounted(() => {
  if (props.schema.component === 'api-select') {
    props.registerFieldInstance?.(props.schema.field, apiSelectRef.value)
  }
})

onUnmounted(() => {
  if (props.schema.component === 'api-select') {
    props.registerFieldInstance?.(props.schema.field, null)
  }
})

const slots = useSlots()

const renderParams = computed<RenderCallbackParams>(() => ({
  schema: props.schema,
  values: props.formModel,
  model: props.formModel,
  field: props.schema.field,
}))

const shouldRender = computed(() => {
  const ifShow = props.schema.ifShow
  if (ifShow === undefined) return true
  if (typeof ifShow === 'boolean') return ifShow
  return ifShow(renderParams.value)
})

const shouldShow = computed(() => {
  const show = props.schema.show
  if (show === undefined) return true
  if (typeof show === 'boolean') return show
  return show(renderParams.value)
})

// const effectiveDisabled = computed(() => {
//   if (props.formDisabled) return true
//   const dyn = props.schema.dynamicDisabled
//   if (dyn === undefined) return false
//   if (typeof dyn === 'boolean') return dyn
//   return dyn(renderParams.value)
// })

const effectiveRules = computed(() => {
  const dyn = props.schema.dynamicRules
  if (!dyn) return props.schema.rules
  if (Array.isArray(dyn)) return dyn
  return dyn(renderParams.value)
})

const effectiveComponentPropsAndListeners = computed(() => {
  const cp = props.schema.componentProps
  const dyn = getDynamicDisabled()
  let dynProps = {}
  if (dyn) {
    dynProps = {
      disabled: dyn,
    }
  }
  if (!cp) return { props: {}, listeners: {} }
  let raw = typeof cp === 'function'
    ? cp({
        ...renderParams.value,
        formActionType: props.formActionType,
      })
    : { ...cp }
  raw = { ...raw, ...dynProps }
  const propsOnly: Record<string, unknown> = {}
  const listeners: Record<string, (...args: unknown[]) => unknown> = {}
  for (const [key, value] of Object.entries(raw)) {
    if (key.length > 2 && /^on[A-Za-z]/.test(key) && typeof value === 'function') {
      const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3)
      listeners[eventName] = value as (...args: unknown[]) => unknown
    } else {
      propsOnly[key] = value
    }
  }
  return { props: propsOnly, listeners }
})

const effectiveComponentProps = computed(() => effectiveComponentPropsAndListeners.value.props)
const effectiveComponentListeners = computed(() => effectiveComponentPropsAndListeners.value.listeners)
const showColon = computed(() => props.schema.colon ?? props.colon ?? false)

const normalizedTooltip = computed(() => {
  const tooltip = props.schema.tooltip
  if (!tooltip) return null
  const resolved = typeof tooltip === 'function' ? tooltip(renderParams.value) : tooltip
  return normalizeTooltipConfig(resolved, props.formModel[props.schema.field])
})

const fieldWrapperComponent = computed(() => normalizedTooltip.value ? 'el-tooltip' : 'span')
const fieldWrapperProps = computed(() => normalizedTooltip.value || {})

const hasSlot = computed(() => !!slots.default)

const getOptions = (props: Record<string, unknown>): Array<{ label: string; value: unknown }> | undefined => {
  const opts = props?.options
  return Array.isArray(opts) ? opts : undefined
}

const resolvedCustomComponent = computed(() => {
  const c = props.schema.component
  if (c == null) return null
  if (typeof c === 'string') {
    if (BUILT_IN_COMPONENTS.has(c)) return null
    return (props.customComponents && props.customComponents[c]) || c
  }
  return c
})

const setFieldValue = (v: unknown) => {
  props.onFieldChange?.(props.schema.field, v)
}

const renderComponent = computed(() => {
  const renderFn = props.schema.render
  if (!renderFn) return null
  return {
    render() {
      const result = renderFn(renderParams.value)
      if (Array.isArray(result)) {
        return h('span', result)
      }
      return result
    },
  }
})
function getDynamicDisabled(): boolean {
  if (props.formDisabled) return true
  const dyn = props.schema.dynamicDisabled
  if (dyn === undefined) return false
  if (typeof dyn === 'boolean') return dyn
  return dyn(renderParams.value)
}
</script>

<style>
.ecp-pro-form-item__colon {
  margin-right: 2px;
}

.ecp-pro-form-item__help-icon {
  margin-left: 4px;
  color: #909399;
  cursor: help;
  font-size: 14px;
}
.ecp-pro-form-item__help-icon:hover {
  color: #409eff;
}
.ecp-pro-form-item__help-item {
  margin-bottom: 4px;
}
.ecp-pro-form-item__help-item:last-child {
  margin-bottom: 0;
}
</style>
