// Service Worker for POS Application (Online-First PWA with Advanced Caching)
const CACHE_VERSION = 'v5';
const STATIC_CACHE = `pos-static-${CACHE_VERSION}`;
const IMAGE_CACHE = `pos-images-${CACHE_VERSION}`;
const RUNTIME_CACHE = `pos-runtime-${CACHE_VERSION}`;
const FAILED_REQUESTS_QUEUE = 'pos-failed-requests';

// Static assets to cache on install (critical path)
const STATIC_ASSETS = [
  '/',
  '/index.html',
  '/manifest.json',
  '/zagel-logo.png',
  '/icons/icon-192.png',
  '/icons/icon-512.png',
  '/icons/icon-maskable.png'
];

// Performance monitoring thresholds
const SLOW_REQUEST_THRESHOLD = 5000; // 5 seconds

// Install event - cache static assets
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(STATIC_CACHE).then((cache) => {
      console.log('[SW] Caching static assets');
      return cache.addAll(STATIC_ASSETS);
    })
  );
  self.skipWaiting();
});

// Activate event - cleanup old caches
self.addEventListener('activate', (event) => {
  const validCaches = [STATIC_CACHE, IMAGE_CACHE, RUNTIME_CACHE, FAILED_REQUESTS_QUEUE];
  
  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames
          .filter((name) => name.startsWith('pos-') && !validCaches.includes(name))
          .map((name) => {
            console.log('[SW] Deleting old cache:', name);
            return caches.delete(name);
          })
      );
    })
  );
  self.clients.claim();
});

// Fetch event - Advanced caching strategies
self.addEventListener('fetch', (event) => {
  const { request } = event;
  const url = new URL(request.url);

  // Skip non-GET requests (except for background sync)
  if (request.method !== 'GET') {
    // Queue failed POST requests for retry
    if (request.method === 'POST' && url.pathname.includes('/api/')) {
      event.respondWith(handlePostWithRetry(request));
    }
    return;
  }

  // API calls: Products get special caching, other APIs are network-only
  if (url.pathname.includes('/api/')) {
    // ✅ تسريع: تخزين مؤقت للمنتجات
    if (url.href.includes('table=products') && url.href.includes('action=get_all')) {
      event.respondWith(networkFirstWithProductCache(request));
      return;
    }
    event.respondWith(networkOnlyWithMonitoring(request));
    return;
  }

  // JS/CSS chunks: Stale-While-Revalidate for fast loading
  if (url.pathname.match(/\.(js|css)$/) && url.origin === self.location.origin) {
    event.respondWith(staleWhileRevalidate(request, RUNTIME_CACHE));
    return;
  }

  // Images: Cache First with Network Fallback
  if (request.destination === 'image' || url.pathname.match(/\.(png|jpg|jpeg|gif|webp|svg|ico)$/)) {
    event.respondWith(cacheFirstWithNetwork(request, IMAGE_CACHE));
    return;
  }

  // Fonts: Cache First (rarely change)
  if (request.destination === 'font' || url.pathname.match(/\.(woff|woff2|ttf|otf)$/)) {
    event.respondWith(cacheFirstWithNetwork(request, STATIC_CACHE));
    return;
  }

  // Default: Network First for HTML navigation
  event.respondWith(networkFirstWithCache(request, STATIC_CACHE));
});

// Network Only with Performance Monitoring
async function networkOnlyWithMonitoring(request) {
  const startTime = Date.now();
  
  try {
    const response = await fetch(request);
    const duration = Date.now() - startTime;
    
    // Log slow requests
    if (duration > SLOW_REQUEST_THRESHOLD) {
      console.warn(`[SW] Slow API request (${duration}ms):`, request.url);
    }
    
    return response;
  } catch (error) {
    console.log('[SW] Network request failed:', request.url);
    return new Response(JSON.stringify({ 
      success: false, 
      error: 'لا يوجد اتصال بالإنترنت',
      offline: true 
    }), {
      status: 503,
      headers: { 'Content-Type': 'application/json' }
    });
  }
}

