/**
 * Production-ready API storage adapter.
 *
 * Backward-compatible with the 3.5.x signature — `apiAdapter('/api/x')`
 * still works exactly as before. New options are all opt-in.
 *
 * @example basic
 *   const adapter = apiAdapter<ConsentSettings>('/api/consent');
 *
 * @example with credentials and CSRF
 *   const adapter = apiAdapter<ConsentSettings>('/api/consent', {
 *     credentials: 'include',
 *     headers: () => ({
 *       'X-CSRF-Token': document.querySelector<HTMLMetaElement>(
 *         'meta[name="csrf-token"]'
 *       )?.content ?? '',
 *     }),
 *   });
 *
 * @example with retry + telemetry
 *   const adapter = apiAdapter<ConsentSettings>('/api/consent', {
 *     retry: { attempts: 2, baseDelayMs: 300 },
 *     onError: (ctx) => Sentry.captureException(ctx.error, { extra: ctx }),
 *     onSuccess: (ctx) => analytics.track('consent_saved', { method: ctx.method }),
 *   });
 *
 * @example with response unwrap
 *   const adapter = apiAdapter<ConsentSettings>('/api/consent', {
 *     // API returns { data: ConsentSettings, ok: true }
 *     unwrap: (raw) => (raw as { data: ConsentSettings }).data,
 *   });
 */
export declare function apiAdapter<T = unknown>(endpoint: string, options?: ApiAdapterOptions<T>): StorageAdapter<T>;

export declare interface ApiAdapterErrorContext<T = unknown> {
    /** Which adapter operation triggered this — `load`, `save`, or `remove`. */
    method: ApiAdapterMethod;
    /** The endpoint URL that failed. */
    endpoint: string;
    /** Underlying error (for network failures / parse errors). */
    error?: unknown;
    /** Response object, if a response was received. */
    response?: Response;
    /** HTTP status code, if available. */
    status?: number;
    /** For `save`, the payload that failed to send. */
    payload?: T;
    /** Which retry attempt this is (0 = first try). Capped at `retry.attempts`. */
    attempt: number;
}

export declare type ApiAdapterMethod = 'load' | 'save' | 'remove';

export declare interface ApiAdapterOptions<T = unknown> {
    /**
     * Extra HTTP headers to send with every request. Useful for `Authorization`,
     * `X-CSRF-Token`, `X-Requested-With`, etc.
     *
     * Can also be a function that returns headers, which lets you read a CSRF
     * token from the DOM/cookie at request time rather than at adapter
     * construction time.
     */
    headers?: Record<string, string> | (() => Record<string, string>);
    /**
     * Forwarded to fetch's `credentials` option. Defaults to `'same-origin'`
     * (the browser default). Set to `'include'` for cross-origin endpoints
     * that need cookies / auth.
     */
    credentials?: RequestCredentials;
    /**
     * HTTP method override for the load operation. Defaults to `'GET'`.
     */
    loadMethod?: 'GET' | 'POST';
    /**
     * HTTP method override for the save operation. Defaults to `'POST'`. Some
     * REST APIs prefer `'PUT'` for upsert semantics.
     */
    saveMethod?: 'POST' | 'PUT' | 'PATCH';
    /**
     * Transform the raw JSON response into the expected `T`. Useful for APIs
     * that wrap responses in `{ data: ... }` or similar envelopes. Called
     * after `res.json()`. If omitted, the parsed JSON is used as-is.
     */
    unwrap?: (raw: unknown) => T | null;
    /**
     * Retry policy for failed requests. Defaults to no retries (preserves the
     * pre-3.6.0 behaviour). When configured, applies to all three operations.
     */
    retry?: ApiAdapterRetryConfig;
    /**
     * Called when a request fails (after all retries exhausted). The adapter
     * still returns a graceful null/void result so the consuming hook
     * doesn't crash — this hook is for telemetry, toasts, or audit logging.
     */
    onError?: (ctx: ApiAdapterErrorContext<T>) => void;
    /**
     * Called when a request succeeds. Useful for cache invalidation,
     * analytics, or syncing other state.
     */
    onSuccess?: (ctx: ApiAdapterSuccessContext<T>) => void;
    /**
     * Per-request fetch options to merge into every request. Use this for
     * things `fetch` itself supports that aren't directly modelled above —
     * `signal`, `mode`, `cache`, `redirect`, etc.
     */
    fetchInit?: Omit<RequestInit, 'method' | 'headers' | 'body' | 'credentials'>;
}

