/**
 * In-Memory Cache Store
 *
 * Simple implementation for development and testing.
 * Not suitable for production (no persistence, single-instance only).
 *
 * @internal This is reserved for future extensibility.
 * For segment caching, use MemorySegmentCacheStore instead.
 */
// ============================================================================
// Constants
// ============================================================================
/** Default TTL when no explicit value is provided */
const DEFAULT_TTL_SECONDS = 60;
/**
 * In-memory cache store implementation
 */
export class MemoryCacheStore {
    constructor() {
        this.cache = new Map();
    }
    async match(key) {
        const entry = this.cache.get(key);
        if (!entry) {
            return undefined;
        }
        // Check expiration
        if (entry.metadata.expiresAt && Date.now() > entry.metadata.expiresAt) {
            this.cache.delete(key);
            return undefined;
        }
        // Reconstruct value based on original type
        const value = this.reconstructValue(entry);
        return {
            value: value,
            metadata: entry.metadata,
        };
    }
    async put(key, value, options) {
        const ttl = options?.ttl ?? DEFAULT_TTL_SECONDS;
        const expiresAt = Date.now() + ttl * 1000;
        // Detect value type and convert for storage
        const { storedValue, valueType, responseHeaders, responseStatus } = await this.prepareForStorage(value);
        const metadata = {
            ...options?.metadata,
            expiresAt,
            valueType,
            responseHeaders,
            responseStatus,
        };
        this.cache.set(key, {
            value: storedValue,
            metadata,
        });
    }
    async delete(key) {
        return this.cache.delete(key);
    }
    /**
     * Clear all entries (useful for testing)
     */
    clear() {
        this.cache.clear();
    }
    /**
     * Get current cache size (useful for testing/debugging)
     */
    get size() {
        return this.cache.size;
    }
    /**
     * Manually purge expired entries
     */
    purgeExpired() {
        const now = Date.now();
        let purged = 0;
        for (const [key, entry] of this.cache) {
            if (entry.metadata.expiresAt && now > entry.metadata.expiresAt) {
                this.cache.delete(key);
                purged++;
            }
        }
        return purged;
    }
    /**
     * Prepare a value for storage
     * Converts streams and responses to ArrayBuffer, detects type
     */
    async prepareForStorage(value) {
        // ReadableStream -> ArrayBuffer
        if (value instanceof ReadableStream) {
            return {
                storedValue: await streamToArrayBuffer(value),
                valueType: "stream",
            };
        }
        // Response -> ArrayBuffer + headers/status
        if (value instanceof Response) {
            const headers = {};
            value.headers.forEach((v, k) => {
                headers[k] = v;
            });
            return {
                storedValue: await value.clone().arrayBuffer(),
                valueType: "response",
                responseHeaders: headers,
                responseStatus: value.status,
            };
        }
        // ArrayBuffer -> store as-is
        if (value instanceof ArrayBuffer) {
            return {
                storedValue: value,
                valueType: "arraybuffer",
            };
        }
        // String -> store as-is
        if (typeof value === "string") {
            return {
                storedValue: value,
                valueType: "string",
            };
        }
        // Object -> store as-is (JSON-serializable)
        return {
            storedValue: value,
            valueType: "object",
        };
    }
    /**
     * Reconstruct original value type from stored entry
     */
    reconstructValue(entry) {
        const { value, metadata } = entry;
        switch (metadata.valueType) {
            case "stream":
                return arrayBufferToStream(value);
            case "response": {
                const status = metadata.responseStatus ?? 200;
                // Status codes 204 (No Content) and 304 (Not Modified) cannot have a body
                const isNullBodyStatus = status === 204 || status === 304;
                return new Response(isNullBodyStatus ? null : value, {
                    status,
                    headers: metadata.responseHeaders,
                });
            }
            case "arraybuffer":
            case "string":
            case "object":
            default:
                return value;
        }
    }
}
/**
 * Convert a ReadableStream to ArrayBuffer.
 * @internal
 */
async function streamToArrayBuffer(stream) {
    const chunks = [];
    const reader = stream.getReader();
    while (true) {
        const { done, value } = await reader.read();
        if (done)
            break;
        chunks.push(value);
    }
    // Concatenate chunks
    const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
    const result = new Uint8Array(totalLength);
    let offset = 0;
    for (const chunk of chunks) {
        result.set(chunk, offset);
        offset += chunk.length;
    }
    return result.buffer;
}
/**
 * Convert an ArrayBuffer to a ReadableStream.
 * @internal
 */
function arrayBufferToStream(buffer) {
    const uint8 = new Uint8Array(buffer);
    return new ReadableStream({
        start(controller) {
            controller.enqueue(uint8);
            controller.close();
        },
    });
}
//# sourceMappingURL=memory-store.js.map