/**
 * Web Push Manager Module
 *
 * Handles Web Push Notification subscriptions and management.
 */

export class WebPushManager {
    constructor(options = {}) {
        this.apiBase = options.apiBase || '/api/push';
        this.serviceWorkerUrl = options.serviceWorkerUrl || '/js/sw-push.js';
        this.vapidPublicKey = options.vapidPublicKey || null;
        this.onSubscriptionChange = options.onSubscriptionChange || null;
    }

    /**
     * Initialize Web Push Manager
     */
    async init() {
        if (!('serviceWorker' in navigator)) {
            throw new Error('Service Workers are not supported in this browser');
        }

        if (!('PushManager' in window)) {
            throw new Error('Push API is not supported in this browser');
        }

        // Register Service Worker
        await this.registerServiceWorker();

        // Get VAPID public key from server if not provided
        if (!this.vapidPublicKey) {
            await this.fetchVapidPublicKey();
        }

        // Check current subscription status
        const subscription = await this.getSubscription();

        if (this.onSubscriptionChange) {
            this.onSubscriptionChange(subscription);
        }

        return subscription !== null;
    }

    /**
     * Register Service Worker
     */
    async registerServiceWorker() {
        try {
            const registration = await navigator.serviceWorker.register(this.serviceWorkerUrl);
            console.log('[WebPush] Service Worker registered', registration);
            return registration;
        } catch (error) {
            console.error('[WebPush] Service Worker registration failed', error);
            throw error;
        }
    }

    /**
     * Fetch VAPID public key from server
     */
    async fetchVapidPublicKey() {
        try {
            const response = await fetch(`${this.apiBase}/vapid-key`);
            const data = await response.json();

            if (!data.public_key) {
                throw new Error('VAPID public key not available');
            }

            this.vapidPublicKey = data.public_key;
            console.log('[WebPush] VAPID public key fetched');
        } catch (error) {
            console.error('[WebPush] Failed to fetch VAPID public key', error);
            throw error;
        }
    }

    /**
     * Request notification permission
     */
    async requestPermission() {
        const permission = await Notification.requestPermission();
        console.log('[WebPush] Permission:', permission);

        if (permission !== 'granted') {
            throw new Error('Notification permission denied');
        }

        return permission;
    }

    /**
     * Subscribe to push notifications
     */
    async subscribe() {
        try {
            // Request permission first
            await this.requestPermission();

            // Get Service Worker registration
            const registration = await navigator.serviceWorker.ready;

            // Check if already subscribed
            let subscription = await registration.pushManager.getSubscription();

            if (subscription) {
                console.log('[WebPush] Already subscribed', subscription);
            } else {
                // Subscribe
                subscription = await registration.pushManager.subscribe({
                    userVisibleOnly: true,
                    applicationServerKey: this.urlBase64ToUint8Array(this.vapidPublicKey)
                });

                console.log('[WebPush] Subscribed', subscription);
            }

            // Send subscription to server
            await this.sendSubscriptionToServer(subscription);

            if (this.onSubscriptionChange) {
                this.onSubscriptionChange(subscription);
            }

            return subscription;
        } catch (error) {
            console.error('[WebPush] Subscription failed', error);
            throw error;
        }
    }

    /**
     * Unsubscribe from push notifications
     */
    async unsubscribe() {
        try {
            const registration = await navigator.serviceWorker.ready;
            const subscription = await registration.pushManager.getSubscription();

            if (!subscription) {
                console.log('[WebPush] Not subscribed');
                return false;
            }

            // Unsubscribe from browser
            const success = await subscription.unsubscribe();

            if (success) {
                console.log('[WebPush] Unsubscribed from browser');

                // Remove from server
                await this.removeSubscriptionFromServer(subscription);

                if (this.onSubscriptionChange) {
                    this.onSubscriptionChange(null);
                }
            }

            return success;
        } catch (error) {
            console.error('[WebPush] Unsubscribe failed', error);
            throw error;
        }
    }

    /**
     * Get current subscription
     */
    async getSubscription() {
        try {
            const registration = await navigator.serviceWorker.ready;
            return await registration.pushManager.getSubscription();
        } catch (error) {
            console.error('[WebPush] Failed to get subscription', error);
            return null;
        }
    }

    /**
     * Check if subscribed
     */
    async isSubscribed() {
        const subscription = await this.getSubscription();
        return subscription !== null;
    }

    /**
     * Send test notification
     */
    async sendTestNotification(title, body) {
        try {
            const subscription = await this.getSubscription();

            if (!subscription) {
                throw new Error('Not subscribed');
            }

            const response = await fetch(`${this.apiBase}/test`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    endpoint: subscription.endpoint,
                    title: title || 'Test Notification',
                    body: body || 'This is a test notification!'
                })
            });

            const result = await response.json();
            console.log('[WebPush] Test notification sent', result);

            return result;
        } catch (error) {
            console.error('[WebPush] Test notification failed', error);
            throw error;
        }
    }

    /**
     * Send subscription to server
     */
    async sendSubscriptionToServer(subscription) {
        try {
            const subscriptionJson = subscription.toJSON();

            const response = await fetch(`${this.apiBase}/subscribe`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(subscriptionJson)
            });

            if (!response.ok) {
                throw new Error(`Server returned ${response.status}`);
            }

            const result = await response.json();
            console.log('[WebPush] Subscription sent to server', result);

            return result;
        } catch (error) {
            console.error('[WebPush] Failed to send subscription to server', error);
            throw error;
        }
    }

    /**
     * Remove subscription from server
     */
    async removeSubscriptionFromServer(subscription) {
        try {
            const response = await fetch(`${this.apiBase}/unsubscribe`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    endpoint: subscription.endpoint
                })
            });

            if (!response.ok) {
                throw new Error(`Server returned ${response.status}`);
            }

            const result = await response.json();
            console.log('[WebPush] Subscription removed from server', result);

            return result;
        } catch (error) {
            console.error('[WebPush] Failed to remove subscription from server', error);
            throw error;
        }
    }

    /**
     * Convert Base64 URL to Uint8Array (for VAPID key)
     */
    urlBase64ToUint8Array(base64String) {
        const padding = '='.repeat((4 - base64String.length % 4) % 4);
        const base64 = (base64String + padding)
            .replace(/-/g, '+')
            .replace(/_/g, '/');

        const rawData = window.atob(base64);
        const outputArray = new Uint8Array(rawData.length);

        for (let i = 0; i < rawData.length; ++i) {
            outputArray[i] = rawData.charCodeAt(i);
        }

        return outputArray;
    }

    /**
     * Get notification permission status
     */
    getPermissionStatus() {
        return Notification.permission;
    }

    /**
     * Check if browser supports Web Push
     */
    static isSupported() {
        return ('serviceWorker' in navigator) && ('PushManager' in window);
    }
}

export default WebPushManager;
