/**
 * Service Worker for Birthday Reminder PWA
 * Handles caching and offline functionality
 */

const CACHE_NAME = "birthday-reminder-v1.0.1";
const RUNTIME_CACHE = "birthday-reminder-runtime";
const URL_PATH = "https://bd.teamhr.co.in";

// Assets to cache on install
const STATIC_ASSETS = [
  URL_PATH + "/home",
  URL_PATH + "/public/js/pwa.js",
  URL_PATH + "/public/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://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css",
];

// Install event - cache static assets
self.addEventListener("install", (event) => {
  console.log("[Service Worker] Installing...");

  // Skip waiting immediately - don't block on caching
  self.skipWaiting();

  // Cache assets in background (non-blocking)
  event.waitUntil(
    caches
      .open(CACHE_NAME)
      .then((cache) => {
        console.log("[Service Worker] Caching static assets in background");
        // Cache each asset individually, ignore failures
        return Promise.allSettled(
          STATIC_ASSETS.map((url) =>
            cache.add(url).catch((err) => {
              console.warn("[Service Worker] Failed to cache:", url, err);
            })
          )
        );
      })
      .then(() => {
        console.log("[Service Worker] Background caching complete");
      })
      .catch((error) => {
        console.error("[Service Worker] Caching error:", error);
      })
  );
});

// Activate event - clean up old caches
self.addEventListener("activate", (event) => {
  console.log("[Service Worker] Activating...");

  event.waitUntil(
    caches
      .keys()
      .then((cacheNames) => {
        return Promise.all(
          cacheNames
            .filter((cacheName) => {
              return cacheName !== CACHE_NAME && cacheName !== RUNTIME_CACHE;
            })
            .map((cacheName) => {
              console.log("[Service Worker] Deleting old cache:", cacheName);
              return caches.delete(cacheName);
            })
        );
      })
      .then(() => {
        console.log("[Service Worker] Activated successfully");
        return self.clients.claim();
      })
  );
});

// Fetch event - serve from cache, fallback to network
self.addEventListener("fetch", (event) => {
  const { request } = event;
  const url = new URL(request.url);

  // Skip cross-origin requests
  if (url.origin !== location.origin) {
    // For CDN resources, use cache-first strategy
    if (
      url.hostname.includes("cdn.jsdelivr.net") ||
      url.hostname.includes("cdnjs.cloudflare.com")
    ) {
      event.respondWith(
        caches.match(request).then((response) => {
          return (
            response ||
            fetch(request).then((fetchResponse) => {
              return caches.open(CACHE_NAME).then((cache) => {
                cache.put(request, fetchResponse.clone());
                return fetchResponse;
              });
            })
          );
        })
      );
    }
    return;
  }

  // Skip API requests (always fetch fresh)
  if (url.pathname.includes("/api/")) {
    event.respondWith(fetch(request));
    return;
  }

  // Skip admin routes (always fetch fresh)
  if (url.pathname.includes("/admin/")) {
    event.respondWith(fetch(request));
    return;
  }

  // For PWA routes and static assets, use cache-first strategy
  event.respondWith(
    caches
      .match(request)
      .then((cachedResponse) => {
        if (cachedResponse) {
          // Return cached response and update cache in background
          fetchAndCache(request);
          return cachedResponse;
        }

        // Not in cache, fetch from network
        return fetchAndCache(request);
      })
      .catch(() => {
        // Network failed, return offline page if available
        if (request.mode === "navigate") {
          return caches.match("/offline");
        }
      })
  );
});

// Helper function to fetch and cache
function fetchAndCache(request) {
  return fetch(request).then((response) => {
    // Don't cache non-successful responses
    if (!response || response.status !== 200 || response.type === "error") {
      return response;
    }

    // Clone the response
    const responseToCache = response.clone();

    // Cache the response
    caches.open(RUNTIME_CACHE).then((cache) => {
      cache.put(request, responseToCache);
    });

    return response;
  });
}

