"""Genera el codigo JavaScript de un Service Worker basico para PWAs."""

from __future__ import annotations


def generate_service_worker(
    cache_name: str = "app-cache-v1",
    precache_urls: list[str] | None = None,
    network_first_patterns: list[str] | None = None,
) -> str:
    """Genera el codigo JavaScript de un Service Worker con estrategia cache-first
    para assets estaticos y network-first para API calls.

    Args:
        cache_name: Nombre del cache a usar para esta version del SW.
        precache_urls: URLs a pre-cachear en el evento install.
        network_first_patterns: Patrones de URL que usan estrategia network-first.

    Returns:
        String con codigo JavaScript valido del Service Worker.
    """
    if precache_urls is None:
        precache_urls = ["/", "/index.html"]
    if network_first_patterns is None:
        network_first_patterns = ["/api/"]

    precache_urls_js = _list_to_js_array(precache_urls, indent=2)
    network_patterns_js = _list_to_js_array(network_first_patterns, indent=2)
    network_check_js = _build_network_check(network_first_patterns)

    return f"""\
// Service Worker — generado automaticamente
// Estrategia: cache-first para assets, network-first para API

const CACHE_NAME = '{cache_name}';

const PRECACHE_URLS = {precache_urls_js};

const NETWORK_FIRST_PATTERNS = {network_patterns_js};

// ── install ──────────────────────────────────────────────────────────────────
// Pre-cachea los assets estaticos esenciales al instalar el SW.
self.addEventListener('install', (event) => {{
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {{
      return cache.addAll(PRECACHE_URLS);
    }})
  );
  self.skipWaiting();
}});

// ── activate ─────────────────────────────────────────────────────────────────
// Limpia caches de versiones anteriores al activar la nueva version del SW.
self.addEventListener('activate', (event) => {{
  event.waitUntil(
    caches.keys().then((cacheNames) => {{
      return Promise.all(
        cacheNames
          .filter((name) => name !== CACHE_NAME)
          .map((name) => caches.delete(name))
      );
    }})
  );
  self.clients.claim();
}});

// ── fetch ─────────────────────────────────────────────────────────────────────
// Intercepta peticiones:
//   - URLs que coinciden con NETWORK_FIRST_PATTERNS → network-first con fallback a cache
//   - El resto → cache-first con fallback a network (y guarda en cache la respuesta)
self.addEventListener('fetch', (event) => {{
  const url = event.request.url;

  const isNetworkFirst = {network_check_js};

  if (isNetworkFirst) {{
    // Network-first: intenta red, si falla usa cache
    event.respondWith(
      fetch(event.request)
        .then((response) => {{
          if (response && response.status === 200) {{
            const responseClone = response.clone();
            caches.open(CACHE_NAME).then((cache) => {{
              cache.put(event.request, responseClone);
            }});
          }}
          return response;
        }})
        .catch(() => caches.match(event.request))
    );
  }} else {{
    // Cache-first: sirve desde cache, si no existe va a red y guarda en cache
    event.respondWith(
      caches.match(event.request).then((cached) => {{
        if (cached) {{
          return cached;
        }}
        return fetch(event.request).then((response) => {{
          if (response && response.status === 200) {{
            const responseClone = response.clone();
            caches.open(CACHE_NAME).then((cache) => {{
              cache.put(event.request, responseClone);
            }});
          }}
          return response;
        }});
      }})
    );
  }}
}});
"""


def _list_to_js_array(items: list[str], indent: int = 0) -> str:
    """Convierte una lista Python a un array JS multilínea."""
    if not items:
        return "[]"
    pad = " " * indent
    inner = f",\n{pad}  ".join(f"'{item}'" for item in items)
    return f"[\n{pad}  {inner},\n{pad}]"


def _build_network_check(patterns: list[str]) -> str:
    """Genera la expresion JS que comprueba si una URL matchea algun patron."""
    if not patterns:
        return "false"
    checks = " || ".join(f"url.includes('{p}')" for p in patterns)
    return checks
