/**
 * PWA Helper - Service Worker Registration & PWA Features Management
 * Handles SW registration, offline detection, and PWA capabilities
 */

class PWAHelper {
  constructor() {
    this.swRegistration = null;
    this.isOnline = navigator.onLine;
    this.deferredPrompt = null;
    this.notificationPermission = 'default';
    
    this.init();
  }

  /**
   * Initialize PWA features
   */
  async init() {
    console.log('[PWA] Initializing PWA Helper...');
    
    // Register Service Worker
    await this.registerServiceWorker();
    
    // Setup event listeners
    this.setupEventListeners();
    
    // Check notification permission
    this.checkNotificationPermission();
    
    // Check online/offline status
    this.setupOnlineOfflineHandling();
    
    console.log('[PWA] PWA Helper initialized');
  }

  /**
   * Register Service Worker
   */
  async registerServiceWorker() {
    if (!('serviceWorker' in navigator)) {
      console.warn('[PWA] Service Worker not supported');
      return;
    }

    try {
      console.log('[PWA] Registering Service Worker...');
      this.swRegistration = await navigator.serviceWorker.register(
        '/invcount/assets/js/service-worker.js',
        { scope: '/invcount/' }
      );

      console.log('[PWA] Service Worker registered successfully');
      console.log('[PWA] Scope:', this.swRegistration.scope);

      // Listen for updates
      this.swRegistration.addEventListener('updatefound', () => {
        console.log('[PWA] Service Worker update found');
        this.handleSWUpdate();
      });

      // Check for updates periodically
      setInterval(() => {
        this.swRegistration.update().catch((err) => {
          console.warn('[PWA] SW update check failed:', err);
        });
      }, 60000); // Every minute

    } catch (error) {
      console.error('[PWA] Service Worker registration failed:', error);
    }
  }

