/**
 * PWA Service - Progressive Web App functionality
 * Handles service worker registration, installation prompts, and offline capabilities
 */

export interface PWAInstallPrompt {
  prompt: () => Promise<void>;
  userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;
}

export interface PWAStatus {
  isInstallable: boolean;
  isInstalled: boolean;
  isOnline: boolean;
  serviceWorkerReady: boolean;
  updateAvailable: boolean;
}

import { logger } from '@/utils/logger';

class PWAService {
  private installPrompt: PWAInstallPrompt | null = null;
  private registration: ServiceWorkerRegistration | null = null;
  private statusCallbacks: Set<(status: PWAStatus) => void> = new Set();

  constructor() {
    this.initialize();
  }

  private async initialize() {
    // Register service worker
    await this.registerServiceWorker();

    // Listen for install prompt
    this.setupInstallPrompt();

    // Listen for online/offline events
    this.setupOnlineDetection();

    // Check for updates
    this.checkForUpdates();
  }

  /**
   * Register the service worker
   * CRITICAL FIX: Service Worker disabled in production to avoid React.Children cache issues
   * The Service Worker was causing cache conflicts with JS chunks, leading to React.Children errors
   */
  private async registerServiceWorker(): Promise<void> {
    // CRITICAL FIX: Disable Service Worker completely to avoid cache issues
    // This prevents React.Children errors caused by cached old JS chunks
    logger.info('[PWA] Service Worker disabled to prevent cache conflicts with JS chunks');
    return;

    // OLD CODE - KEPT FOR REFERENCE BUT NEVER EXECUTED
    // MVP: Désactiver le service worker en développement pour éviter les problèmes de cache
    if (import.meta.env.DEV) {
      logger.info('[PWA] Service Worker disabled in development mode');
      return;
    }

    if ('serviceWorker' in navigator) {
      try {
        this.registration = await navigator.serviceWorker.register('/sw.js', {
          scope: '/',
        });

        logger.info('[PWA] Service Worker registered successfully');

        // Listen for service worker updates
        this.registration.addEventListener('updatefound', () => {
          const newWorker = this.registration!.installing;
          if (newWorker) {
            newWorker.addEventListener('statechange', () => {
              if (
                newWorker.state === 'installed' &&
                navigator.serviceWorker.controller
              ) {
                logger.info('[PWA] New service worker available');
                this.notifyStatusChange();
              }
            });
          }
        });

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

  /**
   * Setup install prompt handling
   */
  private setupInstallPrompt(): void {
    window.addEventListener('beforeinstallprompt', (event) => {
      event.preventDefault();
      this.installPrompt = event as any;
      logger.info('[PWA] Install prompt available');
      this.notifyStatusChange();
    });

    // Listen for app installed event
    window.addEventListener('appinstalled', () => {
      logger.info('[PWA] App installed successfully');
      this.installPrompt = null;
      this.notifyStatusChange();
    });
  }

  /**
   * Setup online/offline detection
   */
  private setupOnlineDetection(): void {
    window.addEventListener('online', () => {
      logger.info('[PWA] Back online');
      this.notifyStatusChange();
    });

    window.addEventListener('offline', () => {
      logger.info('[PWA] Gone offline');
      this.notifyStatusChange();
    });
  }

  /**
   * Check for service worker updates
   */
  private async checkForUpdates(): Promise<void> {
    if (this.registration) {
      try {
        await this.registration.update();
      } catch (error) {
        logger.error('[PWA] Failed to check for updates:', { error });
      }
    }
  }

  /**
   * Prompt user to install the app
   */
  public async promptInstall(): Promise<boolean> {
    if (!this.installPrompt) {
      logger.warn('[PWA] Install prompt not available');
      return false;
    }

    try {
      await this.installPrompt.prompt();
      const choice = await this.installPrompt.userChoice;

      if (choice.outcome === 'accepted') {
        logger.info('[PWA] User accepted install prompt');
        this.installPrompt = null;
        return true;
      } else {
        logger.info('[PWA] User dismissed install prompt');
        return false;
      }
    } catch (error) {
      logger.error('[PWA] Install prompt failed:', { error });
      return false;
    }
  }

  /**
   * Update the service worker
   */
  public async updateServiceWorker(): Promise<void> {
    if (this.registration && this.registration.waiting) {
      // Tell the waiting service worker to skip waiting
      this.registration.waiting.postMessage({ type: 'SKIP_WAITING' });

      // Reload the page to activate the new service worker
      window.location.reload();
    }
  }

  /**
   * Get current PWA status
   */
  public getStatus(): PWAStatus {
    return {
      isInstallable: !!this.installPrompt,
      isInstalled: this.isAppInstalled(),
      isOnline: navigator.onLine,
      serviceWorkerReady: !!this.registration,
      updateAvailable: !!this.registration?.waiting,
    };
  }

  /**
   * Check if app is installed
   */
  private isAppInstalled(): boolean {
    // Check if running in standalone mode (installed PWA)
    return (
      window.matchMedia('(display-mode: standalone)').matches ||
      (window.navigator as any).standalone ||
      document.referrer.includes('android-app://')
    );
  }

  /**
   * Subscribe to status changes
   */
  public onStatusChange(callback: (status: PWAStatus) => void): () => void {
    this.statusCallbacks.add(callback);

    // Return unsubscribe function
    return () => {
      this.statusCallbacks.delete(callback);
    };
  }

  /**
   * Notify all subscribers of status change
   */
  private notifyStatusChange(): void {
    const status = this.getStatus();
    this.statusCallbacks.forEach((callback) => {
      try {
        callback(status);
      } catch (error) {
        logger.error('[PWA] Status callback error:', { error });
      }
    });
  }

  /**
   * Clear all caches
   */
  public async clearCaches(): Promise<void> {
    if (this.registration) {
      const messageChannel = new MessageChannel();

      return new Promise((resolve) => {
        messageChannel.port1.onmessage = (event) => {
          if (event.data.type === 'CACHE_CLEARED') {
            resolve();
          }
        };

        this.registration!.active?.postMessage({ type: 'CLEAR_CACHE' }, [
          messageChannel.port2,
        ]);
      });
    }
  }

  /**
   * Get service worker version
   */
  public async getVersion(): Promise<string> {
    if (this.registration && this.registration.active) {
      const messageChannel = new MessageChannel();

      return new Promise((resolve) => {
        messageChannel.port1.onmessage = (event) => {
          if (event.data.type === 'VERSION') {
            resolve(event.data.payload.version);
          }
        };

        this.registration!.active!.postMessage({ type: 'GET_VERSION' }, [
          messageChannel.port2,
        ]);
      });
    }

    return 'unknown';
  }

  /**
   * Show notification (if permission granted)
   */
  public async showNotification(
    title: string,
    options?: NotificationOptions,
  ): Promise<void> {
    if ('Notification' in window && Notification.permission === 'granted') {
      if (this.registration) {
        await this.registration.showNotification(title, {
          icon: '/icons/icon-192x192.png',
          badge: '/icons/badge-72x72.png',
          ...options,
        });
      }
    }
  }

  /**
   * Request notification permission
   */
  public async requestNotificationPermission(): Promise<NotificationPermission> {
    if ('Notification' in window) {
      return await Notification.requestPermission();
    }
    return 'denied';
  }
}

// Export singleton instance
export const pwaService = new PWAService();

// Re-export for direct import
export { type PWAStatus as PWAStatusType };
