/*__ESM_BODY_START__*/
((function initPrefetchiFrameMSW() {

	class MaxSizeMap extends Map {
		constructor(maxSize, entries) {
			super(entries);
			this.maxSize = maxSize;
		}

		set(key, value) {
			if (this.size >= this.maxSize && !this.has(key))
				this.delete(this.keys().next().value);

			super.set(key, value);
		}
	}

	const CACHE_KEY = 'POLARIS_SHELL';
	const CACHE_TIME_HEADER = 'CACHE-TIME';
	const TARGET_URL_REGEXP = /\/now\/nav\/ui\/classic\/params\/target\/(.+)$/;
	const MAX_CACHE_AGE = 10000; // time in ms... 10s is long enough to wait for the iframe.
	const MAX_CACHE_WAIT_TIME = 300000;
	const MAX_REQUEST_IN_FLIGHT = 6;
	const requestInFlight = new MaxSizeMap(MAX_REQUEST_IN_FLIGHT);
	const SERVICE_WORKER = self.serviceWorkerTypes.POLARIS_SW_PREFETCH_IFRAME;

	const shouldRespond = event => {
		const isNavigation = event.request.mode === 'navigate';
		const targetsClassicUi = TARGET_URL_REGEXP.test(event.request.url) || TARGET_URL_REGEXP.test(event.request.referrer);
		return isNavigation && targetsClassicUi;
	};

	const fetchEventHandler = (event) => {
		if (shouldRespond(event)) {
			const startTime = self.mark({event, serviceWorker: SERVICE_WORKER, type: self.markTypes.INIT});
			event.respondWith(respondTo(event, startTime));
		}

		return;
	};

	const sleep = (timeout) => {
		return new Promise((resolve) => {
			setTimeout(resolve, timeout);
		});
	};

	const getCacheKey = (url) => {
		const match = url.match(TARGET_URL_REGEXP);
		if (match?.[1])
			return '/' + decodeURIComponent(match?.[1]);

		const urlObj = new URL(url);
		return urlObj.pathname + urlObj.search;
	};

	const buildResponseWithCacheTimestamp = async (response) => {
		const headers = new Headers(response.headers);
		headers.set(CACHE_TIME_HEADER, Date.now());
		const options = {
			headers,
			status: response.status,
			statusText: response.statusText
		};
		return new Response(await response.blob(), options);
	};

	const respondTo = async (event, eventStartTime) => {
		const cache = await caches.open(CACHE_KEY);
		let cached = await cache.match(event.request);
		const match = event.request.url.match(TARGET_URL_REGEXP);
		const cacheKey = getCacheKey(event.request.url);

		const startTime = Date.now();

		while (Boolean(requestInFlight.get(cacheKey)) && !cached) {
			if (Date.now() - startTime >= MAX_CACHE_WAIT_TIME) {
				break; // Stop waiting if the maximum cache wait time has elapsed
			}

			await sleep(100);
			cached = await cache.match(event.request);
		}

		if (cached) {
			await cache.delete(event.request); // Always delete the cached response so we never return stale data
			self.mark({event, serviceWorker: SERVICE_WORKER, type: self.markTypes.DELETE_CACHE_KEY});
			const cacheTime = cached.headers.get(CACHE_TIME_HEADER);
			const now = Date.now();
			const cacheAge = (now - cacheTime);

			// Only return the cached response if it's younger than MAX_CACHE_AGE
			if (!isNaN(cacheAge) && now > cacheTime && cacheAge < MAX_CACHE_AGE) {
				self.mark({event, response: cached, serviceWorker: SERVICE_WORKER, type: self.markTypes.CACHE, startTime: eventStartTime});
				return cached;
			}
		}

		self.mark({event, serviceWorker: SERVICE_WORKER, type: self.markTypes.FETCH, startTime: eventStartTime});
		const response = await fetch(event.request);
		setTimeout(() => {
			if (match && response.ok) {
				const prefetchUrl = decodeURIComponent(match[1]);
				const prefetchRequest = new Request(new URL(prefetchUrl, location.origin));
				// Prefetch only when url is not the same as the referrer (to exclude session expired redirection case where url and referrer are same)
				// We do not want to send a prefetch request and overwrite the starting_page, thus keeping the platform redirection url intact post login
				if (event.request.url !== event.request.referrer) {
					requestInFlight.set(cacheKey, true);
					fetch(prefetchRequest)
						.then(async (prefetchResponse) => {
							if (!prefetchResponse.redirected) {
								await cache.put(prefetchRequest, await buildResponseWithCacheTimestamp(prefetchResponse));
								self.mark({event, serviceWorker: SERVICE_WORKER, type: self.markTypes.PUT_CACHE_KEY, startTime: eventStartTime});
								requestInFlight.set(cacheKey, false);
							} else {
								requestInFlight.set(cacheKey, false);
							}
						})
						.catch(error => {
							self.mark({event, error, serviceWorker: SERVICE_WORKER, type: self.markTypes.EXCEPTION, startTime: eventStartTime});
							console.error(error);
							requestInFlight.set(cacheKey, false);
						});
				}
			}
		}, 0);
		return response;
	};

	self.handleFallbackResponse && self.handleFallbackResponse(shouldRespond);

	self.addEventListener('fetch', fetchEventHandler);
})());

/*__ESM_BODY_END__*/