import { C as Chunk, R as ReadOnlyChunk } from '../core-DAc7hZla.js';
import { P as PaginatedAsyncChunk, a as PaginationState, A as AsyncChunk, I as InfiniteAsyncChunk, M as Mutation, b as MutationResult } from '../mutation-DLvwAQ6L.js';

/**
 * Subscribes to a chunk and returns its current value along with setters,
 * reset, and destroy. Accepts both writable `Chunk<T>` and read-only
 * `ReadOnlyChunk<T>` (e.g. derived chunks from `.derive()` or `select()`).
 *
 * For read-only chunks, the returned `set` and `reset` will be no-ops at
 * runtime — prefer `useChunkValue` for derived/read-only chunks.
 *
 * @example
 * const count = chunk(0);
 * const [value, setValue] = useChunk(count);
 *
 * @example
 * // Works with derived chunks too
 * const doubled = count.derive(n => n * 2);
 * const [value] = useChunk(doubled);
 */
declare function useChunk<T, S = T>(chunk: Chunk<T> | ReadOnlyChunk<T>, selector?: (value: T) => S): readonly [S, (valueOrUpdater: T | ((currentValue: T) => T)) => void, () => void, () => void];

/**
 * Subscribes to a chunk and returns only its current value.
 * Accepts both writable `Chunk<T>` and read-only `ReadOnlyChunk<T>`
 * (e.g. derived chunks from `.derive()`, `select()`, or `computed()`).
 *
 * Prefer this over `useChunk` when you only need to read — it makes
 * the read-only intent explicit and works correctly with derived chunks.
 *
 * @example
 * const isAuthenticated = userChunk.derive(u => u !== null);
 * const auth = useChunkValue(isAuthenticated); // ✅ no type error
 *
 * @example
 * const total = computed(() => price.get() * qty.get());
 * const value = useChunkValue(total); // ✅ no type error
 */
declare function useChunkValue<T, S = T>(chunk: Chunk<T> | ReadOnlyChunk<T>, selector?: (value: T) => S): S;

interface UseAsyncChunkResult<T, E extends Error, P extends Record<string, any>> {
    data: T | null;
    loading: boolean;
    error: E | null;
    lastFetched?: number;
    isPlaceholderData: boolean;
    reload: (params?: Partial<P>) => Promise<void>;
    refresh: (params?: Partial<P>) => Promise<void>;
    mutate: (mutator: (currentData: T | null) => T | null) => void;
    reset: (refetch?: boolean) => void;
}
interface UseAsyncChunkResultWithParams<T, E extends Error, P extends Record<string, any>> extends UseAsyncChunkResult<T, E, P> {
    setParams: (params: Partial<Record<keyof P, P[keyof P] | null>>) => void;
    clearParams: () => void;
}
interface UseAsyncChunkResultWithPagination<T, E extends Error, P extends Record<string, any>> extends UseAsyncChunkResult<T, E, P> {
    pagination?: PaginationState;
    nextPage: () => Promise<void>;
    prevPage: () => Promise<void>;
    goToPage: (page: number) => Promise<void>;
    resetPagination: () => Promise<void>;
}
interface UseAsyncChunkResultWithParamsAndPagination<T, E extends Error, P extends Record<string, any>> extends UseAsyncChunkResultWithParams<T, E, P>, Omit<UseAsyncChunkResultWithPagination<T, E, P>, keyof UseAsyncChunkResult<T, E, P>> {
}
interface UseAsyncChunkOptions<T = any, E extends Error = Error, P extends Record<string, any> = {}> {
    /**
     * Parameters to pass to the fetcher. When these change between renders,
     * the chunk automatically re-fetches with the new values.
     */
    params?: Partial<P>;
    /**
     * Force a fetch on mount even when the chunk has no params.
     * Ignored if params is provided.
     * (default: false)
     */
    fetchOnMount?: boolean;
    /**
     * Whether the chunk is enabled.
     * If false, the chunk will not fetch data.
     * (default: true)
     */
    enabled?: boolean;
    /**
     * Called after every successful fetch at the hook level.
     * Has full access to React context — safe to call navigate(), setState(), etc.
     */
    onSuccess?: (data: T) => void;
    /**
     * Called when a fetch fails at the hook level.
     * Has full access to React context — safe to call navigate(), setState(), etc.
     */
    onError?: (error: E) => void;
}
declare function useAsyncChunk<T, E extends Error = Error, P extends Record<string, any> = {}>(asyncChunk: PaginatedAsyncChunk<T, E> & {
    setParams: (params: Partial<P>) => void;
}, options?: UseAsyncChunkOptions<T, E, P>): UseAsyncChunkResultWithParamsAndPagination<T, E, P>;
declare function useAsyncChunk<T, E extends Error = Error, P extends Record<string, any> = {}>(asyncChunk: PaginatedAsyncChunk<T, E>, options?: UseAsyncChunkOptions<T, E, P>): UseAsyncChunkResultWithPagination<T, E, P>;
declare function useAsyncChunk<T, E extends Error = Error, P extends Record<string, any> = {}>(asyncChunk: AsyncChunk<T, E> & {
    setParams: (params: Partial<P>) => void;
}, options?: UseAsyncChunkOptions<T, E, P>): UseAsyncChunkResultWithParams<T, E, P>;
declare function useAsyncChunk<T, E extends Error = Error, P extends Record<string, any> = {}>(asyncChunk: AsyncChunk<T, E>, options?: UseAsyncChunkOptions<T, E, P>): UseAsyncChunkResult<T, E, P>;

