import type { ReactiveFlags } from 'vue'

/**
 * 类型标签，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') {
    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) => {
    clonedObj[key as keyof T] = clone(rawValue[key as keyof T])
  })
  return clonedObj as T
}

type ExtractRawType<T> =
// 匹配 reactive 响应式对象（通过 Vue 内置的 RAW 标记提取原始类型）
  T extends { [ReactiveFlags.RAW]: infer RawValue }
    ? RawValue
    // 递归处理数组（兼容 reactive([]) 场景）
    : T extends Array<infer U>
      ? Array<ExtractRawType<U>>
      // 递归处理嵌套对象（兼容 reactive({ a: { b: 1 } }) 场景）
      : T extends object
        ? { [K in keyof T]: ExtractRawType<T[K]> }
        // 非对象类型直接返回（如 string/number 等）
        : T;

type ResetAble<T> = T & { $reset: (val?: Partial<ExtractRawType<T>>) => void }


function resetAble<T extends object>(target: T): ResetAble<T> {
  const initialData = clone(target) as T

  (target as ResetAble<T>).$reset = (val?: Partial<ExtractRawType<T>>) => {
    if (val == null) {
      val = initialData
    }
    if (Array.isArray(val)) {
      const arr = target as unknown as Array<unknown>
      const initialArr = val as unknown as Array<unknown>
      arr.splice(0, arr.length, ...initialArr)
    } else {
      Object.keys(val).forEach((key) => {
        (target as Record<string, unknown>)[key] = (val as Record<string, unknown>)[key]
      })
      Object.getOwnPropertyNames(target).forEach((key) => {
        if (key !== '$reset' && !(key in val)) {
          (target as Record<string, unknown>)[key] = undefined
        }
      })
    }
  }
  return target as ResetAble<T>
}

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