/**
 * Tenant-aware cache key builder.
 * CRITICAL: Never cache tenant-specific data without tenant identity in the key.
 */

export function tenantCacheKey(
  tenantId: string,
  namespace: string,
  ...parts: Array<string | number | boolean | null | undefined>
): string {
  const suffix = parts
    .filter((part) => part !== null && part !== undefined && part !== "")
    .map(String)
    .join(":");
  return suffix
    ? `tenant:${tenantId}:${namespace}:${suffix}`
    : `tenant:${tenantId}:${namespace}`;
}

export function platformCacheKey(
  namespace: string,
  ...parts: Array<string | number | boolean | null | undefined>
): string {
  const suffix = parts
    .filter((part) => part !== null && part !== undefined && part !== "")
    .map(String)
    .join(":");
  return suffix ? `platform:${namespace}:${suffix}` : `platform:${namespace}`;
}

type CacheEntry<T> = {
  value: T;
  expiresAt: number;
};

/**
 * Development/in-process cache.
 * Production should swap Redis via the same interface.
 * Keys for tenant data MUST use tenantCacheKey().
 */
export class MemoryCache {
  private store = new Map<string, CacheEntry<unknown>>();

  get<T>(key: string): T | undefined {
    const entry = this.store.get(key);
    if (!entry) return undefined;
    if (Date.now() > entry.expiresAt) {
      this.store.delete(key);
      return undefined;
    }
    return entry.value as T;
  }

  set<T>(key: string, value: T, ttlSeconds: number): void {
    this.store.set(key, {
      value,
      expiresAt: Date.now() + ttlSeconds * 1000,
    });
  }

  delete(key: string): void {
    this.store.delete(key);
  }

  /** Invalidate all keys for a tenant namespace prefix. */
  invalidateTenant(tenantId: string, namespace?: string): void {
    const prefix = namespace
      ? `tenant:${tenantId}:${namespace}`
      : `tenant:${tenantId}:`;
    for (const key of this.store.keys()) {
      if (key.startsWith(prefix)) {
        this.store.delete(key);
      }
    }
  }
}

const globalForCache = globalThis as unknown as {
  archiCache?: MemoryCache;
};

export function getCache(): MemoryCache {
  if (!globalForCache.archiCache) {
    globalForCache.archiCache = new MemoryCache();
  }
  return globalForCache.archiCache;
}
