import { SegmentState, SegmentLeaderRole } from '../Utils/Constants';
import { TrackTypeValue } from '../Loaders/P2PSegmentIdResolver';
export type SegmentStateValue = (typeof SegmentState)[keyof typeof SegmentState];
export type SegmentLeaderRoleValue = (typeof SegmentLeaderRole)[keyof typeof SegmentLeaderRole];
/**
 * Persisted metadata for a stored segment. Kept separate from the bytes so it
 * can be loaded cheaply at startup to rebuild the in-memory index without
 * touching the (potentially large) payload blobs.
 */
export type StoredSegmentMetadata = {
    id: string;
    url: string;
    trackType: TrackTypeValue;
    rendition?: string;
    expectedSize: number;
    state: SegmentStateValue;
    leaderRole: SegmentLeaderRoleValue;
    createdAt: number;
    lastUsedAt: number;
    writtenBytes: number;
    failureReason?: string;
};
/**
 * Persistence backend interface. The MVP ships with `IndexedDBBackend` for
 * browsers (parity with iOS `FileManager` + Android filesystem) and
 * `InMemoryBackend` as an automatic fallback for Node / jsdom / SSR.
 * All methods are async: callers must await them.
 */
export interface DiskSegmentStoreBackend {
    /** Load the index of all persisted segment metadata. */
    loadAllMetadata(): Promise<StoredSegmentMetadata[]>;
    /** Persist the metadata for a segment (upsert). */
    putMetadata(meta: StoredSegmentMetadata): Promise<void>;
    /** Persist the final byte payload for a segment (once READY). */
    putBytes(id: string, bytes: Uint8Array): Promise<void>;
    /** Fetch the persisted byte payload; returns undefined if not stored. */
    getBytes(id: string): Promise<Uint8Array | undefined>;
    /** Delete both metadata and payload for a segment. */
    delete(id: string): Promise<void>;
    /** Drop the entire store (metadata + payloads). */
    clearAll(): Promise<void>;
}
/**
 * Persistence backed by the browser's IndexedDB. Origin-scoped, quota-bounded,
 * survives reload. Mirrors the persistence semantics of iOS `FileManager` and
 * Android filesystem used by the native `DiskSegmentStore`.
 */
export declare class IndexedDBBackend implements DiskSegmentStoreBackend {
    private dbPromise?;
    static isSupported(): boolean;
    private openDb;
    loadAllMetadata(): Promise<StoredSegmentMetadata[]>;
    putMetadata(meta: StoredSegmentMetadata): Promise<void>;
    putBytes(id: string, bytes: Uint8Array): Promise<void>;
    getBytes(id: string): Promise<Uint8Array | undefined>;
    delete(id: string): Promise<void>;
    clearAll(): Promise<void>;
}
/** Fallback used when IndexedDB is unavailable (Node, jsdom, SSR). */
export declare class InMemoryBackend implements DiskSegmentStoreBackend {
    private meta;
    private bytes;
    loadAllMetadata(): Promise<StoredSegmentMetadata[]>;
    putMetadata(meta: StoredSegmentMetadata): Promise<void>;
    putBytes(id: string, data: Uint8Array): Promise<void>;
    getBytes(id: string): Promise<Uint8Array | undefined>;
    delete(id: string): Promise<void>;
    clearAll(): Promise<void>;
}
/** Picks the best available backend. */
export declare function createDefaultBackend(): DiskSegmentStoreBackend;
/**
 * A segment in the local cache. Mirrors iOS `StoredSegment` and Android
 * `DiskSegmentStore.Entry`. Metadata is always authoritative in memory for the
 * state machine (ACQUIRING / READY / FAILED / EVICTED); bytes live in memory
 * during acquisition (for streaming reads) and are flushed through to
 * IndexedDB on `markReady` so they survive across sessions.
 */
