// src/composables/useSearchFormLogic.js
import { ref, watch, computed, nextTick } 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
}

function getNestedValue(obj, path) {
  return path.split('.').reduce((current, key) => current?.[key], obj)
}

function isEqualShallow(a, b) {
  const keysA = Object.keys(a)
  const keysB = Object.keys(b)
  if (keysA.length !== keysB.length) return false
  for (let key of keysA) {
    if (a[key] !== b[key]) return false
  }
  return true
}

// ==================== 主逻辑 ====================
export function useSearchFormLogic(props, emit) {
  // === Refs ===
  const formRef = ref(null)
  const localModel = ref({ ...props.modelValue })
  const dictLoaded = ref(new Set())
  const internalConfig = ref([])
  const remoteOptions = ref({})
  const remoteLoading = ref({})

  // === Computed ===
  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
  })

  // === 模型同步 ===
  function syncModelFromProps(newModelValue, newConfig) {
    if (!newModelValue || !newConfig) return {}

    const synced = {}
    // 1. 主字段
    for (const item of newConfig) {
      const key = item.prop
      if (newModelValue.hasOwnProperty(key)) {
        synced[key] = newModelValue[key]
      } else if (item.multiple || ['checkbox-group', 'daterange'].includes(item.type)) {
        synced[key] = item.defaultValue ?? []
      } else {
        synced[key] = item.defaultValue ?? ''
      }
    }

    // 2. extra 字段（通过 options 反查）
    for (const item of newConfig) {
      const extraMap = item.onChangeExtraFields
      if (!extraMap || typeof extraMap !== 'object') continue

      const prop = item.prop
      const idValue = newModelValue[prop]

      let sourceObj = null
      if (idValue && typeof idValue === 'object') {
        sourceObj = idValue
      } else if (Array.isArray(item.options) && idValue !== undefined && idValue !== null) {
        const valueKey = item.valueKey || 'value'
        sourceObj = item.options.find(opt => opt[valueKey] === idValue)
      }

      if (sourceObj && typeof sourceObj === 'object') {
        for (const [targetKey, subPath] of Object.entries(extraMap)) {
          const val = getNestedValue(sourceObj, subPath)
          if (val !== undefined) synced[targetKey] = val
        }
      }
    }

    // 3. 保留 localModel 中的 extra（当 sourceField 未更新）
    for (const item of newConfig) {
      const sourceField = item.prop
      const extraMap = item.onChangeExtraFields
      if (!extraMap || typeof extraMap !== 'object') continue

      if (newModelValue[sourceField] === undefined) {
        for (const [targetKey, subPath] of Object.entries(extraMap)) {
          if (localModel.value.hasOwnProperty(targetKey)) {
            synced[targetKey] = localModel.value[targetKey]
          }
        }
      }
    }

    // 4. 保留其他字段
    for (const key in newModelValue) {
      if (synced.hasOwnProperty(key)) continue
      const isExtraTarget = newConfig.some(
        item => item.onChangeExtraFields && item.onChangeExtraFields.hasOwnProperty(key)
      )
      if (isExtraTarget || !newConfig.some(item => item.prop === key)) {
        synced[key] = newModelValue[key]
      }
    }

    return synced
  }

  // === Watchers ===
  watch(
    () => props.config,
    newConfig => {
      if (!newConfig || newConfig.length === 0) return
      internalConfig.value = deepCloneConfig(newConfig)
      localModel.value = syncModelFromProps(props.modelValue, internalConfig.value)
    },
    { immediate: true }
  )

  watch(
    () => props.modelValue,
    newVal => {
      if (!newVal || !internalConfig.value) return
      localModel.value = syncModelFromProps(newVal, internalConfig.value)
    },
    { deep: true }
  )

  // === 核心方法 ===
  function handleModelChange(value, item) {
    const newModel = { ...localModel.value, [item.prop]: value }

    if (item?.type === 'select' && item.onChangeExtraFields) {
      const options = getSelectOptions(item)
      const opt = options.find(o => o.value === value)
      if (opt?.raw) {
        for (const [targetProp, sourceKey] of Object.entries(item.onChangeExtraFields)) {
          newModel[targetProp] = opt.raw[sourceKey]
        }
      }
    }

    localModel.value = newModel

    nextTick(() => {
      if (!isEqualShallow(props.modelValue, newModel)) {
        emit('update:modelValue', newModel)
      }
    })

    if (item.type === 'select') {
      emit('selectChange', item.prop, value, item)
    } else if (item.type === 'upload') {
      emit('uploadSuccess', item.prop, newModel)
    }
  }

  function getSelectOptions(item) {
    const key = item.prop
    if (item.dictType || item.api) {
      return (remoteOptions.value[key] || []).map(opt => ({
        value: opt.value,
        label: opt.label,
        raw: opt.raw
      }))
    } else if (item.options) {
      return item.options.map(opt => ({
        value: opt.value,
        label: opt.label,
        raw: opt.raw
      }))
    }
    return []
  }

  function getDisabledDateFn(item) {
    const { minDate, maxDate } = item
    if (minDate == null && maxDate == null) return () => false
    return date => {
      const currentDate = dayjs(date).startOf('day')
      let minD = null, maxD = null
      if (minDate != null) {
        const val = typeof minDate === 'function' ? minDate(localModel.value) : minDate
        minD = parseToDate(val)
      }
      if (maxDate != null) {
        const val = typeof maxDate === 'function' ? maxDate(localModel.value) : maxDate
        maxD = parseToDate(val)
      }
      if (minD && currentDate.isBefore(minD)) return true
      if (maxD && currentDate.isAfter(maxD)) return true
      return false
    }
  }

  // === 远程加载 ===
  async function loadDictOptions(dictType) {
    const dictStore = useDictStore()
    let options = dictStore.getDict(dictType)
    if (options?.length) return options

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

  function markDictLoaded(prop) {
    dictLoaded.value.add(prop)
    if (props.modelValue?.[prop] !== undefined) {
      localModel.value[prop] = props.modelValue[prop]
    }
  }

  async function loadRemoteOptionsForInit(item) {
    const { prop, api, requestParams = {} } = item
    try {
      const res = await request({ url: api, method: 'post', data: requestParams })
      const list = typeof item.transform === 'function'
        ? item.transform(res)
        : res.data?.records || res.data || []
      remoteOptions.value[prop] = list.map(i => ({
        value: String(i[item.valueKey || 'value']),
        label: i[item.labelKey || 'label'],
        raw: i
      }))
      markDictLoaded(prop)
    } catch (err) {
      ElMessage.error(`预加载 ${item.label} 失败`)
      remoteOptions.value[prop] = []
    }
  }

  async function loadRemoteOptions(item) {
    const { prop, api } = item
    if (!api || remoteOptions.value[prop]?.length > 0) return
    try {
      remoteLoading.value[prop] = true
      const res = await request({ url: api, method: 'post', data: item.requestParams || {} })
      const list = typeof item.transform === 'function'
        ? item.transform(res)
        : res.data?.records || res.data || []
      remoteOptions.value[prop] = list.map(i => ({
        value: String(i[item.valueKey || 'value']),
        label: i[item.labelKey || 'label'],
        raw: i
      }))
      markDictLoaded(prop)
    } 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
        const res = await request({
          url: api,
          method: 'post',
          data: { ...(requestParams || {}), [keywordField]: keyword }
        })
        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'],
          raw: i
        }))
      } catch (err) {
        ElMessage.error(`搜索 ${item.label} 失败`)
      } finally {
        remoteLoading.value[prop] = false
      }
    }, debounceWait)
  }

  // === 初始化 ===
  async function init() {
    internalConfig.value = deepCloneConfig(props.config)
    const dictPromises = []
    const apiPromises = []

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

      if (item.type === 'select') {
        if (item.dictType) {
          dictPromises.push(loadDictOptions(item.dictType).then(opts => {
            remoteOptions.value[key] = opts
            markDictLoaded(key)
          }))
        } else if (item.api) {
          apiPromises.push(loadRemoteOptionsForInit(item))
        } else if (item.options) {
          remoteOptions.value[key] = [...item.options]
          markDictLoaded(key)
        }
      }
    }

    await Promise.allSettled([...dictPromises, ...apiPromises])
  }

  // === 暴露给 UI 和父组件 ===
  return {
    // refs
    formRef,
    localModel,
    // computed
    visibleConfig,
    formRules,
    // methods for FieldRenderer
    handleModelChange,
    getSelectOptions,
    getDisabledDateFn,
    loadRemoteOptions,
    handleFilterChange,
    remoteLoading,
    // exposed methods for parent
    getFormData: () => ({ ...localModel.value }),
    async validate() {
      return new Promise((resolve, reject) => {
        if (!formRef.value) return resolve(localModel.value)
        formRef.value.validate(valid => {
          valid ? resolve({ ...localModel.value }) : reject(new Error('Validation failed'))
        })
      })
    },
    resetForm() {
      const resetData = {}
      internalConfig.value.forEach(item => {
        const key = item.prop
        if (['checkbox-group', 'daterange'].includes(item.type) || item.multiple || item.type === 'upload') {
          resetData[key] = item.defaultValue ?? []
        } else {
          resetData[key] = item.defaultValue ?? ''
        }
      })
      localModel.value = { ...resetData }
      nextTick(() => formRef.value?.clearValidate())
    },
    // init
    init
  }
}