/* =====================================================
 * Diminet Service Worker
 * - PWA bootstrap (install prompt, offline basics)
 * - Static asset caching
 * - Network-first for API/HTML
 * - Push notification scaffold
 * ===================================================== */

// [1] Version & cache names
const SW_VERSION = "v1.0.1"; // نسخه رو یک پله بردیم بالا برای ریفرش کش
const CACHE_PREFIX = "diminet-cache-";
const PRECACHE_NAME = `${CACHE_PREFIX}${SW_VERSION}-precache`;
const RUNTIME_CACHE_NAME = `${CACHE_PREFIX}${SW_VERSION}-runtime`;

// [2] Core assets to pre-cache (edit these paths if needed)
const PRECACHE_URLS = [
  "/", // root
  "//index.php?tab=home", // main entry

  // اپ
  "/app/assets/js/app.js",
  "/app/assets/css/app.css",

  // PWA manifest + icons (مطمئن شو این فایل‌ها موجودن)
  "/app/manifest.webmanifest",
  "/assets/ico192.png",
  "/assets/ico512.png",

  "/logo.png"
];

// [3] Install event: pre-cache core assets
self.addEventListener("install", (event) => {
  event.waitUntil(
    caches.open(PRECACHE_NAME).then((cache) => {
      return cache.addAll(PRECACHE_URLS).catch((err) => {
        // اگر بعضی assetها خطا دادن، نذار کل SW بترکه
        console.warn("[SW] Precache error:", err);
      });
    })
  );

  // Activate new SW immediately
  self.skipWaiting();ح
});

// [4] Activate event: clean old caches
self.addEventListener("activate", (event) => {
  event.waitUntil(
    caches.keys().then((keys) => {
      const deletePromises = keys
        .filter(
          (key) =>
            key.startsWith(CACHE_PREFIX) &&
            key !== PRECACHE_NAME &&
            key !== RUNTIME_CACHE_NAME
        )
        .map((key) => caches.delete(key));

      return Promise.all(deletePromises);
    })
  );

  // Take control of uncontrolled clients
  self.clients.claim();
});

// [5] Fetch strategy
self.addEventListener("fetch", (event) => {
  const request = event.request;

  // Only handle same-origin GET requests
  if (
    request.method !== "GET" ||
    new URL(request.url).origin !== self.location.origin
  ) {
    return;
  }

  const url = new URL(request.url);

  // [5.1] Navigation requests (HTML pages) → network-first
  if (
    request.mode === "navigate" ||
    request.headers.get("accept")?.includes("text/html")
  ) {
    event.respondWith(networkFirst(request));
    return;
  }

  // [5.2] API endpoints → network-first
  if (
    url.pathname.startsWith("/app/api/") ||
    url.pathname === "/panel_data.php"
  ) {
    event.respondWith(networkFirst(request));
    return;
  }

  // [5.3] Static assets → cache-first (CSS / JS / images / fonts)
  if (
    url.pathname.endsWith(".js") ||
    url.pathname.endsWith(".css") ||
    url.pathname.endsWith(".png") ||
    url.pathname.endsWith(".jpg") ||
    url.pathname.endsWith(".jpeg") ||
    url.pathname.endsWith(".webp") ||
    url.pathname.endsWith(".svg") ||
    url.pathname.endsWith(".ico") ||
    url.pathname.endsWith(".woff") ||
    url.pathname.endsWith(".woff2") ||
    url.pathname.endsWith(".ttf")
  ) {
    event.respondWith(cacheFirst(request));
    return;
  }

  // Default: try network, fallback to cache
  event.respondWith(networkFirst(request));
});

// [5.a] Network-first helper
async function networkFirst(request) {
  try {
    const response = await fetch(request);
    const cache = await caches.open(RUNTIME_CACHE_NAME);
    cache.put(request, response.clone());
    return response;
  } catch (err) {
    // Fallback to cache
    const cached = await caches.match(request);
    if (cached) {
      return cached;
    }

    // As a last resort, try to serve "/" or "/index.php"
    const fallback =
      (await caches.match("/index.php")) ||
      (await caches.match("/")) ||
      new Response("Offline", { status: 503, statusText: "Offline" });

    return fallback;
  }
}

// [5.b] Cache-first helper
async function cacheFirst(request) {
  const cached = await caches.match(request);
  if (cached) {
    // Update cache in background
    fetch(request)
      .then((response) => {
        return caches.open(RUNTIME_CACHE_NAME).then((cache) => {
          cache.put(request, response.clone());
        });
      })
      .catch(() => {
        // ignore background update errors
      });

    return cached;
  }

  // Not in cache → go network
  try {
    const response = await fetch(request);
    const cache = await caches.open(RUNTIME_CACHE_NAME);
    cache.put(request, response.clone());
    return response;
  } catch (err) {
    // Network failed and no cache
    return new Response("Offline", { status: 503, statusText: "Offline" });
  }
}

// [6] Message handler (for future use from app.js)
self.addEventListener("message", (event) => {
  if (!event.data) return;

  if (event.data.type === "SKIP_WAITING") {
    self.skipWaiting();
  }

  if (event.data.type === "CLEAR_RUNTIME_CACHE") {
    caches.keys().then((keys) => {
      keys
        .filter((key) => key === RUNTIME_CACHE_NAME)
        .forEach((key) => caches.delete(key));
    });
  }
});

// [7] Push notifications (scaffold)
self.addEventListener("push", (event) => {
  if (!event.data) {
    return;
  }

  let payload = {};
  try {
    payload = event.data.json();
  } catch (e) {
    payload = { title: "Diminet", body: event.data.text() };
  }

  const title = payload.title || "Diminet";
  const body = payload.body || "";
  const icon = payload.icon || "/favicon.ico";
  const urlToOpen = payload.url || "/";

  const options = {
    body,
    icon,
    data: {
      url: urlToOpen
    }
  };

  event.waitUntil(self.registration.showNotification(title, options));
});

// [8] Notification click handler
self.addEventListener("notificationclick", (event) => {
  event.notification.close();

  const targetUrl = event.notification.data?.url || "/";
  const absoluteUrl = new URL(targetUrl, self.location.origin).href;

  event.waitUntil(
    clients
      .matchAll({ type: "window", includeUncontrolled: true })
      .then((clientList) => {
        for (const client of clientList) {
          if (client.url === absoluteUrl && "focus" in client) {
            return client.focus();
          }
        }
        if (clients.openWindow) {
          return clients.openWindow(absoluteUrl);
        }
      })
  );
});