// Push notification event
self.addEventListener("push", (event) => {
  console.log("[Service Worker] Push notification received");

  let notificationData = {
    title: "Birthday Reminder",
    body: "You have new birthday reminders!",
    icon: URL_PATH + "/public/images/icons/icon-192x192.png",
    badge: URL_PATH + "/public/images/icons/icon-72x72.png",
    vibrate: [200, 100, 200],
    tag: "birthday-reminder",
    requireInteraction: true,
    data: {
      url: URL_PATH + "/home",
    },
    actions: [
      {
        action: "view",
        title: "View",
        icon: URL_PATH + "/public/images/icons/icon-72x72.png",
      },
      {
        action: "close",
        title: "Close",
        icon: URL_PATH + "/public/images/icons/icon-72x72.png",
      },
    ],
  };

  // Parse notification data if available
  if (event.data) {
    try {
      const payload = event.data.json();
      console.log("[Service Worker] Parsed notification payload:", payload);
      notificationData = {
        ...notificationData,
        ...payload,
      };
    } catch (e) {
      // Fallback to text if not JSON
      console.log("[Service Worker] Using text payload");
      notificationData.body = event.data.text();
    }
  }

  event.waitUntil(
    self.registration.showNotification(notificationData.title, {
      body: notificationData.body,
      icon: notificationData.icon,
      badge: notificationData.badge,
      vibrate: notificationData.vibrate,
      tag: notificationData.tag,
      requireInteraction: notificationData.requireInteraction,
      data: notificationData.data,
      actions: notificationData.actions,
    })
  );
});

// Notification click event
self.addEventListener("notificationclick", (event) => {
  console.log("[Service Worker] Notification clicked");
  console.log("[Service Worker] Action:", event.action);
  console.log("[Service Worker] Notification data:", event.notification.data);

  // Close the notification
  event.notification.close();

  // Get the URL to open (from notification data or default)
  const urlToOpen = event.notification.data?.url || "/home";

  // Handle different actions
  if (event.action === "close") {
    // User clicked close, just close the notification
    console.log("[Service Worker] Notification closed by user");
    return;
  }

  // For 'view' action or default click, open the PWA
  event.waitUntil(
    clients
      .matchAll({
        type: "window",
        includeUncontrolled: true,
      })
      .then((clientList) => {
        console.log(
          "[Service Worker] Found",
          clientList.length,
          "open windows"
        );

        // Check if PWA is already open
        for (let i = 0; i < clientList.length; i++) {
          const client = clientList[i];
          console.log("[Service Worker] Checking client:", client.url);

          if (client.url.includes(location.origin) && "focus" in client) {
            // Focus existing window and navigate to home
            console.log("[Service Worker] Focusing existing window");
            return client.focus().then(() => {
              if ("navigate" in client) {
                console.log("[Service Worker] Navigating to:", urlToOpen);
                return client.navigate(urlToOpen);
              }
              return client;
            });
          }
        }

        // If no window is open, open a new one
        console.log("[Service Worker] Opening new window:", urlToOpen);
        if (clients.openWindow) {
          return clients.openWindow(urlToOpen);
        }
      })
      .catch((error) => {
        console.error(
          "[Service Worker] Error handling notification click:",
          error
        );
      })
  );
});

// Background sync event (for future use)
self.addEventListener("sync", (event) => {
  console.log("[Service Worker] Background sync:", event.tag);

  if (event.tag === "sync-data") {
    event.waitUntil(syncData());
  }
});

// Helper function for background sync
function syncData() {
  return fetch("/api/sync")
    .then((response) => response.json())
    .then((data) => {
      console.log("[Service Worker] Data synced:", data);
    })
    .catch((error) => {
      console.error("[Service Worker] Sync failed:", error);
    });
}

// Message event (for communication with main thread)
self.addEventListener("message", (event) => {
  console.log("[Service Worker] 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(RUNTIME_CACHE).then((cache) => cache.addAll(event.data.urls))
    );
  }
});