// Stale-While-Revalidate strategy (for JS/CSS chunks)
async function staleWhileRevalidate(request, cacheName) {
  const cachedResponse = await caches.match(request);
  
  // Fetch in background regardless
  const fetchPromise = fetch(request).then(async (response) => {
    if (response.ok) {
      const cache = await caches.open(cacheName);
      cache.put(request, response.clone());
    }
    return response;
  }).catch(() => cachedResponse);
  
  // Return cached immediately if available, otherwise wait for network
  return cachedResponse || fetchPromise;
}

// Network First with Cache Fallback (for HTML pages)
async function networkFirstWithCache(request, cacheName) {
  try {
    const networkResponse = await fetch(request);
    
    if (networkResponse.ok) {
      const cache = await caches.open(cacheName);
      cache.put(request, networkResponse.clone());
    }
    
    return networkResponse;
  } catch (error) {
    console.log('[SW] Network failed, trying cache:', request.url);
    const cachedResponse = await caches.match(request);
    
    if (cachedResponse) {
      return cachedResponse;
    }
    
    // Return offline fallback for navigation requests
    if (request.mode === 'navigate') {
      return caches.match('/index.html');
    }
    
    throw error;
  }
}

// ✅ تسريع: Network First with Product Cache (5 minutes)
const PRODUCT_CACHE = 'pos-products-v1';
const PRODUCT_CACHE_DURATION = 5 * 60 * 1000; // 5 minutes

async function networkFirstWithProductCache(request) {
  try {
    const networkResponse = await fetch(request);
    
    if (networkResponse.ok) {
      // Clone and add cache timestamp
      const responseData = await networkResponse.clone().json();
      const cachedResponse = new Response(JSON.stringify(responseData), {
        status: 200,
        headers: {
          'Content-Type': 'application/json',
          'sw-cache-time': String(Date.now())
        }
      });
      
      const cache = await caches.open(PRODUCT_CACHE);
      cache.put(request.url, cachedResponse);
      console.log('[SW] Products cached');
    }
    
    return networkResponse;
  } catch (error) {
    console.log('[SW] Network failed for products, checking cache');
    
    const cache = await caches.open(PRODUCT_CACHE);
    const cachedResponse = await cache.match(request.url);
    
    if (cachedResponse) {
      const cacheTime = cachedResponse.headers.get('sw-cache-time');
      if (cacheTime && Date.now() - parseInt(cacheTime) < PRODUCT_CACHE_DURATION) {
        console.log('[SW] Returning cached products');
        return cachedResponse;
      }
    }
    
    // Return offline error
    return new Response(JSON.stringify({ 
      success: false, 
      error: 'لا يوجد اتصال بالإنترنت',
      offline: true 
    }), {
      status: 503,
      headers: { 'Content-Type': 'application/json' }
    });
  }
}

// Cache First with Network Fallback (for images and assets)
async function cacheFirstWithNetwork(request, cacheName) {
  const cachedResponse = await caches.match(request);
  
  if (cachedResponse) {
    // Update cache in background (non-blocking)
    fetch(request).then((response) => {
      if (response.ok) {
        caches.open(cacheName).then((cache) => {
          cache.put(request, response);
        });
      }
    }).catch(() => {});
    
    return cachedResponse;
  }
  
  try {
    const networkResponse = await fetch(request);
    
    if (networkResponse.ok) {
      const cache = await caches.open(cacheName);
      cache.put(request, networkResponse.clone());
    }
    
    return networkResponse;
  } catch (error) {
    console.log('[SW] Both cache and network failed:', request.url);
    throw error;
  }
}

// Handle POST requests with retry capability
async function handlePostWithRetry(request) {
  try {
    const response = await fetch(request.clone());
    return response;
  } catch (error) {
    // Queue for background sync
    await queueFailedRequest(request);
    
    return new Response(JSON.stringify({
      success: false,
      error: 'تم حفظ الطلب للإرسال لاحقاً',
      queued: true
    }), {
      status: 202,
      headers: { 'Content-Type': 'application/json' }
    });
  }
}

