<template>
	<section>
		Notifications are: <b>{{ subscription ? "Enabled" : "Disabled" }}</b>
		<br />
		<button
			:disabled="unsupported"
			@click="onClick"
		>
			{{ unsupported === undefined ? "Checking for support" : null }}
			{{ unsupported === true ? "Notifications are not supported :(." : null }}
			{{ unsupported === false ? (subscription ? "Disable notifications" : "Enable notifications") : null }}
		</button>
		<details>
			<summary>Debug</summary>
			<pre><code>{{ JSON.stringify(subscription?.toJSON(), undefined, 4) ?? "No subscription set" }}</code></pre>
		</details>
	</section>
</template>

<script setup lang="ts">
function notificationUnsupported() {
	return (
		!("serviceWorker" in navigator)
		|| !("PushManager" in window)
		|| !("showNotification" in ServiceWorkerRegistration.prototype)
	)
}

async function registerAndSubscribe(
	vapidPublicKey: string,
	onSubscribe: (subs: PushSubscription | null ) => void,
) {
	try {
		await navigator.serviceWorker.register("/sw.js");
		await subscribe(vapidPublicKey, onSubscribe);
	} catch (err) {
		console.error("Failed to register service worker:", err);
	}
}

async function subscribe(
	vapidPublicKey: string,
	onSubscribe: (subs: PushSubscription | null) => void
) {
	try {
		const registration = await navigator.serviceWorker.ready;
		const subscription = await registration.pushManager.subscribe({
			userVisibleOnly: true,
			applicationServerKey: vapidPublicKey,
		});
		console.log("Got subscription object", subscription.toJSON());
		await submitSubscription(subscription);
		onSubscribe(subscription);
	} catch (err) {
		console.error("Failed to subscribe:" , err);
	}
}

async function unsubscribe(
	subscription: PushSubscription,
	onUnsubscribed: () => void,
) {
	const body = JSON.stringify({ subscription });
	await subscription.unsubscribe();
	const res = await fetch("/api/unsubscribe", {
		method: "POST",
		headers: {
			"Content-Type": "application/json",
		},
		body,
	});
	const result = await res.json();
	console.log("/api/unsubscribe returned", result);
	onUnsubscribed();
}

async function submitSubscription(subscription: PushSubscription) {
	const res = await fetch("/api/subscribe", {
		method: "POST",
		headers: {
			"Content-Type": "application/json",
		},
		body: JSON.stringify({ subscription }),
	});
	const result = await res.json();
	console.log("/api/subscribe returned", result);
}

async function getSubscription(
	onSubscribe: (subs: PushSubscription | null) => void,
) {
	const registration = await navigator.serviceWorker.ready;
	const subscription = await registration.pushManager.getSubscription();
	if (subscription) {
		onSubscribe(subscription);
	}
}

const unsupported = ref<boolean | undefined>(undefined);
const subscription = ref<PushSubscription | null>(null);
const runtimeConfig = useRuntimeConfig();
const { refresh: refreshSession } = useAccountSession();

async function onClick() {
	if (!subscription.value)
		await registerAndSubscribe(runtimeConfig.public.vapidPublicKey, (subs) => { subscription.value = subs })
	else
		await unsubscribe(subscription.value, () => { subscription.value = null })
	refreshSession();
}

onMounted(() => {
	unsupported.value = notificationUnsupported()
	if (unsupported.value) {
		return;
	}
	getSubscription(subs => { subscription.value = subs });
})
</script>
