<template>
    <el-form ref="formRef" :model="localModel" :rules="formRules" label-width="auto" v-bind="$attrs">
        <el-row :gutter="20">
            <el-col v-for="item in visibleConfig" :key="item.prop" :span="item.span || 8">
                <el-form-item :label="item.label" :prop="item.prop" :class="{ 'search-form-item': isSearch }">
                    <!-- Input -->
                    <el-input v-if="item.type === 'input'" v-model="localModel[item.prop]"
                        :placeholder="item.placeholder || `请输入${item.label}`" :clearable="true"
                        @input="(val) => handleNumberInput(val, item)" />

                    <!-- Select (支持 dictType / api / options) -->
                    <el-select v-else-if="item.type === 'select'" v-model="localModel[item.prop]"
                        :multiple="!!item.multiple" :placeholder="item.placeholder || `请选择${item.label}`"
                        :clearable="true" filterable :loading="remoteLoading[item.prop] || false" @change="() => { }"
                        @focus="() => loadRemoteOptions(item)"
                        @filter-change="(keyword) => handleFilterChange(keyword, item)">
                        <el-option v-for="opt in getSelectOptions(item)" :key="opt.value" :label="opt.label"
                            :value="opt.value" />
                    </el-select>

                    <!-- Date -->
                    <el-date-picker v-else-if="item.type === 'date'" v-model="localModel[item.prop]" type="date"
                        :placeholder="`选择${item.label}`" value-format="YYYY-MM-DD" style="width: 100%"
                        :disabled-date="getDisabledDateFn(item)" @change="() => { }" />

                    <!-- Daterange -->
                    <el-date-picker v-else-if="item.type === 'daterange'" v-model="localModel[item.prop]"
                        type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
                        value-format="YYYY-MM-DD" :disabled-date="getDisabledDateFn(item)" style="width: 100%"
                        @change="() => { }" />

                    <!-- Checkbox Group -->
                    <el-checkbox-group v-else-if="item.type === 'checkbox-group'" v-model="localModel[item.prop]"
                        @change="() => { }">
                        <el-checkbox v-for="opt in getSelectOptions(item)" :key="opt.value" :label="opt.value">
                            {{ opt.label }}
                        </el-checkbox>
                    </el-checkbox-group>

                    <span v-else>Unsupported type: {{ item.type }}</span>
                </el-form-item>
            </el-col>
        </el-row>
    </el-form>
</template>

<script setup>
import { ref, watch, onMounted, nextTick, computed } from 'vue'
import { ElMessage } from 'element-plus'

// 🔑 引入你的字典方法
import useDictStore from '@/store/modules/dict'
import { getDicts } from '@/api/system/dict/data'
import request from '@/utils/request'
import dayjs from 'dayjs'
// ==================== 工具函数：深拷贝配置（保留函数） ====================
function deepCloneConfig(obj) {
    if (obj === null || typeof obj !== 'object') return obj
    if (Array.isArray(obj)) return obj.map(deepCloneConfig)
    const cloned = {}
    for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            const val = obj[key]
            cloned[key] = typeof val === 'function' ? val : deepCloneConfig(val)
        }
    }
    return cloned
}
function parseToDate(str) {
    if (!str) return null
    if (str === 'today') {
        return dayjs().startOf('day')
    }
    if (typeof str === 'string') {
        const d = dayjs(str)
        return d.isValid() ? d.startOf('day') : null
    }
    if (str instanceof Date) {
        return dayjs(str).startOf('day')
    }
    return null
}
// ==================== 生成 disabledDate 函数 ====================
function getDisabledDateFn(item) {
    const { minDate, maxDate } = item

    // 如果都没有限制，返回 null（不禁用任何日期）
    if (minDate == null && maxDate == null) {
        return () => false
    }

    return (date) => {
        const currentDate = dayjs(date).startOf('day')
        let minD = null
        let maxD = null

        // 解析最小日期
        if (minDate != null) {
            if (typeof minDate === 'function') {
                const val = minDate(localModel.value)
                minD = parseToDate(val)
            } else {
                minD = parseToDate(minDate)
            }
        }

        // 解析最大日期
        if (maxDate != null) {
            if (typeof maxDate === 'function') {
                const val = maxDate(localModel.value)
                maxD = parseToDate(val)
            } else {
                maxD = parseToDate(maxDate)
            }
        }

        // 判断是否被禁用
        if (minD && currentDate.isBefore(minD)) {
            return true
        }
        if (maxD && currentDate.isAfter(maxD)) {
            return true
        }
        return false
    }
}
// ==================== Props & Emits ====================
const props = defineProps({
    modelValue: { type: Object, default: () => ({}) },
    config: { type: Array, default: () => [] },
    isSearch: { type: Boolean, default: false }
})

