import * as React from 'react';

/**
 * Exxat DS — persisted-state primitive.
 *
 * Two layers in one file:
 *
 * 1. **Low-level storage** — `getStorageItem`, `setStorageItem`,
 *    `scheduleStorageWrite`, `subscribeToStorageKey`,
 *    `clearAllPersistedState`. Use when you need imperative control
 *    (writing on `beforeunload`, listing keys for a Settings panel,
 *    draining a queue).
 *
 * 2. **React hook** — `usePersistedState<T>(key, default, opts?)`. The
 *    drop-in replacement for `useState` that survives reloads. 90% of
 *    consumers should reach for this and not the low-level helpers.
 *
 * Centralised so future migrations (server-side sync, IndexedDB
 * fallback, encryption) only have to touch one file. **Don't read or
 * write `localStorage` directly inside DS code** — go through here.
 */

/** Every DS-written storage key starts with this prefix. */
declare const EXXAT_STORAGE_PREFIX = "exxat-ds:";
/** Debounce window for collapsed writes. */
declare const DEFAULT_DEBOUNCE_MS = 400;
type StorageDriver = "local" | "session";
/**
 * Compose a fully-qualified storage key. Pass the unprefixed key (e.g.
 * `"sidebar:collapsed"`) — the prefix is added here. If the caller already
 * passes a prefixed key (e.g. legacy `exxat-ds:placements:lifecycle:v1:main`)
 * we don't double-prefix.
 */
declare function namespacedKey(key: string): string;
declare function getStorageItem(key: string, driver?: StorageDriver): string | null;
declare function setStorageItem(key: string, value: string, driver?: StorageDriver): void;
declare function removeStorageItem(key: string, driver?: StorageDriver): void;
/**
 * Schedule a debounced write. Successive calls for the same `key` reset the
 * timer so only the trailing value lands in storage. Use this for the hot
 * path (column resize, search keystrokes, scroll position) — anything that
 * fires faster than ~10Hz.
 *
 * For one-shot writes (theme change, sidebar toggle) call `setStorageItem`
 * directly; the debounce is overhead you don't need.
 */
declare function scheduleStorageWrite(key: string, value: string, options?: {
    debounceMs?: number;
    driver?: StorageDriver;
}): void;
/**
 * Force any pending debounced writes to flush synchronously. Safe to call
 * on `beforeunload` so a tab close doesn't drop the last keystroke.
 */
declare function flushPendingStorageWrites(): void;
type StorageListener = (newValue: string | null) => void;
/**
 * Subscribe to changes for a single DS-namespaced key from *other tabs*.
 * The browser fires `storage` events on every tab except the one that
 * triggered the write, so this is the natural cross-tab sync mechanism.
 *
 * Returns an unsubscribe function. SSR-safe (returns a no-op on the server).
 */
declare function subscribeToStorageKey(key: string, listener: StorageListener): () => void;
/**
 * Wipe every key the DS owns (anything starting with `exxat-ds:`). Exposed
 * for Settings → "Reset preferences" flows. Customer apps SHOULD wire this
 * to a settings button rather than letting users hunt through DevTools.
 */
declare function clearAllPersistedState(driver?: StorageDriver): void;
/**
 * List every DS-namespaced key currently in storage. Useful for Settings
 * dashboards that want to show users what they can clear.
 */
declare function listPersistedKeys(driver?: StorageDriver): string[];
interface UsePersistedStateOptions<T> {
    /** Storage driver. Default `"local"`. Use `"session"` for tab-scoped state. */
    driver?: StorageDriver;
    /**
     * Schema version. Bump when the shape of `T` changes. Old payloads with a
     * different version are passed to `migrate`; if `migrate` is missing or
     * returns `undefined`, the persisted record is dropped.
     */
    version?: number;
    /**
     * Migrate a stored payload from a previous version into the current
     * shape. Returning `undefined` discards the record (state falls back to
     * `defaultValue`).
     */
    migrate?: (raw: unknown, fromVersion: number) => T | undefined;
    /** Custom serializer. Default is `JSON.stringify` (with envelope). */
    serialize?: (value: T) => string;
    /**
     * Custom deserializer. Default is `JSON.parse`. Return `undefined` to
     * discard the payload (e.g. shape no longer matches and you don't have a
     * migration).
     */
    deserialize?: (raw: string) => T | undefined;
    /**
     * Debounce window for writes. Default 400ms. Pass `0` for synchronous
     * writes (one-shot toggles).
     */
    debounceMs?: number;
    /**
     * Listen for `storage` events from other tabs and reflect them locally.
     * Default `true`.
     */
    syncAcrossTabs?: boolean;
}
/**
 * Persisted state hook. Drop-in replacement for `useState`.
 *
 * ```tsx
 * const [collapsed, setCollapsed] = usePersistedState("sidebar:collapsed", false)
 * const [theme, setTheme, clearTheme] = usePersistedState("theme", "light", { debounceMs: 0 })
 * ```
 *
 * Returns `[value, setValue, clear]` — `clear()` removes the entry from
 * storage and resets in-memory state to the latest `defaultValue`.
 *
 * **Disabling persistence at runtime:** pass `key = ""` (empty string) and
 * the hook degrades to plain `useState` — no reads, no writes, no `storage`
 * subscription, no namespacing. This lets components conditionally enable
 * persistence (e.g. via a `persistKey?: string` prop) without breaking the
 * rules of hooks.
 */
declare function usePersistedState<T>(key: string, defaultValue: T, options?: UsePersistedStateOptions<T>): [T, React.Dispatch<React.SetStateAction<T>>, () => void];

export { DEFAULT_DEBOUNCE_MS, EXXAT_STORAGE_PREFIX, type StorageDriver, type UsePersistedStateOptions, clearAllPersistedState, flushPendingStorageWrites, getStorageItem, listPersistedKeys, namespacedKey, removeStorageItem, scheduleStorageWrite, setStorageItem, subscribeToStorageKey, usePersistedState };
