// Biblical Guide Service Worker
const CACHE_NAME = 'biblical-guide-v1.0.1';
const STATIC_CACHE = 'biblical-guide-static-v1.0.1';
const DYNAMIC_CACHE = 'biblical-guide-dynamic-v1.0.1';
const BIBLE_CACHE = 'biblical-guide-bible-v1.0.1';

// Static resources that should be cached immediately
const STATIC_ASSETS = [
  '/',
  '/manifest.json',
  '/icon-192.png',
  '/icon-512.png',
  '/biblical-guide-og-image.png',
  '/offline.html', // We'll create this fallback page
];

// Bible API endpoints that should be cached
const BIBLE_API_PATTERNS = [
  /\/api\/bible\/versions/,
  /\/api\/bible\/books/,
  /\/api\/bible\/chapter/,
  /\/api\/bible\/verses/,
];

// Dynamic content that should be cached with network-first strategy
const DYNAMIC_PATTERNS = [
  /\/api\/daily-verse/,
  /\/api\/search/,
];

// Install event - cache static assets
self.addEventListener('install', (event) => {
  console.log('[SW] Installing service worker...');

  event.waitUntil(
    Promise.all([
      caches.open(STATIC_CACHE).then((cache) => {
        console.log('[SW] Caching static assets');
        return cache.addAll(STATIC_ASSETS.map(url => new Request(url, {credentials: 'same-origin'})));
      }),
      caches.open(BIBLE_CACHE).then(() => {
        console.log('[SW] Bible cache initialized');
      })
    ]).then(() => {
      console.log('[SW] Installation complete');
      // Skip waiting to activate immediately
      return self.skipWaiting();
    })
  );
});

// Activate event - clean up old caches
self.addEventListener('activate', (event) => {
  console.log('[SW] Activating service worker...');

  event.waitUntil(
    Promise.all([
      // Clean up old caches
      caches.keys().then((cacheNames) => {
        return Promise.all(
          cacheNames.map((cacheName) => {
            if (cacheName !== STATIC_CACHE &&
                cacheName !== DYNAMIC_CACHE &&
                cacheName !== BIBLE_CACHE &&
                cacheName !== CACHE_NAME) {
              console.log('[SW] Deleting old cache:', cacheName);
              return caches.delete(cacheName);
            }
          })
        );
      }),
      // Take control of all pages immediately
      self.clients.claim()
    ]).then(() => {
      console.log('[SW] Activation complete');
    })
  );
});

// Fetch event - handle all network requests
self.addEventListener('fetch', (event) => {
  const { request } = event;
  const { url, method } = request;

  // Only handle GET requests
  if (method !== 'GET') {
    return;
  }

  // Handle Bible content downloads (store in Bible cache)
  if (BIBLE_API_PATTERNS.some(pattern => pattern.test(url))) {
    event.respondWith(handleBibleRequest(request));
    return;
  }

  // Handle dynamic content (network-first with cache fallback)
  if (DYNAMIC_PATTERNS.some(pattern => pattern.test(url))) {
    event.respondWith(handleDynamicRequest(request));
    return;
  }

  // Handle static assets (cache-first)
  if (isStaticAsset(url)) {
    event.respondWith(handleStaticRequest(request));
    return;
  }

  // Handle navigation requests (HTML pages)
  if (request.mode === 'navigate') {
    event.respondWith(handleNavigationRequest(request));
    return;
  }

  // Default: network-first for everything else
  event.respondWith(handleDefaultRequest(request));
});

// Bible content strategy: Cache-first with network update
async function handleBibleRequest(request) {
  const cache = await caches.open(BIBLE_CACHE);
  const cached = await cache.match(request);

  if (cached) {
    console.log('[SW] Serving Bible content from cache:', request.url);
    // Update cache in background
    updateBibleCache(request, cache);
    return cached;
  }

  try {
    console.log('[SW] Fetching Bible content from network:', request.url);
    const response = await fetch(request);
    if (response.ok) {
      // Clone before caching
      const responseClone = response.clone();
      await cache.put(request, responseClone);
      console.log('[SW] Bible content cached:', request.url);
    }
    return response;
  } catch (error) {
    console.error('[SW] Bible content fetch failed:', error);
    throw error;
  }
}

