"use client";

/**
 * Client-side in-memory query cache for Quto AI Admin.
 * 
 * Provides:
 * 1. Instant tab navigation without redundant MongoDB queries.
 * 2. Category-based TTL (Read-heavy categories: 5m, Admin lists: 60s).
 * 3. Targeted cache invalidation upon mutations (e.g. invalidateAdminCache("posts")).
 * 4. Fresh data guaranteed on mutation.
 * 5. Isolation: in-memory per browser session; never shared across users.
 */

interface CacheEntry<T> {
  data: T;
  timestamp: number;
  tags?: string[];
}

const cacheStore = new Map<string, CacheEntry<unknown>>();

// Default TTLs by category
export const CACHE_TTL = {
  STATIC_READ_HEAVY: 5 * 60 * 1000, // 5 minutes (Categories, Settings, Static Config)
  ADMIN_LIST: 60 * 1000,             // 60 seconds (Posts list, Media list, Users)
  SHORT_LIVED: 15 * 1000,            // 15 seconds
};

/**
 * Fetches data with intelligent in-memory caching.
 */
export async function fetchWithAdminCache<T>(
  url: string,
  options?: {
    ttlMs?: number;
    tags?: string[];
    forceFresh?: boolean;
  }
): Promise<T> {
  const ttl = options?.ttlMs ?? CACHE_TTL.ADMIN_LIST;
  const now = Date.now();
  const cached = cacheStore.get(url) as CacheEntry<T> | undefined;

  if (!options?.forceFresh && cached && now - cached.timestamp < ttl) {
    return cached.data;
  }

  const res = await fetch(url);
  if (!res.ok) {
    let errMessage = `Request failed: ${res.status}`;
    try {
      const json = await res.json();
      if (json.error) errMessage = json.error;
    } catch {}
    throw new Error(errMessage);
  }

  const data = (await res.json()) as T;
  cacheStore.set(url, {
    data,
    timestamp: now,
    tags: options?.tags,
  });

  return data;
}

/**
 * Selectively invalidates cached entries by pattern (URL substring) or tag.
 * If no pattern is provided, clears the entire admin client cache.
 */
export function invalidateAdminCache(patternOrTag?: string): void {
  if (!patternOrTag) {
    cacheStore.clear();
    return;
  }

  const keysToDelete: string[] = [];
  for (const [key, entry] of cacheStore.entries()) {
    if (
      key.includes(patternOrTag) ||
      (entry.tags && entry.tags.includes(patternOrTag))
    ) {
      keysToDelete.push(key);
    }
  }

  for (const key of keysToDelete) {
    cacheStore.delete(key);
  }

  // Also dispatch window custom event for decoupled components
  if (typeof window !== "undefined") {
    window.dispatchEvent(
      new CustomEvent("quto:admin-cache-invalidated", {
        detail: { pattern: patternOrTag },
      })
    );
  }
}

// Global listener for cross-component cache invalidation
if (typeof window !== "undefined") {
  window.addEventListener("quto:invalidate-cache", ((event: CustomEvent<{ pattern?: string }>) => {
    invalidateAdminCache(event.detail?.pattern);
  }) as EventListener);
}
