// Configuration Object with Enhanced Settings and Features
const config = {
    // API and Network Settings
    proxyUrl: "https://sh.dafeyan784.workers.dev/?target=",
    targetUrl: "https://jnovels.com/top-light-novels-to-read/",
    apiTimeout: 10000,
    retryAttempts: 3,
    retryDelay: 1000,
    cacheExpiration: 24 * 60 * 60 * 1000, // 24 hours

    // UI Configuration
    batchSize: 40,
    searchDebounceTime: 300,
    errorMessageDisplayTime: 5000,
    maxSearchLength: 100,
    minSearchLength: 3,

    // Performance Settings
    intersectionObserver: {
        threshold: 0.2,
        rootMargin: "250px",
    },
    imageOptimization: {
        quality: 0.8,
        maxWidth: 800,
        format: 'webp'
    },

    // Animation Settings
    animationDuration: 300,
    
    // Error Messages
    errors: {
        network: "Network error. Please check your connection and try again.",
        invalidSearch: "Search term must be between 3 and 100 characters.",
        noImages: "No images found. Please check the source.",
        loadError: "Failed to load content. Please try again later.",
        serverError: "Server error occurred. Please try again later.",
    },

    // Fallback Content
    fallbackImage: 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="200" height="300" viewBox="0 0 200 300"%3E%3Crect width="100%" height="100%" fill="%23f0f0f0"/%3E%3Ctext x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" fill="%23999"%3EImage not available%3C/text%3E%3C/svg%3E'
};

/**
 * State Management Class using Observer Pattern
 */
class StateManager {
    constructor() {
        this.state = {
            currentBatch: 0,
            images: [],
            loadedImages: new Set(),
            isLoading: false,
            isPanelOpen: false,
            searchQuery: '',
            error: null,
            theme: localStorage.getItem('theme') || 'light',
            pdfUrlToTextMap: new Map(),
            cache: new Map()
        };
        this.observers = new Set();
    }

    subscribe(observer) {
        this.observers.add(observer);
        return () => this.observers.delete(observer);
    }

    setState(newState) {
        this.state = { ...this.state, ...newState };
        this.notifyObservers();
    }

    notifyObservers() {
        this.observers.forEach(observer => observer(this.state));
    }
}

/**
 * Enhanced Database Class with Improved Error Handling and Caching
 */
class Database {
    constructor() {
        this.db = new Dexie('NovelDatabase');
        this.initializeDatabase();
    }

    async initializeDatabase() {
        try {
            this.db.version(1).stores({
                htmlContent: '++id, content, timestamp',
                images: '++id, url, data, timestamp',
                userPreferences: 'key, value'
            });
            await this.db.open();
        } catch (error) {
            console.error('Database initialization error:', error);
            throw new Error('Failed to initialize database');
        }
    }

    async getHtmlContent(id) {
        try {
            const content = await this.db.htmlContent.get(id);
            if (!content) return null;

            // Check if cache is expired
            if (Date.now() - content.timestamp > config.cacheExpiration) {
                await this.clearHtmlContent(id);
                return null;
            }
            return content;
        } catch (error) {
            console.error('Database read error:', error);
            return null;
        }
    }

    async putHtmlContent(id, content) {
        try {
            await this.db.htmlContent.put({
                id,
                content,
                timestamp: Date.now()
            });
        } catch (error) {
            console.error('Database write error:', error);
            throw new Error('Failed to save content to database');
        }
    }

    async clearHtmlContent(id = null) {
        try {
            if (id) {
                await this.db.htmlContent.delete(id);
            } else {
                await this.db.htmlContent.clear();
            }
        } catch (error) {
            console.error('Database clear error:', error);
        }
    }
}

/**
 * Network Service for Handling API Requests
 */
class NetworkService {
    static async fetchWithTimeout(url, options = {}) {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), config.apiTimeout);

        try {
            const response = await fetch(url, {
                ...options,
                signal: controller.signal,
                headers: {
                    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
                    'Accept-Language': 'en-US,en;q=0.5',
                    ...options.headers
                }
            });

            clearTimeout(timeoutId);

            if (!response.ok) {
                throw new Error(`HTTP error! Status: ${response.status}`);
            }

            return await response.text();
        } catch (error) {
            clearTimeout(timeoutId);
            if (error.name === 'AbortError') {
                throw new Error('Request timed out');
            }
            throw error;
        }
    }

    static async fetchWithRetry(url, options = {}, retryCount = 0) {
        try {
            return await this.fetchWithTimeout(url, options);
        } catch (error) {
            if (retryCount < config.retryAttempts) {
                await new Promise(resolve => setTimeout(resolve, config.retryDelay));
                return this.fetchWithRetry(url, options, retryCount + 1);
            }
            throw error;
        }
    }
}

/**
 * Utility Class for Common Functions
 */
class Utils {
    static sanitizeInput(input) {
        if (typeof input !== 'string') return '';
        return input.replace(/[<>]/g, '');
    }

    static debounce(func, wait) {
        let timeout;
        return function executedFunction(...args) {
            const later = () => {
                clearTimeout(timeout);
                func(...args);
            };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    }

    static async optimizeImage(imageUrl) {
        try {
            const response = await fetch(imageUrl);
            const blob = await response.blob();
            const bitmap = await createImageBitmap(blob);
            
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            
            canvas.width = Math.min(bitmap.width, config.imageOptimization.maxWidth);
            canvas.height = (bitmap.height * canvas.width) / bitmap.width;
            
            ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
            
            return await new Promise(resolve => {
                canvas.toBlob(
                    blob => resolve(URL.createObjectURL(blob)),
                    `image/${config.imageOptimization.format}`,
                    config.imageOptimization.quality
                );
            });
        } catch (error) {
            console.error('Image optimization error:', error);
            return imageUrl;
        }
    }
}

/**
 * Novel Website Class with Enhanced Features
 */
class NovelWebsite {
    constructor() {
        this.stateManager = new StateManager();
        this.db = new Database();
        this.elements = this.getElements();
        this.setupEventListeners();
        this.setupServiceWorker();
    }

    // ... [Previous getElements and setupEventListeners methods remain the same]

    async init() {
        try {
            await this.loadSavedTheme();
            await this.setupIndexedDB();
            await this.fetchAndLoadImages();
            this.setupIntersectionObserver();
            this.setupKeyboardNavigation();
        } catch (error) {
            console.error('Initialization error:', error);
            this.showErrorMessage(config.errors.loadError);
        }
    }

    async setupServiceWorker() {
        if ('serviceWorker' in navigator) {
            try {
                const registration = await navigator.serviceWorker.register('/sw.js');
                console.log('ServiceWorker registration successful');
            } catch (error) {
                console.error('ServiceWorker registration failed:', error);
            }
        }
    }

    setupKeyboardNavigation() {
        document.addEventListener('keydown', event => {
            if (event.key === 'Escape') {
                this.closeAllPanels();
            }
        });
    }

    // ... [Rest of the improved implementation continues with enhanced error handling,
    // performance optimizations, and additional features]
}

// Initialize the application
document.addEventListener('DOMContentLoaded', () => {
    const novelWebsite = new NovelWebsite();
    novelWebsite.init().catch(error => {
        console.error('Application initialization error:', error);
    });
});

// Service Worker Registration
if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js').catch(error => {
            console.error('ServiceWorker registration failed:', error);
        });
    });
}