/**
 * 类型标签，Object.prototype.toString.call(obj) 的返回值
 */
export class TypeTag {
  static readonly NULL = '[object Null]'
  static readonly UNDEFINED = '[object Undefined]'

  static readonly STRING = '[object String]'
  static readonly NUMBER = '[object Number]'
  static readonly BOOLEAN = '[object Boolean]'

  static readonly ARRAY = '[object Array]'
  static readonly MAP = '[object Set]'
  static readonly SET = '[object Map]'

  static readonly OBJECT = '[object Object]'
  static readonly SYMBOL = '[object Symbol]'
  static readonly DATE = '[object Date]'
  static readonly REGEXP = '[object RegExp]'
  static readonly PROMISE = '[object Promise]'
  static readonly FUNCTION = '[object Function]'
}

/**
 * 节流<br/>
 * t 毫秒内只执行一次指定的函数<br/>
 *
 * @param fn 待包装的函数
 * @param t 时间阈值（ms）
 * @return 包装后的函数
 */
function throttle<T extends any[]>(t: number, fn: (...args: T) => void) {
  let lastExecTime = 0
  return function (this: any, ...args: T) {
    let now = Date.now()
    if (now - lastExecTime >= t) {
      lastExecTime = now
      fn.apply(this, args)
    }
  }
}

/**
 * 防抖<br/>
 * 指定的函数延迟 t 毫秒只执行，重复调用将重新计时<br/>
 *
 * @param fn 待包装的函数
 * @param t 时间阈值（ms）
 * @return 包装后的函数
 */
function debounce<T extends any[]>(t: number, fn: (...args: T) => void) {
  let deferTimer: number | null = null
  return function (this: any, ...args: T) {
    if (deferTimer != null) {
      clearTimeout(deferTimer)
    }

    deferTimer = window.setTimeout(() => {
      fn.apply(this, args)
    }, t)
  }
}

function clone<T = any>(value: T): T {
  if (value === null || typeof value !== 'object' || typeof value === 'function') {
    return value
  }
  const rawValue = isReactive(value) ? toRaw(value) : value
  if (rawValue instanceof Date) {
    return new Date(rawValue.getTime()) as T
  }
  if (rawValue instanceof RegExp) {
    return new RegExp(rawValue.source, rawValue.flags) as T
  }
  if (Array.isArray(rawValue)) {
    return rawValue.map((item) => clone(item)) as T
  }
  const clonedObj = {} as T
  Object.keys(rawValue).forEach((key) => {
    const propValue = rawValue[key as keyof T]
    if (typeof propValue !== 'function') {
      clonedObj[key as keyof T] = clone(propValue)
    }
  })

  return clonedObj as T
}

type PartialForObject<T> =
// 数组类型：直接返回原数组类型（不做 Partial）
  T extends Array<any>
    ? T
    // 普通对象：做 Partial 处理
    : T extends object
      ? Partial<T>
      // 基本类型：直接返回
      : T;

export type ResetAble<T> = T & {
  $reset: (val?: PartialForObject<T>) => void
  $clone: () => T
}


function resetAble<T>(target: T): ResetAble<T> {
  const initialData = clone(target) as T
  const resetAbleTarget = target as ResetAble<T>
  resetAbleTarget.$clone = () => clone(target) as T

  resetAbleTarget.$reset = (val?: PartialForObject<T>) => {
    const resetValue = val ?? (initialData as PartialForObject<T>)

    if (Array.isArray(resetValue)) {
      const arr = target as unknown as Array<unknown>
      const initialArr = resetValue as unknown as Array<unknown>
      arr.splice(0, arr.length, ...initialArr)
    } else {
      const targetObj = target as Record<string, unknown>
      const resetObj = resetValue as Record<string, unknown>
      // 步骤1：遍历重置值，赋值到目标对象
      Object.keys(resetObj).forEach((key) => {
        targetObj[key] = resetObj[key]
      })

      // 步骤2：清理目标对象中不存在于重置值的属性（保留 $reset/$clone）
      Object.getOwnPropertyNames(targetObj).forEach((key) => {
        if (key !== '$reset' && key !== '$clone' && !(key in resetObj)) {
          targetObj[key] = undefined
        }
      });
    }
  }
  return target as ResetAble<T>
}

export default {
  throttle,
  debounce,
  TypeTag,
  clone,
  resetAble,
}
