import { withLeadingSlash } from "ufo";
//#region src/runtime.ts
function createRendererContext({ manifest, precomputed, buildAssetsURL, dependencySetsCacheSize }) {
	if (!manifest && !precomputed) throw new Error("Either manifest or precomputed data must be provided");
	const ctx = {
		buildAssetsURL: buildAssetsURL || withLeadingSlash,
		manifest,
		precomputed,
		updateManifest,
		_dependencies: {},
		_dependencySets: /* @__PURE__ */ new Map(),
		_dependencySetsCacheSize: typeof dependencySetsCacheSize === "number" && Number.isFinite(dependencySetsCacheSize) && dependencySetsCacheSize > 0 ? Math.floor(dependencySetsCacheSize) : dependencySetsCacheSize === void 0 ? 1e3 : 0,
		_entrypoints: []
	};
	function updateManifest(manifest) {
		const manifestEntries = Object.entries(manifest);
		ctx.manifest = manifest;
		ctx._dependencies = {};
		ctx._dependencySets.clear();
		ctx._entrypoints = manifestEntries.filter((e) => e[1].isEntry).map(([module]) => module);
	}
	if (precomputed) {
		ctx._dependencies = precomputed.dependencies;
		ctx._entrypoints = precomputed.entrypoints;
	} else if (manifest) updateManifest(manifest);
	return ctx;
}
function getModuleDependencies(id, rendererContext) {
	if (rendererContext._dependencies[id]) return rendererContext._dependencies[id];
	const dependencies = rendererContext._dependencies[id] = {
		scripts: {},
		styles: {},
		preload: {},
		prefetch: {}
	};
	if (!rendererContext.manifest) return dependencies;
	const meta = rendererContext.manifest[id];
	if (!meta) return dependencies;
	if (meta.file) {
		dependencies.preload[id] = meta;
		if (meta.isEntry || meta.sideEffects) dependencies.scripts[id] = meta;
	}
	for (const css of meta.css || []) dependencies.styles[css] = dependencies.preload[css] = dependencies.prefetch[css] = rendererContext.manifest[css];
	for (const asset of meta.assets || []) dependencies.preload[asset] = dependencies.prefetch[asset] = rendererContext.manifest[asset];
	for (const depId of meta.imports || []) {
		const depDeps = getModuleDependencies(depId, rendererContext);
		for (const key in depDeps.styles) dependencies.styles[key] = depDeps.styles[key];
		for (const key in depDeps.preload) dependencies.preload[key] = depDeps.preload[key];
		for (const key in depDeps.prefetch) dependencies.prefetch[key] = depDeps.prefetch[key];
	}
	const filteredPreload = {};
	for (const id in dependencies.preload) {
		const dep = dependencies.preload[id];
		if (dep.preload) filteredPreload[id] = dep;
	}
	dependencies.preload = filteredPreload;
	return dependencies;
}
function getAllDependencies(ids, rendererContext) {
	const cacheSize = rendererContext._dependencySetsCacheSize;
	const useCache = cacheSize > 0;
	let cacheKey = "";
	if (useCache) {
		if (ids.size <= 1) for (const id of ids) cacheKey = id;
		else cacheKey = [...ids].sort().join(",");
		const cached = rendererContext._dependencySets.get(cacheKey);
		if (cached !== void 0) {
			if (rendererContext._dependencySets.size >= cacheSize) {
				rendererContext._dependencySets.delete(cacheKey);
				rendererContext._dependencySets.set(cacheKey, cached);
			}
			return cached;
		}
	}
	const allDeps = {
		scripts: {},
		styles: {},
		preload: {},
		prefetch: {}
	};
	for (const id of ids) {
		const deps = getModuleDependencies(id, rendererContext);
		for (const key in deps.scripts) allDeps.scripts[key] = deps.scripts[key];
		for (const key in deps.styles) allDeps.styles[key] = deps.styles[key];
		for (const key in deps.preload) allDeps.preload[key] = deps.preload[key];
		for (const key in deps.prefetch) allDeps.prefetch[key] = deps.prefetch[key];
		for (const dynamicDepId of rendererContext.manifest?.[id]?.dynamicImports || []) {
			const dynamicDeps = getModuleDependencies(dynamicDepId, rendererContext);
			for (const key in dynamicDeps.scripts) allDeps.prefetch[key] = dynamicDeps.scripts[key];
			for (const key in dynamicDeps.styles) allDeps.prefetch[key] = dynamicDeps.styles[key];
			for (const key in dynamicDeps.preload) allDeps.prefetch[key] = dynamicDeps.preload[key];
		}
	}
	const filteredPrefetch = {};
	for (const id in allDeps.prefetch) {
		const dep = allDeps.prefetch[id];
		if (dep.prefetch) filteredPrefetch[id] = dep;
	}
	allDeps.prefetch = filteredPrefetch;
	for (const id in allDeps.preload) delete allDeps.prefetch[id];
	for (const style in allDeps.styles) {
		delete allDeps.preload[style];
		delete allDeps.prefetch[style];
	}
	if (useCache) {
		rendererContext._dependencySets.set(cacheKey, allDeps);
		if (rendererContext._dependencySets.size > cacheSize) {
			const oldest = rendererContext._dependencySets.keys().next().value;
			if (oldest !== void 0) rendererContext._dependencySets.delete(oldest);
		}
	}
	return allDeps;
}
function getRequestDependencies(ssrContext, rendererContext, options) {
	const excluded = options?.exclude ? new Set(options.exclude) : void 0;
	const hasExcluded = excluded && excluded.size > 0;
	if (!hasExcluded && ssrContext._requestDependencies) return ssrContext._requestDependencies;
	let ids;
	const requestIds = ssrContext.modules || ssrContext._registeredComponents;
	if (hasExcluded) {
		ids = /* @__PURE__ */ new Set();
		for (const id of rendererContext._entrypoints) if (!excluded.has(id)) ids.add(id);
		if (requestIds) {
			for (const id of requestIds) if (!excluded.has(id)) ids.add(id);
		}
	} else {
		ids = new Set(rendererContext._entrypoints);
		if (requestIds) for (const id of requestIds) ids.add(id);
	}
	const deps = getAllDependencies(ids, rendererContext);
	if (!hasExcluded) ssrContext._requestDependencies = deps;
	return deps;
}
function renderStyles(ssrContext, rendererContext) {
	const { styles } = getRequestDependencies(ssrContext, rendererContext);
	let result = "";
	for (const key in styles) {
		const resource = styles[key];
		result += `<link rel="stylesheet" href="${rendererContext.buildAssetsURL(resource.file)}" crossorigin>`;
	}
	return result;
}
function getResources(ssrContext, rendererContext) {
	return [...getPreloadLinks(ssrContext, rendererContext), ...getPrefetchLinks(ssrContext, rendererContext)];
}
function renderResourceHints(ssrContext, rendererContext, options) {
	const { preload, prefetch } = getRequestDependencies(ssrContext, rendererContext, options);
	let result = "";
	for (const key in preload) {
		const resource = preload[key];
		const href = rendererContext.buildAssetsURL(resource.file);
		const rel = resource.module ? "modulepreload" : "preload";
		const crossorigin = resource.resourceType === "style" || resource.resourceType === "font" || resource.resourceType === "script" || resource.module ? " crossorigin" : "";
		if (resource.resourceType && resource.mimeType) result += `<link rel="${rel}" as="${resource.resourceType}" type="${resource.mimeType}"${crossorigin} href="${href}">`;
		else if (resource.resourceType) result += `<link rel="${rel}" as="${resource.resourceType}"${crossorigin} href="${href}">`;
		else result += `<link rel="${rel}"${crossorigin} href="${href}">`;
	}
	for (const key in prefetch) {
		const resource = prefetch[key];
		const href = rendererContext.buildAssetsURL(resource.file);
		const crossorigin = resource.resourceType === "style" || resource.resourceType === "font" || resource.resourceType === "script" || resource.module ? " crossorigin" : "";
		if (resource.resourceType && resource.mimeType) result += `<link rel="prefetch" as="${resource.resourceType}" type="${resource.mimeType}"${crossorigin} href="${href}">`;
		else if (resource.resourceType) result += `<link rel="prefetch" as="${resource.resourceType}"${crossorigin} href="${href}">`;
		else result += `<link rel="prefetch"${crossorigin} href="${href}">`;
	}
	return result;
}
function renderResourceHeaders(ssrContext, rendererContext, options) {
	const { preload, prefetch } = getRequestDependencies(ssrContext, rendererContext, options);
	const links = [];
	for (const key in preload) {
		const resource = preload[key];
		let header = `<${rendererContext.buildAssetsURL(resource.file)}>; rel="${resource.module ? "modulepreload" : "preload"}"`;
		if (resource.resourceType) header += `; as="${resource.resourceType}"`;
		if (resource.mimeType) header += `; type="${resource.mimeType}"`;
		if (resource.resourceType === "style" || resource.resourceType === "font" || resource.resourceType === "script" || resource.module) header += "; crossorigin";
		links.push(header);
	}
	for (const key in prefetch) {
		const resource = prefetch[key];
		let header = `<${rendererContext.buildAssetsURL(resource.file)}>; rel="prefetch"`;
		if (resource.resourceType) header += `; as="${resource.resourceType}"`;
		if (resource.mimeType) header += `; type="${resource.mimeType}"`;
		if (resource.resourceType === "style" || resource.resourceType === "font" || resource.resourceType === "script" || resource.module) header += "; crossorigin";
		links.push(header);
	}
	return { link: links.join(", ") };
}
function getPreloadLinks(ssrContext, rendererContext, options) {
	const { preload } = getRequestDependencies(ssrContext, rendererContext, options);
	const result = [];
	for (const key in preload) {
		const resource = preload[key];
		result.push({
			rel: resource.module ? "modulepreload" : "preload",
			as: resource.resourceType,
			type: resource.mimeType ?? null,
			crossorigin: resource.resourceType === "style" || resource.resourceType === "font" || resource.resourceType === "script" || resource.module ? "" : null,
			href: rendererContext.buildAssetsURL(resource.file)
		});
	}
	return result;
}
function getPrefetchLinks(ssrContext, rendererContext, options) {
	const { prefetch } = getRequestDependencies(ssrContext, rendererContext, options);
	const result = [];
	for (const key in prefetch) {
		const resource = prefetch[key];
		result.push({
			rel: "prefetch",
			as: resource.resourceType,
			type: resource.mimeType ?? null,
			crossorigin: resource.resourceType === "style" || resource.resourceType === "font" || resource.resourceType === "script" || resource.module ? "" : null,
			href: rendererContext.buildAssetsURL(resource.file)
		});
	}
	return result;
}
function renderScripts(ssrContext, rendererContext) {
	const { scripts } = getRequestDependencies(ssrContext, rendererContext);
	let result = "";
	for (const key in scripts) {
		const resource = scripts[key];
		if (resource.module) result += `<script type="module" src="${rendererContext.buildAssetsURL(resource.file)}" crossorigin><\/script>`;
		else result += `<script src="${rendererContext.buildAssetsURL(resource.file)}" defer crossorigin><\/script>`;
	}
	return result;
}
function createRenderer(createApp, renderOptions) {
	const rendererContext = createRendererContext(renderOptions);
	return {
		rendererContext,
		async renderToString(ssrContext) {
			ssrContext._registeredComponents = ssrContext._registeredComponents || /* @__PURE__ */ new Set();
			const app = await (await Promise.resolve(createApp).then((r) => "default" in r ? r.default : r))(ssrContext);
			const html = await renderOptions.renderToString(app, ssrContext);
			const wrap = (fn) => () => fn(ssrContext, rendererContext);
			return {
				html,
				renderResourceHeaders: wrap(renderResourceHeaders),
				renderResourceHints: wrap(renderResourceHints),
				renderStyles: wrap(renderStyles),
				renderScripts: wrap(renderScripts)
			};
		}
	};
}
//#endregion
export { createRenderer, createRendererContext, getAllDependencies, getModuleDependencies, getPrefetchLinks, getPreloadLinks, getRequestDependencies, getResources, renderResourceHeaders, renderResourceHints, renderScripts, renderStyles };
