import { cache } from 'cloudflare:workers';
import { env } from '@/server/env';
import { doGetCacheEpoch, doBumpCacheEpoch } from '@/server/do-client.js';
import { captureCaught } from '@/lib/observability';

const EPOCH_READ_TTL_MS = 5000;
const COLO_CACHE_URL = 'https://epoch.internal/catalog';

let cachedEpoch = 0;
let cachedAt = 0;

export function getCachedEpochSnapshot(): number {
  return cachedEpoch;
}

/**
 * Current catalog epoch. Isolate-cached for 5s (the staleness floor). On a cold
 * isolate, tries a colo-local caches.default entry before the cross-region DO.
 * Fail-safe: returns the last-known value (or 0) on any error — degrades to
 * BUILD_ID-only keying, never throws into the request path.
 */
export async function getEpoch(): Promise<number> {
  const now = Date.now();
  if (now - cachedAt < EPOCH_READ_TTL_MS) return cachedEpoch;

  const cache = (globalThis as { caches?: { default?: Cache } }).caches?.default;
  if (cache) {
    try {
      const hit = await cache.match(COLO_CACHE_URL);
      if (hit) {
        const { epoch } = (await hit.json()) as { epoch: number };
        cachedEpoch = epoch;
        cachedAt = now;
        return epoch;
      }
    } catch (err) {
      captureCaught(err, { scope: 'server.cache.epoch.colo-read', severity: 'info' });
    }
  }

  try {
    const epoch = await doGetCacheEpoch(env);
    cachedEpoch = epoch;
    cachedAt = now;
    if (cache) {
      const resp = new Response(JSON.stringify({ epoch }), {
        headers: { 'Cache-Control': 's-maxage=5', 'Content-Type': 'application/json' },
      });
      void cache.put(COLO_CACHE_URL, resp).catch((err) => {
        captureCaught(err, { scope: 'server.cache.epoch.colo-write', severity: 'info' });
      });
    }
    return epoch;
  } catch (err) {
    captureCaught(err, { scope: 'server.cache.epoch.do-read', severity: 'info' });
    return cachedEpoch; // last-known or 0
  }
}

/** Bump epoch (correctness mutation). Updates the isolate cache immediately so the
 * mutating request and its colo observe the new value at once. Fail-safe: logs, no throw. */
export async function bumpEpoch(): Promise<number> {
  try {
    const epoch = await doBumpCacheEpoch(env);
    cachedEpoch = epoch;
    cachedAt = Date.now();
    const oldEpoch = epoch - 1;
    if (oldEpoch >= 0 && typeof cache?.purge === 'function') {
      void cache.purge({ tags: [`epoch:${oldEpoch}`] }).catch((err) => {
        captureCaught(err, { scope: 'server.cache.epoch.purge', severity: 'info' });
      });
    }
    return epoch;
  } catch (err) {
    captureCaught(err, { scope: 'server.cache.epoch.bump', severity: 'error' });
    return cachedEpoch;
  }
}