  /**
   * Handle Service Worker updates
   */
  handleSWUpdate() {
    const newWorker = this.swRegistration.installing;
    newWorker.addEventListener('statechange', () => {
      if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
        // New SW is ready
        console.log('[PWA] New Service Worker available');
        this.notifyUpdate();
      }
    });
  }

  /**
   * Notify user of SW update
   */
  notifyUpdate() {
    const notification = document.createElement('div');
    notification.className = 'pwa-update-notification';
    notification.innerHTML = `
      <div class="pwa-notification-content">
        <span class="pwa-notification-text">App update available</span>
        <button class="pwa-btn-reload" onclick="location.reload()">Reload</button>
        <button class="pwa-btn-dismiss" onclick="this.parentElement.parentElement.remove()">Dismiss</button>
      </div>
    `;
    document.body.appendChild(notification);

    // Auto-hide after 10 seconds
    setTimeout(() => {
      if (notification.parentElement) {
        notification.remove();
      }
    }, 10000);
  }

  /**
   * Setup event listeners for PWA features
   */
  setupEventListeners() {
    // Install prompt
    window.addEventListener('beforeinstallprompt', (e) => {
      console.log('[PWA] Install prompt available');
      e.preventDefault();
      this.deferredPrompt = e;
      this.showInstallButton();
    });

    // App installed
    window.addEventListener('appinstalled', () => {
      console.log('[PWA] App installed');
      this.deferredPrompt = null;
      this.hideInstallButton();
      this.showNotification('App installed successfully', 'You can now use this app offline!');
    });

    // Handle SW messages
    if (navigator.serviceWorker) {
      navigator.serviceWorker.addEventListener('message', (event) => {
        this.handleSWMessage(event.data);
      });
    }
  }

  /**
   * Handle messages from Service Worker
   */
  handleSWMessage(data) {
    console.log('[PWA] Message from SW:', data);

    if (data.type === 'sync-complete') {
      this.showNotification('Sync Complete', data.data);
    } else if (data.type === 'fetch-success') {
      this.showNotification('Download Complete', data.data);
    } else if (data.type === 'fetch-failed') {
      this.showNotification('Download Failed', data.data, 'error');
    }
  }

  /**
   * Setup online/offline status handling
   */
  setupOnlineOfflineHandling() {
    window.addEventListener('online', () => {
      console.log('[PWA] App is online');
      this.isOnline = true;
      document.body.classList.remove('offline-mode');
      this.showNotification('Back Online', 'Connection restored. Syncing data...');
      this.triggerBackgroundSync();
    });

    window.addEventListener('offline', () => {
      console.log('[PWA] App is offline');
      this.isOnline = false;
      document.body.classList.add('offline-mode');
      this.showNotification('Offline Mode', 'You can still use cached features');
    });
  }

  /**
   * Prompt to install app
   */
  async promptInstall() {
    if (!this.deferredPrompt) {
      console.warn('[PWA] Install prompt not available');
      return false;
    }

    try {
      this.deferredPrompt.prompt();
      const { outcome } = await this.deferredPrompt.userChoice;
      console.log('[PWA] Install prompt outcome:', outcome);
      return outcome === 'accepted';
    } catch (error) {
      console.error('[PWA] Install prompt error:', error);
      return false;
    }
  }

  /**
   * Show install button (if available)
   */
  showInstallButton() {
    const btn = document.getElementById('pwa-install-btn');
    if (btn) {
      btn.style.display = 'inline-block';
      btn.addEventListener('click', () => this.promptInstall());
    }
  }

  /**
   * Hide install button
   */
  hideInstallButton() {
    const btn = document.getElementById('pwa-install-btn');
    if (btn) {
      btn.style.display = 'none';
    }
  }

  /**
   * Request notification permission
   */
  async requestNotificationPermission() {
    if (!('Notification' in window)) {
      console.warn('[PWA] Notifications not supported');
      return false;
    }

    try {
      const permission = await Notification.requestPermission();
      this.notificationPermission = permission;
      console.log('[PWA] Notification permission:', permission);
      return permission === 'granted';
    } catch (error) {
      console.error('[PWA] Error requesting notification permission:', error);
      return false;
    }
  }

  /**
   * Check current notification permission
   */
  checkNotificationPermission() {
    if ('Notification' in window) {
      this.notificationPermission = Notification.permission;
      console.log('[PWA] Notification permission:', this.notificationPermission);
    }
  }

  /**
   * Show notification
   */
  showNotification(title, body, type = 'info') {
    // In-app notification (always works)
    this.showInAppNotification(title, body, type);

    // Native notification (if permitted and available)
    if (this.notificationPermission === 'granted' && this.swRegistration) {
      this.swRegistration.showNotification(title, {
        body: body,
        icon: '/invcount/assets/images/icons/icon-192x192.png',
        badge: '/invcount/assets/images/icons/badge-72x72.png',
        tag: 'pwa-notification',
        requireInteraction: type === 'error',
      }).catch((err) => {
        console.error('[PWA] Error showing notification:', err);
      });
    }
  }

  /**
   * Show in-app notification
   */
  showInAppNotification(title, body, type = 'info') {
    const container = document.querySelector('.flash-container') || document.body;
    const notification = document.createElement('div');
    notification.className = `alert alert-${type} pwa-in-app-notification`;
    notification.innerHTML = `
      <strong>${title}</strong>: ${body}
      <button type="button" class="alert-close" onclick="this.parentElement.remove()">&times;</button>
    `;
    container.appendChild(notification);

    // Auto-remove after 5 seconds
    setTimeout(() => {
      if (notification.parentElement) {
        notification.remove();
      }
    }, 5000);
  }

  /**
   * Trigger background sync (if supported)
   */
  async triggerBackgroundSync() {
    if (!('serviceWorker' in navigator) || !this.swRegistration) {
      console.warn('[PWA] Background sync not available');
      return;
    }

    try {
      if ('SyncManager' in window) {
        await this.swRegistration.sync.register('sync-counts');
        await this.swRegistration.sync.register('sync-assignments');
        await this.swRegistration.sync.register('sync-reports');
        console.log('[PWA] Background sync registered');
      }
    } catch (error) {
      console.error('[PWA] Error registering background sync:', error);
    }
  }

  /**
   * Setup periodic background sync (if supported)
   */
  async setupPeriodicBackgroundSync() {
    if (!('serviceWorker' in navigator) || !this.swRegistration) {
      console.warn('[PWA] Periodic background sync not available');
      return;
    }

    try {
      if ('PeriodicSyncManager' in window) {
        // Register 12-hour periodic sync
        await this.swRegistration.periodicSync.register('periodic-sync-counts', {
          minInterval: 12 * 60 * 60 * 1000, // 12 hours
        });

        // Register 30-minute notification check
        await this.swRegistration.periodicSync.register('periodic-check-notifications', {
          minInterval: 30 * 60 * 1000, // 30 minutes
        });

        console.log('[PWA] Periodic background sync registered');
      }
    } catch (error) {
      console.error('[PWA] Error registering periodic background sync:', error);
    }
  }

  /**
   * Subscribe to push notifications
   */
  async subscribeToPushNotifications() {
    if (!('serviceWorker' in navigator) || !this.swRegistration) {
      console.error('[PWA] Push notifications not available');
      return null;
    }

    try {
      const permission = await this.requestNotificationPermission();
      if (!permission) {
        console.warn('[PWA] Notification permission denied');
        return null;
      }

      // Check if already subscribed
      let subscription = await this.swRegistration.pushManager.getSubscription();
      if (subscription) {
        console.log('[PWA] Already subscribed to push notifications');
        return subscription;
      }

      // Subscribe to push
      subscription = await this.swRegistration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: this.urlBase64ToUint8Array(
          await this.getVAPIDPublicKey()
        ),
      });

      console.log('[PWA] Subscribed to push notifications');
      
      // Send subscription to server
      await this.savePushSubscription(subscription);
      
      return subscription;
    } catch (error) {
      console.error('[PWA] Error subscribing to push notifications:', error);
      return null;
    }
  }

  /**
   * Get VAPID public key from server
   */
  async getVAPIDPublicKey() {
    try {
      const response = await fetch('/invcount/api/get-vapid-key');
      const data = await response.json();
      return data.key;
    } catch (error) {
      console.error('[PWA] Error getting VAPID key:', error);
      return null;
    }
  }

  /**
   * Convert URL-safe Base64 to Uint8Array
   */
  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;
  }

  /**
   * Save push subscription to server
   */
  async savePushSubscription(subscription) {
    try {
      const response = await fetch('/invcount/api/save-push-subscription', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          subscription: subscription.toJSON(),
        }),
      });

      if (!response.ok) {
        throw new Error('Failed to save subscription');
      }

      console.log('[PWA] Push subscription saved to server');
    } catch (error) {
      console.error('[PWA] Error saving push subscription:', error);
    }
  }

  /**
   * Enable background fetch (if supported)
   */
  async startBackgroundFetch(id, files, options = {}) {
    if (!('BackgroundFetchManager' in window) || !this.swRegistration) {
      console.warn('[PWA] Background fetch not available');
      return false;
    }

    try {
      const registration = await this.swRegistration.backgroundFetch.fetch(id, files, {
        title: options.title || 'Downloading...',
        icons: [
          {
            src: '/invcount/assets/images/icons/icon-192x192.png',
            sizes: '192x192',
          },
        ],
        downloadTotal: options.downloadTotal || 0,
        ...options,
      });

      console.log('[PWA] Background fetch started:', id);
      return registration;
    } catch (error) {
      console.error('[PWA] Error starting background fetch:', error);
      return false;
    }
  }

  /**
   * Check if app is installed
   */
  isInstalled() {
    if (window.matchMedia('(display-mode: standalone)').matches) {
      return true;
    }
    if (navigator.standalone === true) {
      return true;
    }
    return false;
  }

  /**
   * Get app installation status
   */
  getInstallationStatus() {
    return {
      isInstalled: this.isInstalled(),
      isOnline: this.isOnline,
      swReady: !!this.swRegistration,
      notificationsEnabled: this.notificationPermission === 'granted',
      canInstall: !!this.deferredPrompt,
    };
  }
}

// Initialize PWA Helper when DOM is ready
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', () => {
    window.pwaHelper = new PWAHelper();
  });
} else {
  window.pwaHelper = new PWAHelper();
}