export declare interface ApiAdapterRetryConfig {
    /**
     * Number of additional attempts after the initial request. Defaults to 0
     * (no retries). e.g. `attempts: 2` means up to 3 total requests.
     */
    attempts?: number;
    /**
     * Base delay in ms between attempts. Defaults to 250ms. The actual delay
     * uses exponential backoff: `baseDelayMs * 2^attempt`.
     */
    baseDelayMs?: number;
    /**
     * Predicate that decides whether to retry given the failure context. By
     * default we retry on network errors and 5xx responses, but not on 4xx
     * (those are client errors that won't fix themselves).
     */
    shouldRetry?: (ctx: ApiAdapterErrorContext<unknown>) => boolean;
}

export declare interface ApiAdapterSuccessContext<T = unknown> {
    /** Which adapter operation succeeded — `load`, `save`, or `remove`. */
    method: ApiAdapterMethod;
    /** The endpoint URL. */
    endpoint: string;
    /** Response object. */
    response: Response;
    /** For `load` operations, the parsed (and optionally unwrapped) data. */
    data?: T;
    /** For `save` operations, the payload that was sent. */
    payload?: T;
}

/**
 * Compose a primary adapter with one or more secondary adapters. Reads
 * always go to the primary; writes (`save` / `remove`) fan out to the
 * primary first, then each secondary. Secondary failures are logged but
 * never propagated.
 *
 * Useful for shadowing localStorage to an API endpoint, mirroring consent
 * to a cookie for SSR, or building offline-first sync.
 *
 * @example
 * ```ts
 * import {
 *   composeAdapters,
 *   localStorageAdapter,
 *   apiAdapter,
 * } from '@tantainnovative/ndpr-toolkit/adapters';
 * import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
 *
 * const adapter = composeAdapters(
 *   localStorageAdapter('ndpr_consent'),
 *   apiAdapter('/api/consent'),
 * );
 * useConsent({ options, adapter });
 * ```
 */
export declare function composeAdapters<T = unknown>(primary: StorageAdapter<T>, ...secondaries: StorageAdapter<T>[]): StorageAdapter<T>;

/**
 * Storage adapter backed by a browser cookie. Useful for consent state that
 * needs to be shared with server-side rendering, or for cross-subdomain
 * persistence via the `domain` option.
 *
 * @example
 * ```ts
 * import { cookieAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
 * import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
 *
 * const adapter = cookieAdapter('ndpr_consent', {
 *   domain: '.example.com',
 *   sameSite: 'Lax',
 *   expires: 180,
 * });
 * useConsent({ options, adapter });
 * ```
 */
export declare function cookieAdapter<T = unknown>(key: string, options?: CookieAdapterOptions): StorageAdapter<T>;

export declare interface CookieAdapterOptions {
    domain?: string;
    path?: string;
    expires?: number;
    secure?: boolean;
    sameSite?: 'Strict' | 'Lax' | 'None';
}

/**
 * Storage adapter backed by `window.localStorage`. The default adapter used
 * by every hook in the toolkit when no `adapter` prop is supplied.
 *
 * Safe to import server-side — every method short-circuits when
 * `window` is undefined, so calling `load()` on the server returns `null`.
 *
 * @example
 * ```ts
 * import { localStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
 * import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
 *
 * const adapter = localStorageAdapter('ndpr_consent');
 * useConsent({ options, adapter });
 * ```
 */
export declare function localStorageAdapter<T = unknown>(key: string): StorageAdapter<T>;

/**
 * Storage adapter backed by an in-memory value. Useful in tests, Storybook,
 * SSR previews, or anywhere persistence across reloads is undesirable.
 *
 * @example
 * ```ts
 * import { memoryAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
 * import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
 *
 * const adapter = memoryAdapter({ consents: {}, version: '1.0' });
 * useConsent({ options, adapter });
 * ```
 */
export declare function memoryAdapter<T = unknown>(initialData?: T): StorageAdapter<T>;

/**
 * Storage adapter backed by `window.sessionStorage`. Data is scoped to the
 * current tab and discarded when the tab closes — useful for consent
 * choices that should not survive a fresh session.
 *
 * @example
 * ```ts
 * import { sessionStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
 * import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
 *
 * const adapter = sessionStorageAdapter('ndpr_consent');
 * useConsent({ options, adapter });
 * ```
 */
export declare function sessionStorageAdapter<T = unknown>(key: string): StorageAdapter<T>;

export declare interface StorageAdapter<T = unknown> {
    /** Load persisted data. Called once on hook mount. */
    load(): T | null | Promise<T | null>;
    /** Persist data. Called on every state change. */
    save(data: T): void | Promise<void>;
    /** Clear persisted data. Called on reset. */
    remove(): void | Promise<void>;
}

export { }
