import * as react from 'react';

/** A media object as the browser sees it — host-resolved display URL, server-derived metadata. */
interface MediaItem {
    key: string;
    url: string;
    size: number;
    contentType?: string;
    width?: number;
    height?: number;
    uploadedAt?: number;
}
/**
 * Injected transport seam. The browser NEVER holds storage creds — every method maps to the host's
 * authenticated worker route. Same injection shape as auth-react's AuthClient / content-react's ContentClient.
 */
interface MediaClient {
    upload(file: File, opts?: {
        signal?: AbortSignal;
        onProgress?: (fraction: number) => void;
    }): Promise<MediaItem>;
    list(opts?: {
        cursor?: string;
        limit?: number;
    }): Promise<{
        items: MediaItem[];
        cursor?: string;
    }>;
    remove(key: string): Promise<void>;
}

/**
 * Typed boundary error when the host worker rejects an upload (validation/quota/size/auth).
 * Carries a STRUCTURAL `isUploadRejectedError: true` tag so cross-package callers (the host, the
 * useUpload hook) identify it WITHOUT `instanceof` — two deduped copies of this class break
 * instanceof, and a `name`-only check is spoofable by a plain `{ name: 'UploadRejectedError' }`.
 * Mirrors the same-wave `@platform-modules/uploads/storage` `isStorageError === true` convention
 * (CLAUDE.md §6: cross-package error identity must use a structural type-guard, never instanceof).
 */
declare class UploadRejectedError extends Error {
    readonly reason: string;
    readonly status: number;
    readonly name = "UploadRejectedError";
    readonly isUploadRejectedError: true;
    constructor(reason: string, status: number);
}
declare function isUploadRejectedError(e: unknown): e is UploadRejectedError;
/**
 * Typed boundary error when `useUpload.upload` is called re-entrantly — a SECOND upload while one
 * is already in flight. The hook tracks a single upload's state, so the second call cannot be
 * coalesced (each must return its own MediaItem) and is rejected. DISTINCT from UploadRejectedError
 * (a HOST-side rejection carrying reason+status) — a client-side re-entrancy conflict has neither,
 * so it gets its own discriminant, never a synthetic-status reuse. Carries a STRUCTURAL
 * `isUploadInFlightError: true` tag so callers identify it WITHOUT `instanceof` (CLAUDE.md §6).
 */
declare class UploadInFlightError extends Error {
    readonly name = "UploadInFlightError";
    readonly isUploadInFlightError: true;
    constructor();
}
declare function isUploadInFlightError(e: unknown): e is UploadInFlightError;

interface UseUploadResult {
    upload(file: File, opts?: {
        signal?: AbortSignal;
    }): Promise<MediaItem>;
    uploading: boolean;
    progress: number;
    error: Error | null;
    reset(): void;
}
declare function useUpload(client: MediaClient): UseUploadResult;

interface UseMediaLibraryResult {
    items: MediaItem[];
    loading: boolean;
    error: Error | null;
    hasMore: boolean;
    loadMore(): Promise<void>;
    refresh(): Promise<void>;
    remove(key: string): Promise<void>;
}
declare function useMediaLibrary(client: MediaClient, opts?: {
    limit?: number;
}): UseMediaLibraryResult;

interface MediaLibraryProps {
    client: MediaClient;
    onSelect(item: MediaItem): void;
    className?: string;
}
declare function MediaLibrary({ client, onSelect, className }: MediaLibraryProps): react.JSX.Element;

export { type MediaClient, type MediaItem, MediaLibrary, type MediaLibraryProps, UploadInFlightError, UploadRejectedError, type UseMediaLibraryResult, type UseUploadResult, isUploadInFlightError, isUploadRejectedError, useMediaLibrary, useUpload };
