import { cache, YEAR_MS } from '$lib/server/cache';

// MusicBrainz requires an identifying User-Agent or it will block requests.
const MB_USER_AGENT = 'baileys-website/1.0 (https://tangled.org/pds.dad/my-website)';

/** Release MBIDs arrive either bare or as `mbid:<uuid>` — normalise to bare. */
function normaliseMbid(mbid: string): string {
	return mbid.replace(/^mbid:/, '');
}

/**
 * Probe the Cover Art Archive for a release's front cover. Not every release
 * has art in the CAA, so we HEAD the URL and only return it when it resolves.
 * Results (including misses) are memoised per MBID in the shared cache so the
 * same release isn't re-probed across a page full of plays.
 */
async function probeCoverArt(fetch: typeof globalThis.fetch, mbid: string): Promise<string | null> {
	const id = normaliseMbid(mbid);
	if (!id) return null;

	const cacheKey = `coverart:${id}`;
	const cached = cache.get(cacheKey) as { url: string | null } | null;
	if (cached) return cached.url;

	const url = `https://coverartarchive.org/release/${id}/front-500`;
	let resolved: string | null = null;
	try {
		const res = await fetch(url, { method: 'HEAD', redirect: 'follow' });
		if (res.ok) resolved = url;
	} catch {
		// network error — treat as a miss
	}

	cache.setWithExpiry(cacheKey, { url: resolved }, YEAR_MS);
	return resolved;
}

/**
 * Resolve album artwork for a single track. When a `releaseMbId` is available
 * (e.g. play-history records) the direct CAA probe is enough. The ISRC →
 * MusicBrainz → release lookup is the richer fallback used for "now playing",
 * but it costs extra requests and MusicBrainz rate-limits (~1 req/s), so it is
 * opt-in via `useIsrcLookup` and should stay off for bulk history.
 */
export async function resolveCoverArt(
	fetch: typeof globalThis.fetch,
	opts: {
		isrc?: string | null;
		releaseMbId?: string | null;
		releaseName?: string | null;
		useIsrcLookup?: boolean;
	}
): Promise<string | null> {
	const candidates: string[] = [];

	if (opts.useIsrcLookup && opts.isrc) {
		try {
			const isrcRes = await fetch(
				`https://musicbrainz.org/ws/2/isrc/${encodeURIComponent(opts.isrc)}?fmt=json`,
				{ headers: { 'User-Agent': MB_USER_AGENT } }
			);
			const recordingId = isrcRes.ok
				? ((await isrcRes.json()) as { recordings?: { id: string }[] }).recordings?.[0]?.id
				: undefined;

			if (recordingId) {
				const relRes = await fetch(
					`https://musicbrainz.org/ws/2/release?recording=${recordingId}&fmt=json`,
					{ headers: { 'User-Agent': MB_USER_AGENT } }
				);
				if (relRes.ok) {
					const releases =
						((await relRes.json()) as { releases?: { id: string; title?: string }[] }).releases ??
						[];
					// An ISRC's recording often appears on many releases (singles,
					// comps, regional editions). Prefer the one whose title matches
					// what's playing.
					const wanted = opts.releaseName?.toLowerCase();
					const seen = new Set<string>();
					for (const r of [
						...releases.filter((r) => wanted && r.title?.toLowerCase() === wanted),
						...releases
					]) {
						if (!seen.has(r.id)) {
							seen.add(r.id);
							candidates.push(r.id);
						}
					}
				}
			}
		} catch (error) {
			console.warn('MusicBrainz ISRC lookup failed:', error);
		}
	}

	// Release MBID supplied directly by the record.
	if (opts.releaseMbId) candidates.push(opts.releaseMbId);

	for (const mbid of candidates.slice(0, 5)) {
		const url = await probeCoverArt(fetch, mbid);
		if (url) return url;
	}

	return null;
}
