import Vue from 'vue'

const findTarget = function(obj, prop) {
  let target = obj
  let targetProp = prop
  if (typeof prop === 'string') {
    const paths = prop.split('.')
    targetProp = paths.pop()
    for (const path of paths) {
      if (!obj[path]) {
        Vue.set(obj, path, createPathObject({}))
      }
      target = obj[path]
    }
  }
  return [target, targetProp]
}

function getAllKeys(obj, parent) {
  const result = []
  for (const key in obj) {
    const nextKey = (parent ? `${parent}.` : '') + key
    if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
      result.push(...getAllKeys(obj[key], nextKey))
    } else {
      result.push(nextKey)
    }
  }
  return result
}

export function createPathObject(originObject) {
  originObject = originObject || {}
  return originObject._isPathObject ? originObject : new Proxy(originObject, {
    set: (obj, prop, value) => {
      const [target, targetProp] = findTarget(obj, prop)
      Vue.set(target, targetProp, value)
      return true
    },
    get: (obj, prop) => {
      if (prop === '_isPathObject') {
        return true
      }
      if (prop === '_pathKeys') {
        return getAllKeys(obj)
      }
      const [target, targetProp] = findTarget(obj, prop)
      return target[targetProp]
    },
    has: (obj, prop) => {
      const [target, targetProp] = findTarget(obj, prop)
      return targetProp in target
    },
    deleteProperty: (obj, prop) => {
      const [target, targetProp] = findTarget(obj, prop)
      Vue.delete(target, targetProp)
      return true
    }
  })
}

export function assignPathObject(target, ...args) {
  const pathObjectTarget = createPathObject(target)
  for (const obj of args) {
    const pathObj = createPathObject(obj)
    for (const key of pathObj._pathKeys) {
      pathObjectTarget[key] = pathObj[key]
    }
  }
  return pathObjectTarget
}

/**
 * 格式化时间
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string}
 */
export function parseDate(time, format = 'yyyy-MM-dd hh:mm:ss') {
  const date = time instanceof Date ? time : new Date(time)
  if (isNaN(date.valueOf())) {
    return ''
  }
  const o = {
    'M+': date.getMonth() + 1, // 月份
    'd+': date.getDate(), // 日
    'h+': date.getHours(), // 小时
    'H+': date.getHours(), // 小时
    'm+': date.getMinutes(), // 分
    's+': date.getSeconds(), // 秒
    'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
    'S': date.getMilliseconds() // 毫秒
  }
  if (/(y+)/.test(format)) {
    format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
  }
  for (const k in o) {
    if (new RegExp('(' + k + ')').test(format)) {
      format = format.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
    }
  }
  if (/CN/.test(format)) {
    format = format.replace('CN', () => {
      const now = Date.now()
      const diff = (now - date) / 1000
      if (diff < 30) {
        return '刚刚'
      } else if (diff < 3600) {
        // less 1 hour
        return Math.ceil(diff / 60) + '分钟前'
      } else if (diff < 3600 * 24) {
        return Math.ceil(diff / 3600) + '小时前'
      } else if (diff < 3600 * 24 * 2) {
        return '1天前'
      }
    })
  }
  return format
}

const warningMap = new Set()
export function showWarning(text) {
  if (!warningMap.has(text)) {
    console.warn(`[EasyComponent]${text}`)
    warningMap.add(text)
  }
}

/**
 *
 * @param {*} options
 * @param {*} predicate
 * @param {*} deepLimit 往下查找深度限制 1表示仅在顶层查找
 * @returns
 */
export function findDeepOption(options, predicate, deepLimit) {
  for (const item of options) {
    if (predicate(item)) {
      return item
    }
    if (typeof deepLimit === 'number') {
      deepLimit = deepLimit - 1
    }
    if (Array.isArray(item.children) && (typeof deepLimit !== 'number' || deepLimit > 0)) {
      const child = findDeepOption(item.children, predicate, deepLimit)
      if (child) {
        return child
      }
    }
  }
}

export function findDeepOptionIndex(options, predicate, scopeData = { index: -1 }) {
  for (const item of options) {
    scopeData.index++
    if (predicate(item)) {
      return scopeData.index
    }
    if (Array.isArray(item.children)) {
      const childIndex = findDeepOptionIndex(item.children, predicate, scopeData)
      if (childIndex > -1) {
        return childIndex
      }
    }
  }
  return -1
}

export function filterDeepOption(options, predicate, arr = []) {
  for (const item of options) {
    if (predicate(item)) {
      arr.push(item)
    }
    if (Array.isArray(item.children)) {
      filterDeepOption(item.children, predicate, arr)
    }
  }
  return arr
}

export function JSONStringify(obj) {
  return JSON.stringify(obj, (key, value) => {
    if (typeof value === 'function') {
      return value.toString()
    }
    return value
  })
}

export function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj
  }
  if (obj instanceof File) {
    return obj
  }
  if (Array.isArray(obj)) {
    const newArr = []
    for (const item of obj) {
      newArr.push(deepClone(item))
    }
    return newArr
  }
  const newObj = {}
  for (const key in obj) {
    if (typeof obj[key] === 'object') {
      newObj[key] = deepClone(obj[key])
    } else {
      newObj[key] = obj[key]
    }
  }
  return newObj
}

/**
 * 取第一个不为undefined的值
 */
export function getValueByLevel(...args) {
  for (const value of args) {
    if (value !== undefined) {
      return value
    }
  }
  return undefined
}
