/**
 * Author: MAKATANGA
 * Telegram: @MAKATANGA
 */
const CACHE_NAME = 'freecms-v2';
const URLS_TO_CACHE = [
    '/',
    '/public/assets/css/style.css',
    '/public/assets/css/ui-new.css',
    '/public/assets/js/app.js',
    '/public/assets/js/desktop-features.js',
    '/manifest.json'
];

// Install event - cache resources
self.addEventListener('install', event => {
    event.waitUntil(
        caches.open(CACHE_NAME).then(cache => {
            return cache.addAll(URLS_TO_CACHE).catch(err => {
                console.log('Cache addAll error:', err);
            });
        })
    );
    self.skipWaiting();
});

// Activate event - clean up old caches
self.addEventListener('activate', event => {
    event.waitUntil(
        caches.keys().then(cacheNames => {
            return Promise.all(
                cacheNames
                    .filter(cacheName => cacheName !== CACHE_NAME)
                    .map(cacheName => caches.delete(cacheName))
            );
        })
    );
    self.clients.claim();
});

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

    // Skip cross-origin requests
    if (url.origin !== location.origin) return;

    // API requests and Documents - Network First
    if (url.pathname.startsWith('/api/') || 
        url.pathname.startsWith('/language') || 
        url.pathname.startsWith('/set-lang') || 
        request.destination === 'document') {
        event.respondWith(
            fetch(request)
                .then(response => {
                    const clone = response.clone();
                    caches.open(CACHE_NAME).then(cache => {
                        cache.put(request, clone);
                    });
                    return response;
                })
                .catch(() => {
                    return caches.match(request);
                })
        );
        return;
    }

    // Static assets - Cache First
    if (request.method === 'GET') {
        event.respondWith(
            caches.match(request).then(response => {
                if (response) return response;
                
                return fetch(request).then(response => {
                    const clone = response.clone();
                    caches.open(CACHE_NAME).then(cache => {
                        cache.put(request, clone);
                    });
                    return response;
                }).catch(() => {
                    // Offline fallback
                    if (request.destination === 'document') {
                        return caches.match('/');
                    }
                });
            })
        );
        return;
    }
});

// Push notifications
self.addEventListener('push', event => {
    if (!event.data) return;

    try {
        const data = event.data.json();
        const options = {
            body: data.body,
            icon: '/public/assets/images/icon-192x192.png',
            badge: '/public/assets/images/badge-72x72.png',
            tag: data.tag || 'notification',
            requireInteraction: data.requireInteraction || false,
            data: {
                url: data.url || '/'
            }
        };

        event.waitUntil(
            self.registration.showNotification(data.title || 'FreeCMS', options)
        );
    } catch (e) {
        console.error('Push error:', e);
    }
});

// Notification click
self.addEventListener('notificationclick', event => {
    event.notification.close();

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

// Background sync for offline actions
self.addEventListener('sync', event => {
    if (event.tag === 'sync-posts') {
        event.waitUntil(syncOfflinePosts());
    } else if (event.tag === 'sync-votes') {
        event.waitUntil(syncOfflineVotes());
    }
});

async function syncOfflinePosts() {
    const db = await openDatabase();
    const posts = await getAllFromStore(db, 'pending-posts');
    
    for (const post of posts) {
        try {
            const response = await fetch('/post/store', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(post.data)
            });
            
            if (response.ok) {
                await deleteFromStore(db, 'pending-posts', post.id);
            }
        } catch (error) {
            console.error('Sync post failed:', error);
        }
    }
}

async function syncOfflineVotes() {
    const db = await openDatabase();
    const votes = await getAllFromStore(db, 'pending-votes');
    
    for (const vote of votes) {
        try {
            const response = await fetch('/post/vote', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(vote.data)
            });
            
            if (response.ok) {
                await deleteFromStore(db, 'pending-votes', vote.id);
            }
        } catch (error) {
            console.error('Sync vote failed:', error);
        }
    }
}

function openDatabase() {
    return new Promise((resolve, reject) => {
        const request = indexedDB.open('freecms', 1);
        
        request.onerror = () => reject(request.error);
        request.onsuccess = () => resolve(request.result);
        
        request.onupgradeneeded = event => {
            const db = event.target.result;
            if (!db.objectStoreNames.contains('pending-posts')) {
                db.createObjectStore('pending-posts', { keyPath: 'id', autoIncrement: true });
            }
            if (!db.objectStoreNames.contains('pending-votes')) {
                db.createObjectStore('pending-votes', { keyPath: 'id', autoIncrement: true });
            }
        };
    });
}

function getAllFromStore(db, storeName) {
    return new Promise((resolve, reject) => {
        const transaction = db.transaction([storeName], 'readonly');
        const store = transaction.objectStore(storeName);
        const request = store.getAll();
        
        request.onerror = () => reject(request.error);
        request.onsuccess = () => resolve(request.result);
    });
}

function deleteFromStore(db, storeName, key) {
    return new Promise((resolve, reject) => {
        const transaction = db.transaction([storeName], 'readwrite');
        const store = transaction.objectStore(storeName);
        const request = store.delete(key);
        
        request.onerror = () => reject(request.error);
        request.onsuccess = () => resolve();
    });
}
