/*
 * Wikipedia Explorer - Service Worker
 * Progressive Web App Support
 * Developed by RSK World (https://rskworld.in)
 * Founder: Molla Samser
 * Designer & Tester: Rima Khatun
 * Contact: info@rskworld.com, +91 93305 39277
 * Location: Nutanhat, Mongolkote, Purba Burdwan, West Bengal, India - 713147
 * © 2026 RSK World. All rights reserved.
 * Content used for educational purposes only.
 */

const CACHE_NAME = 'wikipedia-explorer-v1.0.0';
const STATIC_CACHE_NAME = 'wikipedia-explorer-static-v1.0.0';
const DYNAMIC_CACHE_NAME = 'wikipedia-explorer-dynamic-v1.0.0';

// Static assets to cache
const STATIC_ASSETS = [
  '/',
  '/index.html',
  '/styles.css',
  '/script.js',
  '/manifest.json',
  'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css',
  'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js',
  'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css',
  'https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.css',
  'https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.js'
];

// API endpoints that should not be cached
const API_ENDPOINTS = [
  /https:\/\/en\.wikipedia\.org\/w\/api\.php/,
  /https:\/\/en\.wikipedia\.org\/api\/rest_v1\//
];

// Install event - cache static assets
self.addEventListener('install', (event) => {
  console.log('[SW] Installing service worker v1.0.0');
  
  event.waitUntil(
    caches.open(STATIC_CACHE_NAME)
      .then((cache) => {
        console.log('[SW] Caching static assets');
        return cache.addAll(STATIC_ASSETS);
      })
      .then(() => {
        console.log('[SW] Static assets cached successfully');
        return self.skipWaiting();
      })
      .catch((error) => {
        console.error('[SW] Failed to cache static assets:', error);
      })
  );
});

// Activate event - clean up old caches
self.addEventListener('activate', (event) => {
  console.log('[SW] Activating service worker v1.0.0');
  
  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames.map((cacheName) => {
          if (cacheName !== STATIC_CACHE_NAME && 
              cacheName !== DYNAMIC_CACHE_NAME && 
              cacheName !== CACHE_NAME) {
            console.log('[SW] Deleting old cache:', cacheName);
            return caches.delete(cacheName);
          }
        })
      );
    }).then(() => {
      console.log('[SW] Service worker activated');
      return self.clients.claim();
    })
  );
});

// Fetch event - serve from cache with network fallback
self.addEventListener('fetch', (event) => {
  const { request } = event;
  const url = new URL(request.url);
  
  // Skip non-GET requests
  if (request.method !== 'GET') {
    return;
  }
  
  // Skip API requests - always go to network
  if (API_ENDPOINTS.some(pattern => pattern.test(url.href))) {
    return;
  }
  
  // Handle different types of requests
  if (url.origin === self.location.origin) {
    // Same-origin requests
    event.respondWith(handleSameOriginRequest(request));
  } else {
    // Cross-origin requests (CDN, external resources)
    event.respondWith(handleCrossOriginRequest(request));
  }
});

// Handle same-origin requests
async function handleSameOriginRequest(request) {
  const url = new URL(request.url);
  
  // Try cache first for static assets
  if (STATIC_ASSETS.includes(url.pathname) || 
      url.pathname.endsWith('.css') || 
      url.pathname.endsWith('.js') || 
      url.pathname.endsWith('.json')) {
    return cacheFirst(request);
  }
  
  // Use network first for HTML pages
  if (url.pathname.endsWith('.html') || url.pathname === '/') {
    return networkFirst(request);
  }
  
  // Default to network first for other requests
  return networkFirst(request);
}

// Handle cross-origin requests (CDN resources)
async function handleCrossOriginRequest(request) {
  return cacheFirst(request);
}

