---
import { getFontsPackageInfo, getFontsCss } from 'astro-font-loader';
import type { FontConfig, PreloadEntry } from 'astro-font-loader';

interface Props {
	/** Font configurations to load. */
	fonts: FontConfig[];
	/** Output directory name used in generated font URLs. */
	outputDirectory: string;
	/** Variants to preload, with optional weight/style narrowing and media queries. */
	preload?: PreloadEntry[];
	/** Root directory to resolve font packages from. Defaults to process.cwd(). */
	root?: string;
}

const MIME_TYPES: Record<string, string> = {
	woff2: 'font/woff2',
	woff: 'font/woff',
	ttf: 'font/ttf',
	otf: 'font/otf',
	eot: 'application/vnd.ms-fontobject',
};

function getMimeType(filename: string): string {
	const ext = filename.split('.').pop()?.toLowerCase() ?? '';
	return MIME_TYPES[ext] ?? 'font/woff2';
}

function weightEquals(
	a: number | [number, number],
	b: number | [number, number],
): boolean {
	if (Array.isArray(a) && Array.isArray(b)) {
		return a[0] === b[0] && a[1] === b[1];
	}
	return a === b;
}

const {
	fonts,
	outputDirectory,
	preload = [],
	root = process.cwd(),
} = Astro.props;

const preloadHrefs: Array<{ href: string; type: string; media?: string }> = [];
const seenHrefs = new Set<string>();
let allCss = '';

for (const fontConfig of fonts) {
	const { source } = fontConfig;
	const packageInfo = getFontsPackageInfo(source.package, root, source.styleFile);
	if (!packageInfo) continue;

	for (const variant of fontConfig.variants) {
		const result = getFontsCss(
			{ name: variant.name, variants: [variant], outputDirectory },
			packageInfo,
		);
		allCss += result.css;

		const entry = preload.find((p) => {
			if (p.variant.toLowerCase() !== variant.name.toLowerCase()) {
				return false;
			}

			if (p.weight !== undefined && !weightEquals(p.weight, variant.weight)) {
				return false;
			}

			if (p.styles && !p.styles.every((s) => variant.styles.includes(s))) {
				return false;
			}

			return true;
		});

		if (entry) {
			for (const filename of result.filenames) {
				const href = `/${outputDirectory}/${filename}`;
				if (!seenHrefs.has(href)) {
					seenHrefs.add(href);
					preloadHrefs.push({
						href,
						type: getMimeType(filename),
						media: entry.media,
					});
				}
			}
		}
	}
}
---

{preloadHrefs.map(({ href, type, media }) => (
	<link rel="preload" as="font" crossorigin href={href} type={type} media={media} />
))}
{allCss && <style set:html={allCss} is:inline />}