export declare class StoredSegment {
    readonly id: string;
    readonly url: string;
    readonly trackType: TrackTypeValue;
    readonly rendition?: string;
    expectedSize: number;
    state: SegmentStateValue;
    leaderRole: SegmentLeaderRoleValue;
    readonly createdAt: number;
    lastUsedAt: number;
    writtenBytes: number;
    failureReason?: string;
    /** Per-chunk buffer used while ACQUIRING, discarded once flattened. */
    private _chunks;
    /** Flat payload held in RAM during the session after `markReady`. */
    private _finalData?;
    /** True if the bytes live only in the backend (rebuilt from hydrate()). */
    private _bytesHydratedFromBackend;
    private _waiters;
    constructor(meta: StoredSegmentMetadata);
    toMetadata(): StoredSegmentMetadata;
    touch(): void;
    isVisibleForRendition(activeVideoRendition: string | undefined): boolean;
    /** Fast sync read from RAM (returns undefined if bytes live only in backend). */
    readDataSync(): Uint8Array | undefined;
    /** Internal helpers used by the store. */
    appendBytes(bytes: Uint8Array): void;
    finalizeReady(): Uint8Array;
    adoptFinalData(bytes: Uint8Array): void;
    needsBytesFromBackend(): boolean;
    markHydratedWithoutBytes(): void;
    discard(): void;
    /** Read in-memory bytes at `offset` (used by GrowingSegmentReader). */
    readBytesAt(offset: number, maxBytes: number): Uint8Array | undefined;
    /** Register a one-shot waiter notified on next state change or append. */
    subscribeWaiter(waiter: (state: SegmentStateValue) => void): () => void;
    private _notifyWaiters;
}
/**
 * Segment store with the iOS/Android public API, backed by IndexedDB by
 * default. The in-memory mirror keeps the state-machine synchronous (so
 * P2PLoader/CDNLoader flow works like on native) while byte I/O is async
 * against the backend.
 *
 * Typical lifecycle of a captured segment:
 *  1. `createOrGetAcquiring` → an in-memory `StoredSegment` with state=ACQUIRING.
 *     Metadata is written-through to the backend immediately (for crash recovery).
 *  2. `append(id, bytes)` while the CDN stream flows. Bytes stay in RAM; any
 *     open `GrowingSegmentReader` is notified so peers can stream the in-flight
 *     segment (early announcement / ACQUIRING serve).
 *  3. `markReady(id)` flattens the chunks, writes them to the backend (so they
 *     survive a reload), keeps a copy in RAM for the current session, and
 *     returns the finalized segment.
 *  4. Eviction via `evictExpiredAndOverflow` or explicit `evict(id)` removes
 *     both RAM and backend copies.
 */
export default class DiskSegmentStore {
    private segments;
    private backend;
    private hydrated;
    /**
     * Serialized write chain for backend mutations. Metadata and byte writes
     * submitted via `queueBackendWrite` run in submission order. Prevents
     * races where a later-submitted READY write lands on disk before the
     * earlier ACQUIRING write, leaving a stale state in IndexedDB.
     */
    private writeChain;
    constructor(backend?: DiskSegmentStoreBackend);
    /**
     * Allows tests to await all pending write-through flushes. Returns a
     * promise that resolves once the internal write chain is quiescent.
     */
    flushPendingWrites(): Promise<void>;
    private queueBackendWrite;
    /**
     * Loads the persisted index from the backend. Does NOT read the byte
     * payloads — those are fetched lazily on `readDataAsync` / `openReader`
     * first access. Call once at startup.
     */
    hydrate(): Promise<void>;
    createOrGetAcquiring(id: string, url: string, trackType: TrackTypeValue, rendition: string | undefined, expectedSize: number, leaderRole: SegmentLeaderRoleValue): StoredSegment;
    append(id: string, bytes: Uint8Array): void;
    markReady(id: string): StoredSegment | undefined;
    markFailed(id: string, reason?: string): StoredSegment | undefined;
    evict(id: string): StoredSegment | undefined;
    getReady(id: string): StoredSegment | undefined;
    get(id: string): StoredSegment | undefined;
    readyIds(activeVideoRendition?: string): Set<string>;
    totalReadyBytes(): number;
    readyCount(): number;
    evictExpiredAndOverflow(retentionMs: number, maxBytes: number): StoredSegment[];
    openReader(id: string): GrowingSegmentReader | undefined;
    clear(): Promise<void>;
    /**
     * Async payload read. Prefers RAM (`readDataSync`); if the bytes were
     * persisted in a previous session, fetches them from the backend on demand
     * and caches the result for subsequent reads.
     */
    readDataAsync(id: string): Promise<Uint8Array | undefined>;
    /** Internal: used by GrowingSegmentReader to pull bytes for READY, ejected-from-RAM entries. */
    _backfillBytes(seg: StoredSegment): Promise<void>;
    private persistMetadata;
}
/**
 * Streaming reader over a `StoredSegment`. Returns chunks as they are
 * appended; awaits up to `waitTimeoutMs` on each call when the segment is
 * still ACQUIRING. Parity with iOS `GrowingSegmentReader` (sync-in-Swift,
 * Promise-based in JS).
 */
export declare class GrowingSegmentReader {
    private segment;
    private store?;
    private offset;
    private closed;
    constructor(segment: StoredSegment, store?: DiskSegmentStore);
    expectedSize(): number;
    currentState(): SegmentStateValue;
    hasPendingBytes(): boolean;
    readNextChunk(maxBytes: number, waitTimeoutMs: number): Promise<Uint8Array | undefined>;
    close(): void;
}