// Cache-first strategy
async function cacheFirst(request) {
  try {
    const cachedResponse = await caches.match(request);
    if (cachedResponse) {
      console.log('[SW] Serving from cache:', request.url);
      return cachedResponse;
    }
    
    // Not in cache, fetch from network
    const networkResponse = await fetch(request);
    
    // Cache successful responses
    if (networkResponse.ok) {
      const cache = await caches.open(DYNAMIC_CACHE_NAME);
      cache.put(request, networkResponse.clone());
    }
    
    return networkResponse;
  } catch (error) {
    console.error('[SW] Cache-first strategy failed:', error);
    return new Response('Offline', { 
      status: 503, 
      statusText: 'Service Unavailable' 
    });
  }
}

// Network-first strategy
async function networkFirst(request) {
  try {
    const networkResponse = await fetch(request);
    
    // Cache successful responses
    if (networkResponse.ok) {
      const cache = await caches.open(DYNAMIC_CACHE_NAME);
      cache.put(request, networkResponse.clone());
    }
    
    return networkResponse;
  } catch (error) {
    console.log('[SW] Network failed, trying cache:', request.url);
    
    // Try to serve from cache
    const cachedResponse = await caches.match(request);
    if (cachedResponse) {
      return cachedResponse;
    }
    
    // Return offline page for HTML requests
    if (request.headers.get('accept').includes('text/html')) {
      return new Response(getOfflinePage(), {
        headers: { 'Content-Type': 'text/html' }
      });
    }
    
    return new Response('Offline', { 
      status: 503, 
      statusText: 'Service Unavailable' 
    });
  }
}

// Generate offline page
function getOfflinePage() {
  return `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Offline - Wikipedia Explorer</title>
      <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
      <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
      <style>
        body {
          background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
          min-height: 100vh;
          display: flex;
          align-items: center;
          justify-content: center;
          font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        .offline-container {
          background: rgba(255, 255, 255, 0.95);
          border-radius: 1rem;
          padding: 3rem;
          text-align: center;
          box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15);
          max-width: 500px;
        }
        .offline-icon {
          font-size: 4rem;
          color: #6c757d;
          margin-bottom: 1rem;
        }
        .offline-title {
          color: #212529;
          font-size: 1.5rem;
          font-weight: 700;
          margin-bottom: 1rem;
        }
        .offline-message {
          color: #6c757d;
          margin-bottom: 2rem;
        }
        .retry-btn {
          background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
          border: none;
          color: white;
          padding: 0.75rem 2rem;
          border-radius: 0.5rem;
          font-weight: 600;
          transition: transform 0.3s ease;
        }
        .retry-btn:hover {
          transform: translateY(-2px);
        }
      </style>
    </head>
    <body>
      <div class="offline-container">
        <div class="offline-icon">
          <i class="fas fa-wifi-slash"></i>
        </div>
        <h1 class="offline-title">You're Offline</h1>
        <p class="offline-message">
          It looks like you're not connected to the internet. 
          Some features may not be available until you reconnect.
        </p>
        <button class="btn retry-btn" onclick="window.location.reload()">
          <i class="fas fa-sync-alt me-2"></i>
          Try Again
        </button>
        <div class="mt-3">
          <small class="text-muted">
            <i class="fas fa-info-circle me-1"></i>
            Cached content may still be available
          </small>
        </div>
      </div>
    </body>
    </html>
  `;
}

// Background sync for offline actions
self.addEventListener('sync', (event) => {
  console.log('[SW] Background sync triggered:', event.tag);
  
  if (event.tag === 'background-sync-bookmarks') {
    event.waitUntil(syncBookmarks());
  } else if (event.tag === 'background-sync-history') {
    event.waitUntil(syncHistory());
  }
});

// Sync bookmarks when back online
async function syncBookmarks() {
  try {
    // Get pending bookmarks from IndexedDB
    const pendingBookmarks = await getPendingBookmarks();
    
    // Process each pending bookmark
    for (const bookmark of pendingBookmarks) {
      try {
        // Sync with server (implement your server sync logic here)
        console.log('[SW] Syncing bookmark:', bookmark);
        
        // Remove from pending after successful sync
        await removePendingBookmark(bookmark.id);
      } catch (error) {
        console.error('[SW] Failed to sync bookmark:', error);
      }
    }
  } catch (error) {
    console.error('[SW] Bookmark sync failed:', error);
  }
}

