/**
 * Load SRI manifest and inject module preload links
 * @param {string} manifestUrl - URL to the SRI manifest JSON file
 * @returns {Promise<Object>} The loaded manifest
 */
async function loadSRIManifest(manifestUrl = './vega-sri-manifest.json') {
	try {
		const response = await fetch(manifestUrl);
		if (!response.ok) {
			throw new Error(`Failed to load manifest: ${response.statusText}`);
		}
		return await response.json();
	} catch (error) {
		console.error('Error loading SRI manifest:', error);
		throw error;
	}
}

/**
 * Inject module preload links with SRI into the document head
 * @param {Object} manifest - The SRI manifest object
 * @param {Object} options - Configuration options
 */
function injectModulePreloads(manifest, options) {
	const {
		selector = 'head',
		crossorigin = 'anonymous',
		excludeMain = true, // Exclude vega.esm.js from preload (will be loaded separately)
		vegaDistUrl,
	} = options;

	const targetElement = document.querySelector(selector);
	if (!targetElement) {
		console.error(`Target element "${selector}" not found`);
		return;
	}
	const files = Object.entries(manifest.files);
	let injected = 0;
	files.forEach(([filename, fileInfo], index) => {
		// Skip vega.esm.js if excludeMain is true (will be loaded as main script)
		if (excludeMain && filename === 'vega.esm.js') {
			return;
		}
		// Create link element
		const link = document.createElement('link');
		link.rel = 'modulepreload';
		link.href = vegaDistUrl + fileInfo.url;
		link.integrity = fileInfo.integrity;
		link.crossOrigin = crossorigin;
		// Append to target element
		targetElement.appendChild(link);
		injected++;
	});
	return injected;
}

/**
 * Load the main Vega script (vega.esm.js) with SRI
 * @param {Object} manifest - The SRI manifest object
 * @param {Object} options - Configuration options
 */
function loadMainVegaScript(manifest, options = {}) {
	const { mainScriptName, crossorigin = 'anonymous', onLoad = null, onError = null, vegaDistUrl } = options;
	return new Promise((resolve, reject) => {
		// Find the main script in manifest
		const mainScriptInfo = manifest.files[mainScriptName];
		if (!mainScriptInfo) {
			const error = new Error(`Main script "${mainScriptName}" not found in manifest`);
			console.error('❌', error.message);
			reject(error);
			return;
		}
		// Create script element
		const script = document.createElement('script');
		script.type = 'module';
		script.src = vegaDistUrl + mainScriptInfo.url;
		script.integrity = mainScriptInfo.integrity;
		script.crossOrigin = crossorigin;
		script.setAttribute('data-filename', mainScriptName);
		script.setAttribute('data-sri-verified', 'true');
		// Handle load event
		script.onload = () => {
			if (onLoad) onLoad();
			resolve();
		};
		// Handle error event
		script.onerror = error => {
			if (onError) onError(error);
			reject(new Error(`Failed to load ${mainScriptName}`));
		};
		// Append to head
		document.head.appendChild(script);
	});
}

/**
 * Initialize SRI-protected module preloading
 * @param {Object} options - Configuration options
 */
async function initializeSRIPreload(options = {}) {
	const { manifestUrl, autoInject, loadMainScript, ...injectOptions } = options;
	try {
		// Load manifest
		const manifest = await loadSRIManifest(manifestUrl);
		// Auto-inject preload links if enabled
		if (autoInject) {
			injectModulePreloads(manifest, injectOptions);
		}
		// Load main Vega script if enabled
		if (loadMainScript) {
			await loadMainVegaScript(manifest, injectOptions);
		}
		return manifest;
	} catch (error) {
		console.error('Failed to initialize SRI preload:', error);
		throw error;
	}
}

/**
 * Get base URL of Vega dist folder
 */
function getVegaDistUrl() {
	const url = new URL(import.meta.url);
	const pathname = url.pathname;
	return pathname.split('/sri/')[0];
}

function main() {
	const vegaDistUrl = getVegaDistUrl();
	initializeSRIPreload({
		manifestUrl: vegaDistUrl + '/sri/vega-sri-manifest.json',
		autoInject: true,
		loadMainScript: true,
		mainScriptName: 'vega.esm.js',
		vegaDistUrl: vegaDistUrl,
	})
		.then(() => {
			// Dispatch custom event for other scripts to know Vega is ready
			window.dispatchEvent(new CustomEvent('vega-sri-ready'));
		})
		.catch(error => {
			console.error('❌ Vega SRI initialization failed:', error);
		});
}

main();
