/**
 * This code is derived from the following projects:
 *
 * 1. dynamic-importmap (https://github.com/keller-mark/dynamic-importmap)
 * 2. es-module-shims (https://github.com/guybedford/es-module-shims)
 *
 * The original implementation was created by Guy Bedford in es-module-shims,
 * then adapted by Mark Keller in dynamic-importmap, and further modified
 * for use in this project.
 *
 * Both projects are licensed under the MIT license.
 *
 * MIT License: https://opensource.org/licenses/MIT
 */

/**
 * Internal dependencies
 */
import { type ModuleLoad } from './loader';

const fetching = ( url: string, parent?: string ) => {
	return ` fetching ${ url }${ parent ? ` from ${ parent }` : '' }`;
};

const jsContentType = /^(text|application)\/(x-)?javascript(;|$)/;

/**
 * Fetches the passed module URL and return the corresponding `ModuleLoad`
 * instance. If the passed URL does not point to a JS file, the function
 * throws and error.
 *
 * @param url       Module URL.
 * @param fetchOpts Fetch init options.
 * @param parent    Parent module URL referencing this URL (if any).
 * @return Promise with a `ModuleLoad` instance.
 */
export async function fetchModule(
	url: string,
	fetchOpts: RequestInit,
	parent: string
): Promise< ModuleLoad > {
	let res: Response;
	try {
		res = await fetch( url, fetchOpts );
	} catch {
		throw Error( `Network error${ fetching( url, parent ) }.` );
	}
	if ( ! res.ok ) {
		throw Error( `Error ${ res.status }${ fetching( url, parent ) }.` );
	}
	const contentType = res.headers.get( 'content-type' );
	if ( ! jsContentType.test( contentType ) ) {
		throw Error(
			`Bad Content-Type "${ contentType }"${ fetching( url, parent ) }.`
		);
	}
	return { responseUrl: res.url, source: await res.text() };
}
