//! localStorage 持久化 ref — 读初始化 + 写回 localStorage(JSON)
//!
//! 背景:Tasks/Projects/Ideas 等列表页的筛选/分页状态散布在多个 ref,各自手写
//! localStorage.getItem/setItem 易漏且风格不一。本 composable 收敛为声明式一行:
//!   const page = usePersistedRef('tasks.page', 1)
//!
//! 行为:
//! - 初始化时读 localStorage,存在且 JSON 解析成功则用其值,否则用 default
//! - watch ref 深度变化,JSON.stringify 写回 localStorage(try/catch 防脏数据/配额)
//! - SSR/无 localStorage 环境(SSR 不适用于 Tauri webview,但防御性兜底)返回纯 ref
//!
//! 设计取舍:
//! - 不做跨 tab 同步(storage 事件)——单实例 Tauri 应用无此需求
//! - 不做类型校验(解析出的值类型可能漂移)——调用方 default 决定类型,JSON 解析成功即采用,
//!   若需严格类型校验可在调用方业务层判断(当前所有调用点均为 string/number,无需求)

import { ref, watch, type Ref } from 'vue'

/**
 * 创建一个持久化到 localStorage 的 ref。
 *
 * @param key localStorage 键名(建议带模块前缀,如 'tasks.page')
 * @param defaultValue 默认值(localStorage 无值或解析失败时使用)
 * @returns 与普通 ref 行为一致的 Ref<T>
 */
export function usePersistedRef<T>(key: string, defaultValue: T): Ref<T> {
  // 初始化:读 localStorage,失败/不存在回落到 default
  const initial = readPersisted(key, defaultValue)
  const r = ref(initial) as Ref<T>

  // 写回:深度 watch,JSON.stringify 失败静默(防循环引用等异常)
  watch(
    r,
    (val) => {
      try {
        localStorage.setItem(key, JSON.stringify(val))
      } catch {
        /* 忽略:配额溢出 / 序列化失败 / 隐私模式禁用 localStorage */
      }
    },
    { deep: true },
  )

  return r
}

/** 读 localStorage 并 JSON 解析,失败/不存在返回 defaultValue。仅本模块内部使用。 */
function readPersisted<T>(key: string, defaultValue: T): T {
  try {
    const raw = localStorage.getItem(key)
    if (raw === null) return defaultValue
    return JSON.parse(raw) as T
  } catch {
    return defaultValue
  }
}