// Update Bible cache in background
async function updateBibleCache(request, cache) {
  try {
    const response = await fetch(request);
    if (response.ok) {
      await cache.put(request, response.clone());
      console.log('[SW] Bible cache updated:', request.url);
    }
  } catch (error) {
    console.log('[SW] Background Bible cache update failed:', error);
  }
}

// Dynamic content strategy: Network-first with cache fallback
async function handleDynamicRequest(request) {
  const cache = await caches.open(DYNAMIC_CACHE);

  try {
    console.log('[SW] Fetching dynamic content from network:', request.url);
    const response = await fetch(request);
    if (response.ok) {
      // Cache successful responses
      await cache.put(request, response.clone());
      console.log('[SW] Dynamic content cached:', request.url);
    }
    return response;
  } catch (error) {
    console.log('[SW] Network failed, checking cache for:', request.url);
    const cached = await cache.match(request);
    if (cached) {
      console.log('[SW] Serving dynamic content from cache:', request.url);
      return cached;
    }
    throw error;
  }
}

// Static assets strategy: Cache-first
async function handleStaticRequest(request) {
  const cache = await caches.open(STATIC_CACHE);
  const cached = await cache.match(request);

  if (cached) {
    console.log('[SW] Serving static asset from cache:', request.url);
    return cached;
  }

  try {
    console.log('[SW] Fetching static asset from network:', request.url);
    const response = await fetch(request);
    if (response.ok) {
      await cache.put(request, response.clone());
      console.log('[SW] Static asset cached:', request.url);
    }
    return response;
  } catch (error) {
    console.error('[SW] Static asset fetch failed:', error);
    throw error;
  }
}

// Navigation strategy: Network-first with offline fallback
async function handleNavigationRequest(request) {
  try {
    console.log('[SW] Fetching navigation from network:', request.url);
    const response = await fetch(request);
    if (response.ok) {
      // Cache successful navigation responses
      const cache = await caches.open(DYNAMIC_CACHE);
      await cache.put(request, response.clone());
    }
    return response;
  } catch (error) {
    console.log('[SW] Navigation network failed, checking cache:', request.url);
    const cache = await caches.open(DYNAMIC_CACHE);
    const cached = await cache.match(request);

    if (cached) {
      console.log('[SW] Serving navigation from cache:', request.url);
      return cached;
    }

    // Return offline fallback page
    console.log('[SW] Serving offline fallback page');
    const offlineCache = await caches.open(STATIC_CACHE);
    const offlinePage = await offlineCache.match('/offline.html');
    return offlinePage || new Response('Offline - Please check your connection', {
      status: 503,
      statusText: 'Service Unavailable',
      headers: { 'Content-Type': 'text/plain' }
    });
  }
}

// Default strategy: Network-first
async function handleDefaultRequest(request) {
  try {
    return await fetch(request);
  } catch (error) {
    console.log('[SW] Default request failed:', request.url);
    throw error;
  }
}

// Helper function to check if URL is a static asset
function isStaticAsset(url) {
  return url.includes('/_next/') ||
         url.includes('/icon-') ||
         url.includes('/manifest.json') ||
         url.includes('/biblical-guide-og-image.png') ||
         url.includes('.css') ||
         url.includes('.js') ||
         url.includes('.woff') ||
         url.includes('.woff2');
}

// Background sync for Bible downloads
self.addEventListener('sync', (event) => {
  console.log('[SW] Background sync triggered:', event.tag);

  if (event.tag === 'download-bible-version') {
    event.waitUntil(handleBibleDownloadSync());
  }
});

// Handle Bible version download in background
async function handleBibleDownloadSync() {
  try {
    console.log('[SW] Processing background Bible download');
    // Get pending downloads from IndexedDB
    const pendingDownloads = await getPendingBibleDownloads();

    for (const download of pendingDownloads) {
      await downloadBibleVersion(download);
    }
  } catch (error) {
    console.error('[SW] Background Bible download failed:', error);
  }
}

