type Unsubscribe = () => void;

const originalPush = history.pushState.bind(history);
const originalReplace = history.replaceState.bind(history);

function navigationApi(): EventTarget | undefined {
	const candidate = (window as unknown as { navigation?: EventTarget })
		.navigation;
	return candidate;
}

export function onUrlChange(callback: () => void): Unsubscribe {
	const wrapped = () => callback();
	const navigation = navigationApi();

	if (navigation) {
		navigation.addEventListener("navigate", wrapped);
		return () => navigation.removeEventListener("navigate", wrapped);
	}

	history.pushState = (...args: Parameters<History["pushState"]>) => {
		const result = originalPush(...args);
		wrapped();
		return result;
	};
	history.replaceState = (...args: Parameters<History["replaceState"]>) => {
		const result = originalReplace(...args);
		wrapped();
		return result;
	};
	window.addEventListener("popstate", wrapped);

	return () => {
		history.pushState = originalPush;
		history.replaceState = originalReplace;
		window.removeEventListener("popstate", wrapped);
	};
}
