/**
 * GUARDiA ITSM — Service Worker (F-4 Mobile PWA)
 *
 * 전략:
 *   - 정적 자산 : Cache-First (빠른 로딩)
 *   - API 요청  : Network-First (최신 데이터 우선, 오프라인 시 캐시)
 *   - 오프라인  : /static/offline.html 폴백
 *
 * 캐시 버전이 바뀌면 이전 캐시를 자동 정리합니다.
 */

const CACHE_VERSION  = 'guardia-v1';
const STATIC_CACHE   = `${CACHE_VERSION}-static`;
const API_CACHE      = `${CACHE_VERSION}-api`;
const OFFLINE_URL    = '/static/offline.html';

// 설치 시 사전 캐싱할 정적 자산
const PRECACHE_URLS = [
  '/',
  '/static/offline.html',
  '/static/manifest.json',
  '/static/style.css',
  '/static/app.js',
  '/static/login.html',
  '/static/login.css',
  '/static/login.js',
  '/static/index.html',
  '/static/customer.html',
];

// API 캐시 대상 접두사
const API_CACHE_PREFIXES = [
  '/api/dashboard',
  '/api/sr',
  '/api/incidents',
  '/api/metrics/summary',
  '/api/metrics/health',
];

// 캐시하지 않을 API 경로 (실시간·민감 데이터)
const NO_CACHE_PATTERNS = [
  '/api/auth',
  '/api/audit',
  '/api/pam',
  '/api/otp',
  '/ws',
];

// ── 설치 (Install) ─────────────────────────────────────────────────────────
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(STATIC_CACHE)
      .then(cache => cache.addAll(PRECACHE_URLS).catch(() => {
        // 일부 파일이 없어도 SW 설치 계속 진행
        return Promise.resolve();
      }))
      .then(() => self.skipWaiting())
  );
});

// ── 활성화 (Activate) — 이전 캐시 정리 ─────────────────────────────────────
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(keys =>
      Promise.all(
        keys
          .filter(k => k.startsWith('guardia-') && k !== STATIC_CACHE && k !== API_CACHE)
          .map(k => caches.delete(k))
      )
    ).then(() => self.clients.claim())
  );
});

// ── Fetch 인터셉트 ─────────────────────────────────────────────────────────
self.addEventListener('fetch', event => {
  const { request } = event;
  const url = new URL(request.url);

  // 다른 오리진 요청은 처리하지 않음 (Ollama 등 내부 서비스 포함)
  if (url.origin !== self.location.origin) return;

  // WebSocket / POST/PUT/DELETE → 캐시 안 함
  if (request.method !== 'GET') return;

  // 보안 민감 경로 → 캐시 안 함
  if (NO_CACHE_PATTERNS.some(p => url.pathname.startsWith(p))) return;

  // API 요청 → Network-First
  if (url.pathname.startsWith('/api/')) {
    event.respondWith(networkFirst(request, API_CACHE));
    return;
  }

  // 정적 자산 → Cache-First
  event.respondWith(cacheFirst(request, STATIC_CACHE));
});

// ── 전략 함수 ──────────────────────────────────────────────────────────────

/**
 * Cache-First: 캐시 → 네트워크 → 오프라인 폴백
 */
async function cacheFirst(request, cacheName) {
  const cached = await caches.match(request);
  if (cached) return cached;

  try {
    const response = await fetch(request);
    if (response.ok) {
      const cache = await caches.open(cacheName);
      cache.put(request, response.clone());
    }
    return response;
  } catch {
    const offline = await caches.match(OFFLINE_URL);
    return offline || new Response('오프라인 상태입니다.', {
      status: 503,
      headers: { 'Content-Type': 'text/html; charset=utf-8' },
    });
  }
}

/**
 * Network-First: 네트워크 → 캐시 → 오프라인 폴백
 * API 응답은 5분간 캐시 유지
 */
async function networkFirst(request, cacheName) {
  try {
    const response = await fetch(request);
    if (response.ok) {
      const cache = await caches.open(cacheName);
      // API 응답에 캐시 타임스탬프 추가
      const cloned = response.clone();
      cache.put(request, cloned);
    }
    return response;
  } catch {
    const cached = await caches.match(request);
    if (cached) return cached;

    // HTML 요청 시 오프라인 페이지
    if (request.headers.get('Accept')?.includes('text/html')) {
      const offline = await caches.match(OFFLINE_URL);
      if (offline) return offline;
    }

    return new Response(
      JSON.stringify({ error: '오프라인 상태입니다.', offline: true }),
      {
        status: 503,
        headers: { 'Content-Type': 'application/json; charset=utf-8' },
      }
    );
  }
}

// ── 백그라운드 동기화 ──────────────────────────────────────────────────────
self.addEventListener('sync', event => {
  if (event.tag === 'guardia-sync-sr') {
    event.waitUntil(syncPendingSR());
  }
});

async function syncPendingSR() {
  // IndexedDB에서 오프라인 중 생성된 SR 대기열 처리 (향후 구현)
  // 현재는 로그만 기록
  console.log('[GUARDiA SW] 오프라인 SR 동기화 시작');
}

// ── 푸시 알림 ──────────────────────────────────────────────────────────────
self.addEventListener('push', event => {
  if (!event.data) return;

  let data;
  try {
    data = event.data.json();
  } catch {
    data = { title: 'GUARDiA 알림', body: event.data.text() };
  }

  const options = {
    body:    data.body    || '새 알림이 있습니다.',
    icon:    '/static/icons/icon-192.png',
    badge:   '/static/icons/icon-72.png',
    tag:     data.tag     || 'guardia-notification',
    data:    data.data    || {},
    actions: data.actions || [
      { action: 'view',    title: '확인' },
      { action: 'dismiss', title: '닫기' },
    ],
    requireInteraction: data.severity === 'CRITICAL',
  };

  event.waitUntil(
    self.registration.showNotification(data.title || 'GUARDiA ITSM', options)
  );
});

self.addEventListener('notificationclick', event => {
  event.notification.close();
  if (event.action === 'dismiss') return;

  const url = event.notification.data?.url || '/';
  event.waitUntil(
    clients.matchAll({ type: 'window', includeUncontrolled: true }).then(clientList => {
      for (const client of clientList) {
        if (client.url === url && 'focus' in client) return client.focus();
      }
      return clients.openWindow(url);
    })
  );
});