// Sync history when back online
async function syncHistory() {
  try {
    // Get pending history from IndexedDB
    const pendingHistory = await getPendingHistory();
    
    // Process each pending history item
    for (const historyItem of pendingHistory) {
      try {
        // Sync with server (implement your server sync logic here)
        console.log('[SW] Syncing history item:', historyItem);
        
        // Remove from pending after successful sync
        await removePendingHistoryItem(historyItem.id);
      } catch (error) {
        console.error('[SW] Failed to sync history item:', error);
      }
    }
  } catch (error) {
    console.error('[SW] History sync failed:', error);
  }
}

// IndexedDB helpers for offline storage
async function getPendingBookmarks() {
  // Implement IndexedDB logic for pending bookmarks
  return [];
}

async function removePendingBookmark(id) {
  // Implement IndexedDB logic to remove pending bookmark
  console.log('[SW] Removed pending bookmark:', id);
}

async function getPendingHistory() {
  // Implement IndexedDB logic for pending history
  return [];
}

async function removePendingHistoryItem(id) {
  // Implement IndexedDB logic to remove pending history item
  console.log('[SW] Removed pending history item:', id);
}

// Push notification handling
self.addEventListener('push', (event) => {
  console.log('[SW] Push notification received:', event);
  
  const options = {
    body: 'New Wikipedia articles matching your interests are available!',
    icon: '/manifest.json',
    badge: '/manifest.json',
    vibrate: [100, 50, 100],
    data: {
      dateOfArrival: Date.now(),
      primaryKey: 1
    },
    actions: [
      {
        action: 'explore',
        title: 'Explore Articles',
        icon: '/manifest.json'
      },
      {
        action: 'dismiss',
        title: 'Dismiss',
        icon: '/manifest.json'
      }
    ]
  };
  
  event.waitUntil(
    self.registration.showNotification('Wikipedia Explorer', options)
  );
});

// Notification click handling
self.addEventListener('notificationclick', (event) => {
  console.log('[SW] Notification click received:', event);
  
  event.notification.close();
  
  if (event.action === 'explore') {
    event.waitUntil(
      clients.openWindow('/')
    );
  } else if (event.action === 'dismiss') {
    // Just close the notification
  } else {
    // Default action - open the app
    event.waitUntil(
      clients.openWindow('/')
    );
  }
});

// Periodic background sync for content updates
self.addEventListener('periodicsync', (event) => {
  console.log('[SW] Periodic sync triggered:', event.tag);
  
  if (event.tag === 'content-update') {
    event.waitUntil(updateContent());
  }
});

// Update cached content
async function updateContent() {
  try {
    console.log('[SW] Updating cached content');
    
    // Update static assets
    const staticCache = await caches.open(STATIC_CACHE_NAME);
    await staticCache.addAll(STATIC_ASSETS);
    
    console.log('[SW] Content updated successfully');
  } catch (error) {
    console.error('[SW] Content update failed:', error);
  }
}

// Message handling from main thread
self.addEventListener('message', (event) => {
  console.log('[SW] Message received:', event.data);
  
  if (event.data && event.data.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
  
  if (event.data && event.data.type === 'CACHE_URLS') {
    event.waitUntil(
      caches.open(DYNAMIC_CACHE_NAME)
        .then((cache) => cache.addAll(event.data.urls))
    );
  }
});

// Cleanup old caches periodically
self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'CLEANUP_CACHE') {
    event.waitUntil(cleanupCache());
  }
});

async function cleanupCache() {
  try {
    const cacheNames = await caches.keys();
    const oldCaches = cacheNames.filter(name => 
      name !== STATIC_CACHE_NAME && 
      name !== DYNAMIC_CACHE_NAME && 
      name !== CACHE_NAME
    );
    
    await Promise.all(
      oldCaches.map(name => caches.delete(name))
    );
    
    console.log('[SW] Cache cleanup completed');
  } catch (error) {
    console.error('[SW] Cache cleanup failed:', error);
  }
}

console.log('[SW] Service worker loaded successfully');
