import { usePage } from '@inertiajs/vue3';
import { computed, onMounted, ref } from 'vue';

function urlBase64ToUint8Array(base64String: string): Uint8Array {
    const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
    const base64 = (base64String + padding)
        .replace(/-/g, '+')
        .replace(/_/g, '/');
    const rawData = atob(base64);

    return Uint8Array.from([...rawData].map((char) => char.charCodeAt(0)));
}

export function usePushNotification() {
    const isSupported = computed(
        () =>
            'Notification' in window &&
            'serviceWorker' in navigator &&
            'PushManager' in window,
    );

    const isSubscribed = ref(false);
    const isLoading = ref(false);

    const page = usePage();
    const vapidPublicKey = (page.props as Record<string, unknown>)
        .vapidPublicKey as string | undefined;

    async function checkSubscriptionStatus(): Promise<void> {
        if (!isSupported.value) {
return;
}

        try {
            const registration = await navigator.serviceWorker.ready;
            const subscription =
                await registration.pushManager.getSubscription();
            isSubscribed.value = !!subscription;
        } catch {
            isSubscribed.value = false;
        }
    }

    async function subscribe(): Promise<void> {
        if (!isSupported.value || isLoading.value) {
return;
}

        const permission = await Notification.requestPermission();

        if (permission !== 'granted') {
return;
}

        isLoading.value = true;

        try {
            const registration = await navigator.serviceWorker.ready;
            const publicKey =
                vapidPublicKey ?? import.meta.env.VITE_VAPID_PUBLIC_KEY ?? '';

            const subscription = await registration.pushManager.subscribe({
                userVisibleOnly: true,
                applicationServerKey: urlBase64ToUint8Array(publicKey),
            });

            const json = subscription.toJSON();

            await fetch('/push-subscriptions', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRF-TOKEN':
                        (
                            document.querySelector(
                                'meta[name="csrf-token"]',
                            ) as HTMLMetaElement
                        )?.content ?? '',
                },
                body: JSON.stringify({
                    endpoint: subscription.endpoint,
                    publicKey: json.keys?.p256dh ?? '',
                    authToken: json.keys?.auth ?? '',
                }),
            });

            isSubscribed.value = true;
        } catch (error) {
            console.error('[PushNotification] Subscribe failed:', error);
        } finally {
            isLoading.value = false;
        }
    }

    async function unsubscribe(): Promise<void> {
        if (!isSupported.value || isLoading.value) {
return;
}

        isLoading.value = true;

        try {
            const registration = await navigator.serviceWorker.ready;
            const subscription =
                await registration.pushManager.getSubscription();

            if (!subscription) {
                isSubscribed.value = false;

                return;
            }

            await fetch('/push-subscriptions', {
                method: 'DELETE',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRF-TOKEN':
                        (
                            document.querySelector(
                                'meta[name="csrf-token"]',
                            ) as HTMLMetaElement
                        )?.content ?? '',
                },
                body: JSON.stringify({ endpoint: subscription.endpoint }),
            });

            await subscription.unsubscribe();
            isSubscribed.value = false;
        } catch (error) {
            console.error('[PushNotification] Unsubscribe failed:', error);
        } finally {
            isLoading.value = false;
        }
    }

    async function toggle(): Promise<void> {
        if (isSubscribed.value) {
            await unsubscribe();
        } else {
            await subscribe();
        }
    }

    onMounted(() => {
        void checkSubscriptionStatus();
    });

    return {
        isSupported,
        isSubscribed,
        isLoading,
        subscribe,
        unsubscribe,
        toggle,
    };
}
