/**
 * withUserEdgeCache — thin edge-cache wrapper for per-user personalization data.
 *
 * Stores JSON in Cloudflare's `caches.default` keyed by a SHA-256 hash of
 * the supplied key string. Falls back to the loader directly when the Cache
 * API is unavailable (local dev, unit tests).
 *
 * NOT suitable for cacheable page responses — only for private /api/* endpoints
 * where Set-Cookie is permitted.
 */

import { bytesToHex } from '@/lib/encoding.js';
import { captureCaught } from '@/lib/observability';

const TEXT = new TextEncoder();

async function hashKey(key: string): Promise<string> {
  const buf = await crypto.subtle.digest('SHA-256', TEXT.encode(key));
  return bytesToHex(buf);
}

export async function withUserEdgeCache<T>(
  key: string,
  opts: { ttl: number; swr: number },
  loader: () => Promise<T>,
): Promise<T> {
  const cache: Cache | undefined = (caches as unknown as { default?: Cache }).default;
  if (!cache) return loader();

  const hash = await hashKey(key);
  const cacheReq = new Request(`https://_internal/mh-cache/${hash}`);

  try {
    const cached = await cache.match(cacheReq);
    if (cached) {
      const expires = Number(cached.headers.get('x-mh-expires') ?? 0);
      if (Date.now() < expires) return cached.json() as Promise<T>;
    }
  } catch (readErr) {
    captureCaught(readErr, {
      scope: 'server.middleware.with-edge-cache-user.read',
      severity: 'info',
    });
  }

  const fresh = await loader();

  try {
    const res = new Response(JSON.stringify(fresh), {
      headers: {
        'Cache-Control': `public, max-age=${opts.ttl + opts.swr}`,
        'x-mh-expires': String(Date.now() + opts.ttl * 1000),
        'Content-Type': 'application/json',
      },
    });
    await cache.put(cacheReq, res.clone());
  } catch (writeErr) {
    captureCaught(writeErr, {
      scope: 'server.middleware.with-edge-cache-user.write',
      severity: 'info',
    });
  }

  return fresh;
}
