import { bundledSnapshots } from "./bundled-snapshots";
import { DEFAULT_CHAIN, getChain, CHAINS } from "./chains";
import { isSnapshotSet, mergeSnapshots, type SnapshotSet } from "./liquidity-set";
import { readSharedSnapshots, refreshSharedSnapshots, readFeedStatuses } from "./shared-liquidity";
import { edgeCache } from "./edge-cache";
import { FRESH_MS } from "./feed-config";
import { type FeedEnvironment } from "./liquidity-provider";

type Background = { waitUntil(promise: Promise<unknown>): void };
export async function serveLiquidity(request: Request, background?: Background, db?: D1Database, env: FeedEnvironment = {}): Promise<Response> {
  const selected = getChain(new URL(request.url).searchParams.get("chain") ?? DEFAULT_CHAIN.id);
  if (!selected) return Response.json({ error: "Unsupported chain" }, { status: 400 });
  const cache = await edgeCache();
  const key = new Request(new URL("/__liquidity_snapshot_all_v1", request.url));
  let best = bundledSnapshots;
  let source = "bundled";
  try {
    const hit = await cache?.match(key);
    const candidate: unknown = hit ? await hit.json() : null;
    if (isSnapshotSet(candidate)) { best = mergeSnapshots(best, candidate); source = "edge-cache"; }
  } catch { /* Durable and bundled copies cover unavailable edge storage. */ }
  if (db) {
    try {
      const saved = await readSharedSnapshots(db);
      best = mergeSnapshots(best, saved);
      if (saved[selected.id] && Date.parse(saved[selected.id]!.updatedAt) >= Date.parse(best[selected.id].updatedAt)) source = "database";
    } catch (error) { console.warn("Liquidity snapshot read failed", error instanceof Error ? error.message : "database error"); }
    const update = refreshSharedSnapshots(db, env).catch(error => { console.warn("Liquidity collection failed", error instanceof Error ? error.message : "collector error"); return null; });
    background?.waitUntil(update);
    let timer: ReturnType<typeof setTimeout> | undefined;
    const fresh = await Promise.race([update, new Promise<null>(resolve => { timer = setTimeout(() => resolve(null), 1_200); })]);
    clearTimeout(timer);
    if (fresh?.chainId) { best = mergeSnapshots(best, { [fresh.chainId]: fresh }); if (fresh.chainId === selected.id) source = "live"; }
    try {
      const statuses = await readFeedStatuses(db, env);
      best = Object.fromEntries(CHAINS.map(({ id }) => [id, { ...best[id], feed: statuses[id] }])) as SnapshotSet;
    } catch { /* The observation age remains visible. */ }
  }
  const snapshots = Object.fromEntries(CHAINS.map(({ id }) => [id, { ...best[id], stale: Boolean(best[id].stale || Date.now() - Date.parse(best[id].updatedAt) > FRESH_MS) }])) as SnapshotSet;
  try { background?.waitUntil((cache?.put(key, Response.json(best, { headers: { "Cache-Control": "public, max-age=86400" } })) ?? Promise.resolve()).catch(() => {})); } catch { /* Optional edge cache. */ }
  return Response.json({ ...snapshots[selected.id], chains: snapshots }, { headers: {
    "Cache-Control": "no-store", "X-Data-Source": source, "X-Data-Updated-At": snapshots[selected.id].updatedAt,
    "X-Feed-State": snapshots[selected.id].feed?.state ?? "unconfigured", "X-Content-Type-Options": "nosniff",
  } });
}