// Queue failed request for later retry
async function queueFailedRequest(request) {
  try {
    const body = await request.clone().text();
    const serialized = {
      url: request.url,
      method: request.method,
      headers: Object.fromEntries(request.headers.entries()),
      body: body,
      timestamp: Date.now()
    };
    
    const cache = await caches.open(FAILED_REQUESTS_QUEUE);
    const key = `/queued/${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    await cache.put(new Request(key), new Response(JSON.stringify(serialized)));
    
    console.log('[SW] Request queued for retry:', request.url);
  } catch (error) {
    console.error('[SW] Failed to queue request:', error);
  }
}

// Background Sync - Retry failed requests
self.addEventListener('sync', (event) => {
  if (event.tag === 'retry-failed-requests') {
    event.waitUntil(retryQueuedRequests());
  }
});

// Retry all queued requests
async function retryQueuedRequests() {
  try {
    const cache = await caches.open(FAILED_REQUESTS_QUEUE);
    const keys = await cache.keys();
    
    console.log(`[SW] Retrying ${keys.length} queued requests`);
    
    for (const key of keys) {
      try {
        const response = await cache.match(key);
        if (!response) continue;
        
        const serialized = await response.json();
        
        // Rebuild the request
        const retryRequest = new Request(serialized.url, {
          method: serialized.method,
          headers: serialized.headers,
          body: serialized.body
        });
        
        const retryResponse = await fetch(retryRequest);
        
        if (retryResponse.ok) {
          await cache.delete(key);
          console.log('[SW] Successfully retried:', serialized.url);
          
          // Notify main thread
          const clients = await self.clients.matchAll();
          clients.forEach(client => {
            client.postMessage({
              type: 'sync-success',
              url: serialized.url
            });
          });
        }
      } catch (error) {
        console.log('[SW] Retry failed, will try again later');
      }
    }
  } catch (error) {
    console.error('[SW] Error retrying queued requests:', error);
  }
}

// Push notifications
self.addEventListener('push', (event) => {
  if (event.data) {
    const data = event.data.json();
    event.waitUntil(
      self.registration.showNotification(data.title, {
        body: data.body,
        icon: '/zagel-logo.png',
        badge: '/zagel-logo.png',
        dir: 'rtl',
        lang: 'ar',
        requireInteraction: data.requireInteraction || false,
        tag: data.tag || 'default',
        actions: data.actions || []
      })
    );
  }
});

// Notification click handler
self.addEventListener('notificationclick', (event) => {
  event.notification.close();
  
  const action = event.action;
  let targetUrl = '/';
  
  if (action === 'pos') {
    targetUrl = '/pos';
  } else if (action === 'invoices') {
    targetUrl = '/';
  }
  
  event.waitUntil(
    self.clients.matchAll({ type: 'window' }).then((clients) => {
      // Focus existing window if available
      for (const client of clients) {
        if (client.url.includes(self.location.origin) && 'focus' in client) {
          client.navigate(targetUrl);
          return client.focus();
        }
      }
      // Open new window
      return self.clients.openWindow(targetUrl);
    })
  );
});

// Message handler
self.addEventListener('message', (event) => {
  const { data } = event;
  
  if (data === 'skipWaiting') {
    self.skipWaiting();
  }
  
  if (data === 'clearCache') {
    caches.keys().then((names) => {
      names.forEach((name) => caches.delete(name));
    });
  }
  
  // Handle precache routes request
  if (data?.type === 'precache-routes') {
    precacheRoutes(data.routes);
  }
  
  // Handle notification requests from main app
  if (data?.type === 'showNotification') {
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: '/zagel-logo.png',
      badge: '/zagel-logo.png',
      dir: 'rtl',
      lang: 'ar',
      tag: data.tag || 'notification',
      requireInteraction: data.requireInteraction || false
    });
  }
  
  // Check for update
  if (data === 'checkForUpdate') {
    self.registration.update();
  }
});

// Precache specific routes
async function precacheRoutes(routes) {
  const cache = await caches.open(RUNTIME_CACHE);
  
  for (const route of routes) {
    try {
      const response = await fetch(route);
      if (response.ok) {
        await cache.put(route, response);
        console.log('[SW] Precached route:', route);
      }
    } catch (error) {
      console.log('[SW] Failed to precache:', route);
    }
  }
}