import {
  EInfinityString,
  ETypeStrings,
  LeFE_Prefix,
  Segment,
  UndefinedReplacer
} from './defines'
import {
  isArray,
  isDate,
  isMap,
  isObject,
  isSet,
  isString
} from './type_detectors'

const parseReplaceString = (str: string) => {
  // 由于 dataString 里可能还有 Segment，这里的意思是只取前两个，剩下的，还给拼起来，留着下面用
  const [, type, ...dataStringArr] = str.split(Segment)
  const dataString = dataStringArr.join(Segment)
  return {
    type,
    dataString
  }
}

const stringParse = (str: string, parse: (json: string) => any) => {
  if (str.startsWith(LeFE_Prefix)) {
    const { type, dataString } = parseReplaceString(str)
    switch (type) {
      // undefined 比较坑，这里不处理，最后遍历统一处理
      // case ETypeStrings.undefined:
      //   return undefined
      case ETypeStrings.Infinity:
        return dataString === EInfinityString.positive ? Infinity : -Infinity
      case ETypeStrings.NaN:
        return NaN
      case ETypeStrings.BigInt:
        try {
          return BigInt(dataString)
        } catch (error) {
          console.error(error)
          return BigInt(0)
        }
      case ETypeStrings.Symbol:
        return Symbol(dataString)
      case ETypeStrings.Function:
        try {
          return Function(`return ${dataString}`)()
        } catch (error) {
          console.error(error)
          return function placeholder() {
            console.warn('注意！该函数在 JSON 解析时出现错误。')
          }
        }
      case ETypeStrings.Date:
        return new Date(Number(dataString))
      case ETypeStrings.Set:
        try {
          return new Set(parse(dataString))
        } catch (error) {
          console.error(error)
          return new Set()
        }
      case ETypeStrings.Map:
        try {
          return new Map(parse(dataString))
        } catch (error) {
          console.error(error)
          return new Map()
        }
      default:
        return str
    }
  } else {
    /* Start: 老 Function 逻辑兼容 */
    if (str.startsWith('function')) {
      try {
        return Function(`return ${str}`)()
      } catch (error) {
        console.error(error)
        return function placeholder() {
          console.warn('注意！该函数在 JSON 解析时出现错误。')
        }
      }
    }
    /* End: 老 Function 逻辑兼容 */
    return str
  }
}

const isTypesNeededTraverse = (
  val: unknown
): val is unknown[] | Record<string, unknown> =>
  (isObject(val) && !isDate(val) && !isSet(val) && !isMap(val)) || isArray(val)

const needNotTraverseHandler = (val: unknown) =>
  isString(val)
    ? stringParse(val, parse)
    : // 在无需遍历的类型中，除了 string 就是 boolean, number, null, 直接返回
      val

const undefinedHandler = (
  val: unknown[] | Record<string, unknown>
): unknown[] | Record<string, unknown> =>
  isObject(val)
    ? Object.entries(val).reduce((prev, [k, v]) => {
        if (isTypesNeededTraverse(v)) {
          return Object.assign(prev, {
            [k]: undefinedHandler(v)
          })
        } else {
          const { type } =
            isString(v) && v.startsWith(LeFE_Prefix)
              ? parseReplaceString(v)
              : {
                  type: ''
                }
          return Object.assign(prev, {
            [k]:
              type === ETypeStrings.undefined || v === UndefinedReplacer
                ? undefined
                : v
          })
        }
      }, {})
    : val.map(item => {
        if (isTypesNeededTraverse(item)) {
          return undefinedHandler(item)
        } else {
          const { type } =
            isString(item) && item.startsWith(LeFE_Prefix)
              ? parseReplaceString(item)
              : {
                  type: ''
                }
          return type === ETypeStrings.undefined ? undefined : item
        }
      })

export const parse = (json: string): any => {
  const result = JSON.parse(json, (key: string, val: string) => {
    return !isTypesNeededTraverse(val) ? needNotTraverseHandler(val) : val
  })
  return undefinedHandler(result)
}
