/**
 * Public types for directory operations (`walk`, `uploadDirectory`,
 * `downloadDirectory`).
 *
 * `DirectoryHandleLike` and `FileHandleLike` are structurally compatible
 * with the browser File System Access API
 * (`FileSystemDirectoryHandle` / `FileSystemFileHandle`) so that browser
 * consumers can pass them directly. For Bun/Node, use the adapter from
 * `node-directory-handle.ts`.
 */

export interface FileHandleLike {
  readonly kind: 'file';
  readonly name: string;
  /** Read-side accessor — used by `uploadDirectory`. */
  getFile(): Promise<FileLike>;
  /** Write-side accessor — used by `downloadDirectory`. */
  createWritable(): Promise<WritableStreamLike>;
}

export interface FileLike {
  readonly name: string;
  readonly size: number;
  readonly type: string;
  stream(): ReadableStream<Uint8Array>;
  arrayBuffer(): Promise<ArrayBuffer>;
}

export interface WritableStreamLike {
  write(chunk: Uint8Array): Promise<void>;
  close(): Promise<void>;
  abort(reason?: unknown): Promise<void>;
}

export interface DirectoryHandleLike {
  readonly kind: 'directory';
  readonly name: string;
  /** Yield child entries (file or directory). Used by `uploadDirectory`. */
  entries(): AsyncIterable<[string, DirectoryHandleLike | FileHandleLike]>;
  /** Used by `downloadDirectory` to create remote → local mapping. */
  getDirectoryHandle(name: string, opts?: { create?: boolean }): Promise<DirectoryHandleLike>;
  getFileHandle(name: string, opts?: { create?: boolean }): Promise<FileHandleLike>;
}

// ─── Bulk transfer types ─────────────────────────────────────

export type BulkTransferEvent =
  | { type: 'plan'; totalFiles: number; totalBytes: number | undefined }
  | { type: 'file-start'; path: string; size: number }
  | { type: 'file-progress'; path: string; bytesDone: number; bytesTotal: number }
  | { type: 'file-done'; path: string; bytesDone: number }
  | { type: 'file-error'; path: string; error: unknown }
  | {
      type: 'progress';
      filesDone: number;
      filesTotal: number;
      bytesDone: number;
      bytesTotal: number | undefined;
    }
  | { type: 'complete'; filesDone: number; bytesDone: number; durationMs: number }
  | { type: 'abort'; reason: string };

export interface BulkTransferResult {
  filesDone: number;
  bytesDone: number;
  durationMs: number;
}

export interface BulkTransferHandle {
  /** Async-iterable event stream — plan, per-file events, aggregate progress. */
  readonly events: AsyncIterable<BulkTransferEvent>;
  abort(reason?: string): Promise<void>;
  done(): Promise<BulkTransferResult>;
}

export interface BulkOpts {
  /**
   * Max files in flight at once. Default 4. Capped at 16 to bound memory
   * (each in-flight file may hold a buffered chunk; with 1 MiB chunks +
   * 16 lanes that's still bounded).
   */
  concurrency?: number;
  /**
   * Continue past per-file failures. Default false (fail-fast).
   * When true, errors are emitted via `file-error` events and the whole
   * transfer still resolves (with `done()` returning the count of
   * successful files).
   */
  continueOnError?: boolean;
  /** Cancellation. */
  signal?: AbortSignal;
}

/** Hard cap to bound memory regardless of caller-supplied concurrency. */
export const MAX_BULK_CONCURRENCY = 16;
/** Default concurrency. */
export const DEFAULT_BULK_CONCURRENCY = 4;
