// Copyright 2017-2025 @pezkuwi/api-derive authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { DeriveCache } from './types.js';

import { deriveNoopCache } from './cacheImpl.js';

interface CacheValue<T> {
  v: T;
  x: number;
}

const CACHE_EXPIRY = 7 * (24 * 60) * (60 * 1000);

let deriveCache: DeriveCache;

function wrapCache (keyStart: string, cache: DeriveCache): DeriveCache {
  return {
    del: (partial: string): void => cache.del(`${keyStart}${partial}`),
    forEach: cache.forEach,
    get: <T> (partial: string): T | undefined => {
      const key = `${keyStart}${partial}`;
      const cached = cache.get<CacheValue<T>>(key);

      if (cached) {
        cached.x = Date.now();
        cache.set(key, cached);

        return cached.v;
      }

      return undefined;
    },
    set: (partial: string, v: unknown): void => {
      cache.set(`${keyStart}${partial}`, { v, x: Date.now() });
    }
  };
}

function clearCache (cache: DeriveCache): void {
  // clear all expired values
  const now = Date.now();
  const all: string[] = [];

  cache.forEach((key: string, { x }: CacheValue<any>): void => {
    ((now - x) > CACHE_EXPIRY) && all.push(key);
  });

  // don't do delete inside loop, just in-case
  all.forEach((key) => cache.del(key));
}

export function setDeriveCache (prefix = '', cache?: DeriveCache): void {
  deriveCache = cache
    ? wrapCache(`derive:${prefix}:`, cache)
    : deriveNoopCache;

  if (cache) {
    clearCache(cache);
  }
}

setDeriveCache();

export { deriveCache };
