/**
 * selectValueType 功能辅助工具
 * 用于处理表单选择组件的值存储模式转换

 * todo 移除 processLabelMode processBothMode 抽象逻辑 仅采用 processExtFieldData
 * 需要根据配置查询使用配置，检查前端版本，检查配置使用公司
 */

/**
 * 根据selectValueType预处理options数据
 * @param {Array} options - 原始选项数据
 * @param {String} selectValueType - 值存储类型：'value' | 'label' | 'both'
 * @returns {Array} 处理后的选项数据
 */
export function processOptionsForValueType (options, selectValueType = 'value') {
  // value模式：不做任何改变，保持现有逻辑
  if (selectValueType === 'value') {
    return options
  }

  // label模式：交换value和label，保存原始value到originValue
  if (selectValueType === 'label') {
    return processOptionsForLabelType(options)
  }

  // both模式：不处理options
  return options
}

/**
 * 处理label模式的options数据转换
 * @param {Array} options - 原始选项数据
 * @returns {Array} 转换后的选项数据
 */
export function processOptionsForLabelType (options) {
  if (!Array.isArray(options)) {
    return options
  }

  return options.map(item => {
    // 先创建基础的转换对象
    const transformedItem = { ...item }

    // 仅处理标准格式 {value, label}
    if (item.value !== undefined && item.label !== undefined) {
      transformedItem.originValue = item.value
      transformedItem.value = item.label
    }

    // 处理树形结构（递归处理children）
    if (item.children && Array.isArray(item.children)) {
      transformedItem.children = processOptionsForLabelType(item.children)
    }

    return transformedItem
  })
}

/**
 * 根据value查找对应的label（支持单选和多选）
 * @param {any} value - 要查找的值
 * @param {Array} options - 选项数据
 * @returns {String|Array|null} 对应的label值，找不到时返回null
 */
export function findLabelByValue (value, options) {
  if (value === undefined || value === null) {
    return null
  }

  // 多选情况：value是数组
  if (Array.isArray(value)) {
    const labels = []
    for (const val of value) {
      const label = findSingleLabelByValue(val, options)
      if (label !== null) {
        labels.push(label)
      }
    }
    return labels.length > 0 ? labels : null
  }

  // 单选情况：value是单个值
  return findSingleLabelByValue(value, options)
}

/**
 * 根据value查找完整的option对象（支持树形结构递归查找）
 * @param {any} value - 要查找的值
 * @param {Array} options - 选项数据
 * @returns {Object|null} 完整的option对象，找不到时返回null
 */
export function findOptionByValue (value, options) {
  if (!Array.isArray(options)) {
    return null
  }

  for (const item of options) {
    // 仅处理标准格式 {value, label}
    if (item.value !== undefined && String(item.value) === String(value)) {
      return item
    }

    // 递归查找树形结构
    if (item.children && Array.isArray(item.children)) {
      const childOption = findOptionByValue(value, item.children)
      if (childOption !== null) {
        return childOption
      }
    }
  }

  return null
}

/**
 * 在选项数据中查找单个value对应的label（支持树形结构递归查找）
 * @param {any} value - 要查找的值
 * @param {Array} options - 选项数据
 * @returns {String} 对应的label值，找不到时返回String(value)作为fallback
 */
export function findSingleLabelByValue (value, options) {
  const option = findOptionByValue(value, options)
  if (option !== null) {
    return option.label || String(value)
  }
  return String(value)
}

/**
 * 处理 label 模式数据存储
 * @param {Object} form - 表单对象
 * @param {String} fieldName - 字段名
 * @param {any} currentValue - 当前值
 * @param {Array} options - 选项数据
 * @param {Function} setFieldValue - Vue的$set方法
 */
export function processLabelModeData (form, fieldName, currentValue, options, setFieldValue) {
  // 确保 originData 对象存在
  if (!form.originData) {
    setFieldValue(form, 'originData', {})
  }

  // 获取当前值对应的原始值
  const originValue = getOriginValue(currentValue, options)

  // 存储原始值到 originData 中
  setFieldValue(form.originData, fieldName, originValue)
}

/**
 * 处理 both 模式数据存储
 * @param {Object} form - 表单对象
 * @param {String} fieldName - 字段名
 * @param {any} currentValue - 当前值
 * @param {Array} options - 选项数据
 * @param {Function} setFieldValue - Vue的$set方法
 */
