const TILE_CACHE = 'lageplan-tiles-v3'
const STATIC_CACHE = 'lageplan-static-v3'
const APP_CACHE = 'lageplan-app-v3'
const API_CACHE = 'lageplan-api-v3'

// API routes that should be cached for offline use
const CACHEABLE_API = ['/api/icons', '/api/hose-types', '/api/dictionary']

// Pre-cache essential app shell on install
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(APP_CACHE).then((cache) =>
      cache.addAll([
        '/app',
        '/login',
        '/',
        '/logo.svg',
        '/logo-icon.png',
        '/manifest.json',
      ]).catch(() => {})
    )
  )
  self.skipWaiting()
})

self.addEventListener('fetch', (event) => {
  const url = event.request.url
  const { pathname } = new URL(url)

  // Skip non-GET requests
  if (event.request.method !== 'GET') return

  // Never intercept Socket.IO — let it pass through directly
  if (pathname.startsWith('/socket.io')) return

  // Cacheable API routes: Network First with cache fallback (icons, hose-types, dictionary)
  if (CACHEABLE_API.some(p => pathname.startsWith(p))) {
    event.respondWith(
      caches.open(API_CACHE).then((cache) =>
        fetch(event.request).then((response) => {
          if (response.ok) cache.put(event.request, response.clone())
          return response
        }).catch(() =>
          cache.match(event.request).then((cached) => cached || new Response('{"error":"offline"}', {
            status: 503, headers: { 'Content-Type': 'application/json' }
          }))
        )
      )
    )
    return
  }

  // Projects API: Network First with cache fallback
  if (pathname === '/api/projects' || pathname.match(/^\/api\/projects\/[^/]+$/)) {
    event.respondWith(
      caches.open(API_CACHE).then((cache) =>
        fetch(event.request).then((response) => {
          if (response.ok) cache.put(event.request, response.clone())
          return response
        }).catch(() =>
          cache.match(event.request).then((cached) => cached || new Response('{"error":"offline"}', {
            status: 503, headers: { 'Content-Type': 'application/json' }
          }))
        )
      )
    )
    return
  }

  // Features API: Network First with cache fallback
  if (pathname.match(/^\/api\/projects\/[^/]+\/features$/)) {
    event.respondWith(
      caches.open(API_CACHE).then((cache) =>
        fetch(event.request).then((response) => {
          if (response.ok) cache.put(event.request, response.clone())
          return response
        }).catch(() =>
          cache.match(event.request).then((cached) => cached || new Response('{"error":"offline"}', {
            status: 503, headers: { 'Content-Type': 'application/json' }
          }))
        )
      )
    )
    return
  }

  // Other API requests: network only
  if (pathname.startsWith('/api/')) return

  // Cache map tiles from OSM / MapTiler / ArcGIS / Swisstopo (Cache First — tiles don't change)
  if (url.includes('tile.openstreetmap.org') || url.includes('api.maptiler.com') || url.includes('server.arcgisonline.com') || url.includes('geo.admin.ch')) {
    event.respondWith(
      caches.open(TILE_CACHE).then((cache) =>
        cache.match(event.request).then((cached) => {
          if (cached) return cached
          return fetch(event.request).then((response) => {
            if (response.ok) cache.put(event.request, response.clone())
            return response
          }).catch(() => new Response('', { status: 503 }))
        })
      )
    )
    return
  }

  // Next.js build chunks (_next/static): Cache First (hashed filenames = immutable)
  if (pathname.startsWith('/_next/static/')) {
    event.respondWith(
      caches.open(STATIC_CACHE).then((cache) =>
        cache.match(event.request).then((cached) => {
          if (cached) return cached
          return fetch(event.request).then((response) => {
            if (response.ok) cache.put(event.request, response.clone())
            return response
          }).catch(() => new Response('', { status: 503 }))
        })
      )
    )
    return
  }

  // Other static assets (JS, CSS, images, fonts): Stale While Revalidate
  if (pathname.match(/\.(js|css|png|jpg|jpeg|svg|ico|woff2?)$/)) {
    event.respondWith(
      caches.open(STATIC_CACHE).then((cache) =>
        cache.match(event.request).then((cached) => {
          const fetchPromise = fetch(event.request).then((response) => {
            if (response.ok) cache.put(event.request, response.clone())
            return response
          }).catch(() => cached || new Response('', { status: 503 }))
          return cached || fetchPromise
        })
      )
    )
    return
  }

  // App pages / navigation: Network First with cache fallback
  if (event.request.mode === 'navigate' || pathname === '/app' || pathname === '/' || pathname.startsWith('/app')) {
    event.respondWith(
      fetch(event.request).then((response) => {
        if (response.ok) {
          const clone = response.clone()
          caches.open(APP_CACHE).then((cache) => cache.put(event.request, clone))
        }
        return response
      }).catch(() =>
        caches.match(event.request).then((cached) => cached || caches.match('/app'))
      )
    )
    return
  }
})

// Clean old caches on activation
self.addEventListener('activate', (event) => {
  const currentCaches = [TILE_CACHE, STATIC_CACHE, APP_CACHE, API_CACHE]
  event.waitUntil(
    caches.keys().then((keys) =>
      Promise.all(
        keys
          .filter((k) => !currentCaches.includes(k))
          .map((k) => caches.delete(k))
      )
    ).then(() => self.clients.claim())
  )
})

// Listen for sync events (Background Sync for queued saves)
self.addEventListener('sync', (event) => {
  if (event.tag === 'sync-saves') {
    event.waitUntil(syncQueuedSaves())
  }
})

// Process queued saves from IndexedDB/localStorage
async function syncQueuedSaves() {
  try {
    const clients = await self.clients.matchAll()
    clients.forEach(client => client.postMessage({ type: 'SYNC_START' }))

    // Read queue from a BroadcastChannel or let the main thread handle it
    clients.forEach(client => client.postMessage({ type: 'FLUSH_SYNC_QUEUE' }))
  } catch (e) {
    console.error('[SW] Sync error:', e)
  }
}