interface UseInfiniteAsyncChunkOptions<P extends Record<string, any>> extends Omit<UseAsyncChunkOptions<P>, 'initialParams' | 'params'> {
    /**
     * @deprecated Use `params` instead. Will be removed in v3 stable.
     */
    initialParams?: Omit<Partial<P>, 'page' | 'pageSize'>;
    /** Reactive parameters — page and pageSize are managed automatically. Re-fetches from page 1 when these change. */
    params?: Omit<Partial<P>, 'page' | 'pageSize'>;
    /** Automatically load next page when sentinel enters viewport (default: true) */
    autoLoad?: boolean;
    /** IntersectionObserver threshold — 0.0 to 1.0 (default: 1.0) */
    threshold?: number;
}
interface UseInfiniteAsyncChunkResult<T, E extends Error, P extends Record<string, any>> {
    data: T[] | null;
    loading: boolean;
    error: E | null;
    lastFetched?: number;
    isPlaceholderData: boolean;
    /** True when fetching a new page while existing data is already loaded */
    isFetchingMore: boolean;
    /** True if more pages are available */
    hasMore: boolean;
    reload: (params?: Partial<P>) => Promise<void>;
    refresh: (params?: Partial<P>) => Promise<void>;
    mutate: (mutator: (currentData: T[] | null) => T[]) => void;
    reset: () => void;
    nextPage: () => Promise<void>;
    prevPage: () => Promise<void>;
    goToPage: (page: number) => Promise<void>;
    resetPagination: () => Promise<void>;
    /** Manually trigger loading the next page */
    loadMore: () => void;
    /** Attach this ref to a sentinel element at the bottom of your list */
    observerTarget: React.RefObject<HTMLElement>;
}
/**
 * Subscribes to an infinite async chunk and wires up automatic infinite scroll.
 *
 * Attach `observerTarget` to a sentinel element at the bottom of your list —
 * the next page loads automatically when it enters the viewport.
 * Use `loadMore()` for manual triggering.
 *
 * @param chunk - An `InfiniteAsyncChunk` instance.
 * @param options.autoLoad - Auto-load on scroll (default: true).
 * @param options.threshold - IntersectionObserver threshold 0.0–1.0 (default: 1.0).
 * @param options.params - Reactive params excluding `page` and `pageSize`. Resets to page 1 and refetches when changed.
 *
 * @example
 * const { data, loading, hasMore, observerTarget, loadMore } = useInfiniteAsyncChunk(postsChunk);
 *
 * @example
 * // Reactive search — resets to page 1 automatically when searchTerm changes
 * const { data } = useInfiniteAsyncChunk(companiesChunk, {
 *   params: { search: searchTerm },
 * });
 *
 * return (
 *   <>
 *     {data?.map(post => <Post key={post.id} {...post} />)}
 *     <div ref={observerTarget} />
 *   </>
 * );
 */
declare function useInfiniteAsyncChunk<T, E extends Error = Error, P extends Record<string, any> = {}>(chunk: InfiniteAsyncChunk<T, E, P>, options?: UseInfiniteAsyncChunkOptions<P>): UseInfiniteAsyncChunkResult<T, E, P>;

interface UseMutationResult<TData, TError extends Error = Error, TVariables = void> {
    /** Current mutation state */
    loading: boolean;
    data: TData | null;
    error: TError | null;
    isSuccess: boolean;
    /**
     * Execute the mutation. Always resolves — never throws.
     * Safe to fire and forget, or await for local UI control.
     *
     * @example
     * // Fire and forget
     * mutate({ title: 'Hello' });
     *
     * // Await for local control — no try/catch needed
     * const { data, error } = await mutate({ title: 'Hello' });
     * if (!error) router.push('/posts');
     */
    mutate: TVariables extends void ? () => Promise<MutationResult<TData, TError>> : (variables: TVariables) => Promise<MutationResult<TData, TError>>;
    /** Reset mutation state back to initial */
    reset: () => void;
}
/**
 * Subscribes to a mutation instance and returns its reactive state with `mutate` and `reset`.
 *
 * @param mutation - A `mutation()` instance from `stunk/query`.
 *
 * @example
 * const createPost = mutation(
 *   async (data: NewPost) => fetchAPI('/posts', { method: 'POST', body: data }),
 *   { invalidates: [postsChunk] }
 * );
 *
 * function CreatePostForm() {
 *   const { mutate, loading, error, isSuccess } = useMutation(createPost);
 *
 *   const handleSubmit = async (data: NewPost) => {
 *     const { error } = await mutate(data);
 *     if (!error) router.push('/posts');
 *   };
 * }
 */
declare function useMutation<TData, TError extends Error = Error, TVariables = void>(mutation: Mutation<TData, TError, TVariables>): UseMutationResult<TData, TError, TVariables>;

export { type UseMutationResult, useAsyncChunk, useChunk, useChunkValue, useInfiniteAsyncChunk, useMutation };
