"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_primordials_error = require('../primordials/error.js');
const require_primordials_map_set = require('../primordials/map-set.js');
const require_primordials_date = require('../primordials/date.js');
const require_debug_output = require('../debug/output.js');
const require_memo__internal = require('./_internal.js');

//#region src/memo/memoize.ts
/**
* @file `memoize` — synchronous function memoizer with LRU eviction (Map
*   insertion-order based), optional TTL, and optional custom key generator.
*   Each instance registers itself with the shared `cacheRegistry` so
*   `clearAllMemoizationCaches` can sweep it.
*/
/**
* Memoize a function with configurable caching behavior. Caches function
* results to avoid repeated computation.
*
* @example
*   import { memoize } from '@socketsecurity/lib/memo/memoize'
*
*   const expensiveOperation = memoize(
*     (n: number) => {
*       // Heavy computation
*       return Array(n)
*         .fill(0)
*         .reduce((a, _, i) => a + i, 0)
*     },
*     { maxSize: 100, ttl: 60000, name: 'sum' },
*   )
*
*   expensiveOperation(1000) // Computed
*   expensiveOperation(1000) // Cached
*
* @param fn - Function to memoize.
* @param options - Memoization options.
*
* @returns Memoized version of the function
*/
function memoize(fn, options = {}) {
	const { keyGen = (...args) => require_memo__internal.defaultKeyGen(args), maxSize = Number.POSITIVE_INFINITY, name = fn.name || "anonymous", ttl = Number.POSITIVE_INFINITY } = options;
	if (ttl < 0) throw new require_primordials_error.TypeErrorCtor("TTL must be non-negative");
	const cache = new require_primordials_map_set.MapCtor();
	require_memo__internal.cacheRegistry.push(() => {
		cache.clear();
	});
	function evictLRU() {
		if (cache.size >= maxSize) {
			const oldest = cache.keys().next().value;
			/* c8 ignore next 8 - cache.size >= maxSize guarantees keys().next()
			yields a defined value; the undefined branch is defensive. */
			if (oldest !== void 0) {
				cache.delete(oldest);
				require_debug_output.debugLog(`[memoize:${name}] clear`, {
					key: oldest,
					reason: "LRU"
				});
			}
		}
	}
	function isExpired(entry) {
		if (ttl === Number.POSITIVE_INFINITY) return false;
		return require_primordials_date.DateNow() - entry.timestamp > ttl;
	}
	return function memoized(...args) {
		const key = keyGen(...args);
		const cached = cache.get(key);
		if (cached) {
			if (!isExpired(cached)) {
				cached.hits++;
				cache.delete(key);
				cache.set(key, cached);
				require_debug_output.debugLog(`[memoize:${name}] hit`, {
					key,
					hits: cached.hits
				});
				return cached.value;
			}
			cache.delete(key);
		}
		require_debug_output.debugLog(`[memoize:${name}] miss`, { key });
		const value = fn(...args);
		evictLRU();
		cache.set(key, {
			value,
			timestamp: Date.now(),
			hits: 0
		});
		require_debug_output.debugLog(`[memoize:${name}] set`, {
			key,
			cacheSize: cache.size
		});
		return value;
	};
}

//#endregion
exports.memoize = memoize;