/**
 * Persists the React Query cache to IndexedDB so the dashboard is *viewable*
 * offline (last-synced data) and survives a reload with no connection.
 *
 * Uses `dehydrate`/`hydrate` from @tanstack/react-query directly — no extra
 * dependency. Writes are debounced; reads are guarded by a schema buster, a
 * max-age, and a tenant scope so one café never hydrates another's data.
 */
import { dehydrate, hydrate, type QueryClient } from "@tanstack/react-query";
import { kvGet, kvSet } from "@/lib/offline/offline-db";

const CACHE_KEY = "rq-cache";
/** Bump when cached shapes change so stale persisted data is dropped on deploy. */
const BUSTER = "v1";
const MAX_AGE_MS = 24 * 60 * 60 * 1000; // 24h
const SAVE_DEBOUNCE_MS = 1000;

type PersistedCache = {
  buster: string;
  timestamp: number;
  /** Tenant/user scope this cache belongs to (cafeId, or "anon"). */
  scope: string;
  state: unknown;
};

/**
 * Hydrate the query cache from IndexedDB if a valid snapshot exists for this
 * scope. Safe to call before or after queries mount.
 */
export async function restoreQueryCache(qc: QueryClient, scope: string): Promise<void> {
  const saved = await kvGet<PersistedCache>(CACHE_KEY);
  if (!saved) return;
  if (saved.buster !== BUSTER) return; // schema changed
  if (saved.scope !== scope) return; // different tenant/user — do not leak
  if (Date.now() - saved.timestamp > MAX_AGE_MS) return; // too old
  try {
    hydrate(qc, saved.state as never);
  } catch {
    // corrupt snapshot — ignore, it will be overwritten on next save
  }
}

/**
 * Subscribe to cache changes and persist a debounced snapshot. Returns an
 * unsubscribe function.
 */
export function startPersisting(qc: QueryClient, scope: string): () => void {
  let timer: ReturnType<typeof setTimeout> | null = null;

  const save = () => {
    timer = null;
    const snapshot: PersistedCache = {
      buster: BUSTER,
      timestamp: Date.now(),
      scope,
      state: dehydrate(qc),
    };
    void kvSet(CACHE_KEY, snapshot);
  };

  const unsubscribe = qc.getQueryCache().subscribe(() => {
    if (timer) return; // a save is already scheduled
    timer = setTimeout(save, SAVE_DEBOUNCE_MS);
  });

  return () => {
    if (timer) clearTimeout(timer);
    unsubscribe();
  };
}