const emit = defineEmits(['update:modelValue'])

// ==================== Refs ====================
const formRef = ref(null)
const localModel = ref({})
const internalConfig = ref([])
const remoteOptions = ref({}) // { prop: [options] }
const remoteLoading = ref({}) // { prop: boolean }

// ==================== 条件显隐 & 规则 ====================
const visibleConfig = computed(() => {
    return internalConfig.value.filter(item => {
        if (typeof item.visible === 'function') {
            return item.visible(localModel.value)
        }
        return true
    })
})

const formRules = computed(() => {
    const rules = {}
    visibleConfig.value.forEach(item => {
        if (item.rules) rules[item.prop] = item.rules
    })
    return rules
})

// ==================== 双向绑定 ====================
watch(() => props.modelValue, (newVal) => {
    if (newVal && typeof newVal === 'object') {
        localModel.value = { ...newVal }
    }
}, { immediate: true, deep: true })

watch(localModel, (newVal) => {
    if (props.modelValue !== undefined) {
        emit('update:modelValue', { ...newVal })
    }
}, { deep: true })

// ==================== 加载字典选项 ====================
async function loadDictOptions(dictType) {
    const dictStore = useDictStore()
    let options = dictStore.getDict(dictType)

    if (options && options.length > 0) {
        return options
    }

    try {
        const resp = await getDicts(dictType)
        options = resp.data.map(p => ({
            label: p.itemLabel,
            value: p.itemValue
        }))
        dictStore.setDict(dictType, options)
        return options
    } catch (err) {
        console.error(`加载字典 ${dictType} 失败`, err)
        ElMessage.error(`字典 ${dictType} 加载失败`)
        return []
    }
}

// ==================== 初始化 ====================
onMounted(async () => {
    internalConfig.value = deepCloneConfig(props.config)

    const initialData = {}
    const dictTypePromises = []

    for (const item of internalConfig.value) {
        const key = item.prop
        if (localModel.value[key] == null) {
            if (item.multiple) {
                initialData[key] = item.defaultValue ?? []
            } else if (['checkbox-group', 'daterange'].includes(item.type)) {
                initialData[key] = item.defaultValue ?? []
            } else {
                initialData[key] = item.defaultValue ?? ''
            }
        }

        // 预加载 dictType
        if (item.type === 'select' && item.dictType) {
            dictTypePromises.push(
                loadDictOptions(item.dictType).then(opts => {
                    remoteOptions.value[key] = opts
                })
            )
        } else if (item.type === 'select' && item.options) {
            remoteOptions.value[key] = [...item.options]
        }
        // api 类型：延迟加载（focus 时）
    }

    if (Object.keys(initialData).length > 0) {
        localModel.value = { ...localModel.value, ...initialData }
    }

    // 等待所有字典加载完成
    await Promise.allSettled(dictTypePromises)
})

// ==================== 获取 select 选项 ====================
function getSelectOptions(item) {
    return remoteOptions.value[item.prop] || []
}

