import { StorageError, assertExactStorageKey, assertPresignExpiry } from "./storage.js";
//#region src/storage-memory.ts
async function bodyToBytes(body) {
	if (body instanceof Uint8Array) return body;
	if (body instanceof ArrayBuffer) return new Uint8Array(body);
	if (ArrayBuffer.isView(body)) return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
	if (typeof Blob !== "undefined" && body instanceof Blob) return new Uint8Array(await body.arrayBuffer());
	const reader = body.getReader();
	const chunks = [];
	for (;;) {
		const { done, value } = await reader.read();
		if (done) break;
		if (value) chunks.push(value);
	}
	const total = chunks.reduce((n, c) => n + c.length, 0);
	const out = new Uint8Array(total);
	let off = 0;
	for (const c of chunks) {
		out.set(c, off);
		off += c.length;
	}
	return out;
}
/** Cheap deterministic content etag (djb2 hex) — test double only, not a cryptographic digest. */
function etagOf(bytes) {
	let h = 5381;
	for (let i = 0; i < bytes.length; i++) h = (h << 5) + h + bytes[i] >>> 0;
	return `"${h.toString(16)}"`;
}
function streamOf(bytes) {
	return new ReadableStream({ start(controller) {
		controller.enqueue(bytes);
		controller.close();
	} });
}
/** In-memory StorageAdapter — the second real backend (a Map, not a mock of R2). */
function createMemoryStorage() {
	const store = /* @__PURE__ */ new Map();
	return {
		async put(key, body, opts) {
			const bytes = await bodyToBytes(body);
			const head = {
				key,
				size: bytes.length,
				etag: etagOf(bytes),
				contentType: opts?.contentType,
				customMetadata: opts?.customMetadata,
				uploadedAt: void 0
			};
			store.set(key, {
				bytes,
				head
			});
			return {
				key,
				size: bytes.length,
				etag: head.etag
			};
		},
		async get(key) {
			const entry = store.get(key);
			if (!entry) return null;
			return {
				...entry.head,
				body: streamOf(entry.bytes)
			};
		},
		async head(key) {
			return store.get(key)?.head ?? null;
		},
		async delete(key) {
			store.delete(key);
		},
		async list(opts) {
			const prefix = opts?.prefix ?? "";
			const limit = Math.min(Math.max(opts?.limit ?? 1e3, 1), 1e3);
			const offset = opts?.cursor ? Number.parseInt(opts.cursor, 10) || 0 : 0;
			const all = [...store.values()].map((e) => e.head).filter((h) => h.key.startsWith(prefix)).sort((a, b) => a.key.localeCompare(b.key));
			const page = all.slice(offset, offset + limit);
			const next = offset + limit;
			return {
				objects: page,
				cursor: next < all.length ? String(next) : void 0
			};
		},
		async presignPut(key, opts) {
			assertExactStorageKey(key);
			assertPresignExpiry(opts.expiresIn);
			return {
				url: `memory://${key}?expires=${opts.expiresIn}`,
				method: "PUT",
				headers: {},
				expiresIn: opts.expiresIn
			};
		},
		async presignGet(key, opts) {
			assertExactStorageKey(key);
			assertPresignExpiry(opts.expiresIn);
			return {
				url: `memory://${key}?expires=${opts.expiresIn}&op=get`,
				method: "GET",
				headers: {},
				expiresIn: opts.expiresIn
			};
		}
	};
}
//#endregion
export { StorageError, createMemoryStorage };