export function processBothModeData (form, fieldName, currentValue, options, setFieldValue) {
  // 确保 labelData 对象存在
  if (!form.labelData) {
    setFieldValue(form, 'labelData', {})
  }

  // 获取当前值对应的标签值
  const labelValue = findLabelByValue(currentValue, options)

  // 存储标签值到 labelData 中
  if (labelValue !== null && labelValue !== undefined) {
    setFieldValue(form.labelData, fieldName, labelValue)
  }
}


/**
 * 处理 扩展数据 模式数据存储
 * @param {Object} form - 表单对象
 * @param {String} fieldName - 字段名
 * @param {any} currentValue - 当前值
 * @param {Array} options - 选项数据
 * @param {Function} setFieldValue - Vue的$set方法
 */
export function processExtFieldData (form, fieldName, currentValue, options, setFieldValue) {
  // 边界条件检查
  if (currentValue === undefined || currentValue === null || !Array.isArray(options)) {
    return
  }

  // 多选场景：不处理ext字段
  if (Array.isArray(currentValue)) {
    return
  }

  // 单选场景：查找对应的option
  const option = findOptionByValue(currentValue, options)
  // 如果找到option且有ext对象
  if (option && option.ext && typeof option.ext === 'object') {
    // 将ext中的每个字段赋值到form中
    Object.keys(option.ext).forEach(key => {
      setFieldValue(form, key, option.ext[key])
    })
  }
}

/**
 * 获取原始值（用于label模式时获取originValue）
 * @param {any} currentValue - 当前值
 * @param {Array} options - 选项数据
 * @returns {any} 原始值，找不到时返回currentValue作为fallback
 */
export function getOriginValue (currentValue, options) {
  if (!Array.isArray(options) || currentValue === undefined || currentValue === null) {
    return currentValue
  }

  // 多选情况
  if (Array.isArray(currentValue)) {
    const originValues = []
    for (const val of currentValue) {
      const originVal = findOriginValueByLabel(val, options)
      // 只有找到真正的原始值时才使用originVal（不是fallback值）
      if (originVal !== val) {
        originValues.push(originVal)
      } else {
        // 如果没找到原始值，保留当前值
        originValues.push(val)
      }
    }
    return originValues
  }

  // 单选情况
  return findOriginValueByLabel(currentValue, options)
}

/**
 * 根据label查找原始value值
 * @param {any} label - 标签值
 * @param {Array} options - 选项数据
 * @returns {any} 原始值，找不到时返回label作为fallback
 */
function findOriginValueByLabel (label, options) {
  for (const item of options) {
    // 如果有originValue，说明是经过label模式转换的
    if (item.originValue !== undefined && String(item.value) === String(label)) {
      return item.originValue
    }

    // 递归查找树形结构
    if (item.children && Array.isArray(item.children) && item.children.length > 0) {
      const childOriginValue = findOriginValueByLabel(label, item.children)
      // 只有当找到真正的匹配项时才返回（不等于传入的label）
      if (childOriginValue !== label) {
        return childOriginValue
      }
    }
  }

  return label // 如果找不到，返回原值
}

/**
 * 创建selectValueType处理器的工厂函数
 * @param {Object} context - Vue组件上下文
 * @returns {Object} 处理器对象
 */
export function createSelectValueTypeHandler (context) {
  return {
    // 预处理options数据
    processOptions (options, selectValueType) {
      return processOptionsForValueType(options, selectValueType)
    },

    // 查找label值
    findLabel (value, options) {
      return findLabelByValue(value, options)
    },

    // 处理both模式数据（自动从context获取参数）
    processBothMode () {
      const form = context.form
      const fieldName = context.attr.model
      const currentValue = form[fieldName]
      const options = context.option
      return processBothModeData(form, fieldName, currentValue, options, context.$set)
    },

    // 处理label模式数据（自动从context获取参数）
    processLabelMode () {
      const form = context.form
      const fieldName = context.attr.model
      const currentValue = form[fieldName]
      const options = context.option
      return processLabelModeData(form, fieldName, currentValue, options, context.$set)
    },

    // 处理选项 options 中的扩展字段（自动从context获取参数）
    // options: [{label,value, ext: {}}] 选中节点之后 ext 中的数据会被赋值进去
    // 但是此操作要求 ext 为空时字段必须存在 比如 {a: null}, 不能是 {}
    processExtField () {
      const form = context.form
      const fieldName = context.attr.model
      const currentValue = form[fieldName]
      const options = context.option
      return processExtFieldData(form, fieldName, currentValue, options, context.$set)
    },

    // 获取原始值
    getOriginValue (currentValue, options) {
      return getOriginValue(currentValue, options)
    }
  }
}

export default {
  processOptionsForValueType,
  findLabelByValue,
  processLabelModeData,
  processBothModeData,
  getOriginValue
}