// ==================== 加载远程 API 选项（首次 focus 时加载，无搜索词） ====================
async function loadRemoteOptions(item) {
    const { prop, api, requestParams = {}, keywordField, debounceWait, ...rest } = item
    if (!api || remoteOptions.value[prop]?.length > 0) return

    try {
        remoteLoading.value[prop] = true

        // 构造请求体：合并 requestParams + 分页（默认第一页）
        const payload = {
            ...(requestParams || {})
            // 注意：此时无 keyword，所以不加 keywordField
        }

        const res = await request({
            url: api,
            method: 'post', // ← 改为 POST
            data: payload   // ← 参数放 body
        })

        const list = typeof item.transform === 'function'
            ? item.transform(res)
            : res.data?.records || res.data || []

        remoteOptions.value[prop] = list.map(i => ({
            value: i[item.valueKey || 'value'],
            label: i[item.labelKey || 'label']
        }))
    } catch (err) {
        ElMessage.error(`加载 ${item.label} 失败`)
        remoteOptions.value[prop] = []
    } finally {
        remoteLoading.value[prop] = false
    }
}

// ==================== 远程搜索（带关键词，防抖） ====================
let searchTimeout = null
function handleFilterChange(keyword, item) {
    const { prop, api, requestParams = {}, keywordField = 'keyword', debounceWait = 300 } = item
    if (!api) return

    clearTimeout(searchTimeout)
    searchTimeout = setTimeout(async () => {
        try {
            remoteLoading.value[prop] = true

            // 构造请求体：requestParams + 分页 + 动态关键词字段
            const payload = {
                ...(requestParams || {}),
                [keywordField]: keyword // ← 动态字段名，如 name / companyName
            }

            const res = await request({
                url: api,
                method: 'post', // ← POST 请求
                data: payload   // ← body 传参
            })

            const list = typeof item.transform === 'function'
                ? item.transform(res)
                : res.data?.records || res.data || []

            remoteOptions.value[prop] = list.map(i => ({
                value: i[item.valueKey || 'value'],
                label: i[item.labelKey || 'label']
            }))
        } catch (err) {
            ElMessage.error(`搜索 ${item.label} 失败`)
        } finally {
            remoteLoading.value[prop] = false
        }
    }, debounceWait)
}

// ==================== 数字输入处理 ====================
function handleNumberInput(value, item) {
    const { inputType = 'text', decimalDigits = 2, prop } = item
    if (!prop) return

    let result = String(value ?? '').trim()

    if (inputType === 'integer') {
        result = result.replace(/[^\d]/g, '')
    } else if (inputType === 'decimal') {
        result = result.replace(/[^\d.]/g, '').replace(/^\./, '')
        const parts = result.split('.')
        if (parts.length > 2) {
            result = parts[0] + '.' + parts.slice(1).join('')
        }
        if (result.includes('.')) {
            const [intPart, decPart] = result.split('.')
            const trimmedDec = decPart.slice(0, decimalDigits)
            result = intPart + (trimmedDec ? '.' + trimmedDec : '')
            if (result.endsWith('.')) result = result.slice(0, -1)
        }
    }

    localModel.value = { ...localModel.value, [prop]: result }
}

// ==================== 暴露方法 ====================
defineExpose({
    getSearchParams() {
        return { ...localModel.value }
    },
    getFormData() {
        return { ...localModel.value }
    },
    async validate() {
        return new Promise((resolve, reject) => {
            formRef.value?.validate((valid) => {
                if (valid) resolve(localModel.value)
                else reject(new Error('Validation failed'))
            })
        })
    },
    resetForm() {
        const resetData = {}
        internalConfig.value.forEach(item => {
            const key = item.prop
            if (['checkbox-group', 'daterange'].includes(item.type)) {
                resetData[key] = item.defaultValue ?? []
            } else {
                resetData[key] = item.defaultValue ?? ''
            }
        })
        localModel.value = { ...resetData }
        nextTick(() => formRef.value?.clearValidate())
    }
})
</script>

<style scoped>
.search-form-item {
    margin-bottom: 20px;
}
</style>