// Get pending downloads from IndexedDB
async function getPendingBibleDownloads() {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open('BibleStorage', 1);

    request.onsuccess = () => {
      const db = request.result;
      const transaction = db.transaction(['downloads'], 'readonly');
      const store = transaction.objectStore('downloads');
      const getAllRequest = store.getAll();

      getAllRequest.onsuccess = () => {
        resolve(getAllRequest.result.filter(d => d.status === 'pending'));
      };

      getAllRequest.onerror = () => reject(getAllRequest.error);
    };

    request.onerror = () => reject(request.error);
  });
}

// Download a Bible version
async function downloadBibleVersion(download) {
  try {
    console.log('[SW] Downloading Bible version:', download.versionId);

    // Download books list
    const booksResponse = await fetch(`/api/bible/books?version=${download.versionId}`);
    if (!booksResponse.ok) throw new Error('Failed to fetch books');

    const books = await booksResponse.json();

    // Download each chapter
    for (const book of books.books) {
      for (let chapter = 1; chapter <= book.chaptersCount; chapter++) {
        const chapterUrl = `/api/bible/chapter?book=${book.id}&chapter=${chapter}&version=${download.versionId}`;
        await fetch(chapterUrl); // This will be cached by the fetch handler
      }
    }

    // Mark download as complete
    await updateDownloadStatus(download.versionId, 'completed');

    console.log('[SW] Bible version download completed:', download.versionId);
  } catch (error) {
    console.error('[SW] Bible version download failed:', error);
    await updateDownloadStatus(download.versionId, 'failed');
  }
}

// Update download status in IndexedDB
async function updateDownloadStatus(versionId, status) {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open('BibleStorage', 1);

    request.onsuccess = () => {
      const db = request.result;
      const transaction = db.transaction(['downloads'], 'readwrite');
      const store = transaction.objectStore('downloads');

      const getRequest = store.get(versionId);
      getRequest.onsuccess = () => {
        const download = getRequest.result;
        if (download) {
          download.status = status;
          download.updatedAt = new Date().toISOString();
          const putRequest = store.put(download);
          putRequest.onsuccess = () => resolve();
          putRequest.onerror = () => reject(putRequest.error);
        } else {
          resolve(); // Download not found, ignore
        }
      };

      getRequest.onerror = () => reject(getRequest.error);
    };

    request.onerror = () => reject(request.error);
  });
}

// Message handling for communication with the 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 === 'CLEAR_CACHE') {
    clearAllCaches().then(() => {
      event.ports[0].postMessage({success: true});
    });
  }

  if (event.data && event.data.type === 'CACHE_BIBLE_VERSION') {
    const { versionId } = event.data;
    cacheBibleVersion(versionId).then(() => {
      event.ports[0].postMessage({success: true, versionId});
    }).catch((error) => {
      event.ports[0].postMessage({success: false, error: error.message, versionId});
    });
  }
});

// Clear all caches
async function clearAllCaches() {
  const cacheNames = await caches.keys();
  await Promise.all(cacheNames.map(name => caches.delete(name)));
  console.log('[SW] All caches cleared');
}

// Cache a specific Bible version
async function cacheBibleVersion(versionId) {
  console.log('[SW] Caching Bible version:', versionId);

  try {
    // Download and cache all content for this version
    const booksResponse = await fetch(`/api/bible/books?version=${versionId}`);
    if (!booksResponse.ok) throw new Error('Failed to fetch books');

    const books = await booksResponse.json();
    const cache = await caches.open(BIBLE_CACHE);

    // Cache books list
    await cache.put(`/api/bible/books?version=${versionId}`, booksResponse.clone());

    // Cache each chapter
    for (const book of books.books) {
      for (let chapter = 1; chapter <= book.chaptersCount; chapter++) {
        const chapterUrl = `/api/bible/chapter?book=${book.id}&chapter=${chapter}&version=${versionId}`;
        const chapterResponse = await fetch(chapterUrl);
        if (chapterResponse.ok) {
          await cache.put(chapterUrl, chapterResponse.clone());
        }
      }
    }

    console.log('[SW] Bible version cached successfully:', versionId);
  } catch (error) {
    console.error('[SW] Failed to cache Bible version:', error);
    throw error;
  }
}

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