"use client"

import {
  createJSONStorage,
  type PersistStorage,
  type StateStorage,
  type StorageValue,
} from "zustand/middleware"

const DEFAULT_DEBOUNCE_MS = 220

/** In-memory fallback when `localStorage` is missing (SSR) or throws (private mode, etc.). */
function createMemoryStateStorage(): StateStorage {
  const data = new Map<string, string>()
  return {
    getItem: (name) => data.get(name) ?? null,
    setItem: (name, value) => {
      data.set(name, value)
    },
    removeItem: (name) => {
      data.delete(name)
    },
  }
}

function getPersistBackingStorage(): StateStorage {
  if (typeof window === "undefined") {
    return createMemoryStateStorage()
  }
  try {
    return window.localStorage
  } catch {
    return createMemoryStateStorage()
  }
}

/**
 * JSON persist storage that debounces writes to `localStorage` so rapid
 * store updates do not block the main thread on every mutation.
 * Flushes pending keys on a timer, `beforeunload`, and `pagehide`.
 * Uses in-memory storage during SSR or when `localStorage` is unavailable.
 */
function buildDebouncedJsonStorage(): PersistStorage<unknown> {
  const base =
    createJSONStorage(getPersistBackingStorage) ??
    createJSONStorage(() => createMemoryStateStorage())
  if (!base) {
    throw new Error("[debounced-json-storage] failed to create JSON storage")
  }

  const pending = new Map<string, StorageValue<unknown>>()
  const timers = new Map<string, ReturnType<typeof globalThis.setTimeout>>()

  const flushKey = (name: string) => {
    const t = timers.get(name)
    if (t !== undefined) {
      globalThis.clearTimeout(t)
      timers.delete(name)
    }
    const value = pending.get(name)
    if (value === undefined) return
    pending.delete(name)
    base.setItem(name, value)
  }

  const flushAll = () => {
    for (const name of [...pending.keys()]) flushKey(name)
  }

  if (typeof window !== "undefined") {
    window.addEventListener("beforeunload", flushAll)
    window.addEventListener("pagehide", flushAll)
  }

  return {
    getItem: (name) => base.getItem(name),
    setItem: (name, value) => {
      pending.set(name, value)
      const existing = timers.get(name)
      if (existing !== undefined) globalThis.clearTimeout(existing)
      const id = globalThis.setTimeout(() => {
        timers.delete(name)
        flushKey(name)
      }, DEFAULT_DEBOUNCE_MS)
      timers.set(name, id)
    },
    removeItem: (name) => {
      const existing = timers.get(name)
      if (existing !== undefined) {
        globalThis.clearTimeout(existing)
        timers.delete(name)
      }
      pending.delete(name)
      return base.removeItem(name)
    },
  }
}

/** Shared instance for all zustand `persist` stores in this app. */
export const debouncedPersistJSONStorage = buildDebouncedJsonStorage()
