/**
 * Advanced Link Prefetching System
 * Supports multiple strategies: hover, visible, eager
 */
import { Logger } from './logger.js';
import { SimpleCache } from '../utils/cache.js';

export class LinkPrefetcher {
    constructor(options = {}) {
        this.options = {
            maxCacheSize: options.maxCacheSize || 20,
            cacheTTL: options.cacheTTL || 60000, // 60 seconds
            hoverDelay: options.hoverDelay || 150, // ms before prefetch on hover
            strategies: options.strategies || ['hover', 'visible'], // Available: hover, visible, eager
            observerMargin: options.observerMargin || '50px',
            priority: options.priority || 'low', // low, high
            ...options
        };

        this.cache = new SimpleCache(this.options.maxCacheSize, this.options.cacheTTL);
        this.prefetching = new Set(); // Currently prefetching URLs
        this.prefetched = new Set(); // Already prefetched URLs
        this.observer = null;
        this.hoverTimeout = null;
        this.cleanupInterval = null;
        
        this.init();
    }

    init() {
        // Setup strategies
        if (this.options.strategies.includes('visible')) {
            this.setupIntersectionObserver();
        }

        // Setup cleanup interval
        this.cleanupInterval = setInterval(() => {
            this.cache.cleanup();
        }, 120000); // Clean every 2 minutes

        Logger.info('[LinkPrefetcher] initialized with strategies:', this.options.strategies);
    }

    setupIntersectionObserver() {
        if (!('IntersectionObserver' in window)) {
            Logger.warn('[LinkPrefetcher] IntersectionObserver not supported');
            return;
        }

        this.observer = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const link = entry.target;
                    const href = link.getAttribute('href');
                    
                    // Lower priority for visible links
                    this.prefetch(href, { priority: 'low' });
                    
                    // Stop observing once prefetched
                    this.observer.unobserve(link);
                }
            });
        }, {
            rootMargin: this.options.observerMargin
        });
    }

    /**
     * Check if a link should be prefetched
     */
    shouldPrefetch(link) {
        if (!link || !(link instanceof HTMLAnchorElement)) return false;
        
        const href = link.getAttribute('href');
        if (!href || href.startsWith('#') || href.startsWith('mailto:') || href.startsWith('tel:')) {
            return false;
        }

        // Skip external links
        try {
            const url = new URL(href, window.location.origin);
            if (url.origin !== window.location.origin) return false;
        } catch {
            return false;
        }

        // Skip if has data-no-prefetch attribute
        if (link.hasAttribute('data-no-prefetch')) return false;

        // Skip download links
        if (link.hasAttribute('download')) return false;

        // Skip target="_blank" links
        if (link.target === '_blank') return false;

        return true;
    }

    /**
     * Prefetch a URL
     */
    async prefetch(href, options = {}) {
        if (!href || this.prefetching.has(href) || this.cache.has(href)) {
            return;
        }

        // Mark as prefetching
        this.prefetching.add(href);

        try {
            Logger.info(`[LinkPrefetcher] prefetching: ${href}`);

            // Use different methods based on priority
            if (options.priority === 'high' || this.options.priority === 'high') {
                await this.fetchWithPriority(href, 'high');
            } else {
                // Use link prefetch hint for low priority
                this.createPrefetchLink(href);
                // Also fetch for cache
                await this.fetchWithPriority(href, 'low');
            }

        } catch (error) {
            Logger.warn(`[LinkPrefetcher] failed to prefetch ${href}:`, error);
        } finally {
            this.prefetching.delete(href);
            this.prefetched.add(href);
        }
    }

    /**
     * Fetch with priority
     */
    async fetchWithPriority(href, priority = 'low') {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), 10000); // 10s timeout

        try {
            const response = await fetch(href, {
                signal: controller.signal,
                priority: priority, // Fetch priority hint (Chrome 121+)
                credentials: 'same-origin',
                headers: {
                    'X-Prefetch': 'true'
                }
            });

            clearTimeout(timeoutId);

            if (response.ok) {
                const html = await response.text();
                this.cache.set(href, {
                    data: html,
                    timestamp: Date.now(),
                    headers: {
                        contentType: response.headers.get('content-type'),
                        lastModified: response.headers.get('last-modified')
                    }
                });
            }
        } catch (error) {
            clearTimeout(timeoutId);
            if (error.name !== 'AbortError') {
                throw error;
            }
        }
    }

    /**
     * Create a link element for browser prefetch hint
     */
    createPrefetchLink(href) {
        // Check if already exists
        if (document.querySelector(`link[rel="prefetch"][href="${href}"]`)) {
            return;
        }

        const link = document.createElement('link');
        link.rel = 'prefetch';
        link.href = href;
        link.as = 'document';
        document.head.appendChild(link);

        // Remove after some time to avoid cluttering
        setTimeout(() => link.remove(), 30000);
    }

    /**
     * Handle hover events
     */
    handleHover(link) {
        if (!this.shouldPrefetch(link)) return;

        const href = link.getAttribute('href');
        
        clearTimeout(this.hoverTimeout);
        this.hoverTimeout = setTimeout(() => {
            this.prefetch(href, { priority: 'high' });
        }, this.options.hoverDelay);
    }

    /**
     * Handle mouse leave
     */
    handleMouseLeave() {
        clearTimeout(this.hoverTimeout);
    }

    /**
     * Observe a link for intersection
     */
    observeLink(link) {
        if (!this.observer || !this.shouldPrefetch(link)) return;
        
        this.observer.observe(link);
    }

    /**
     * Observe all links in a container
     */
    observeLinks(container = document) {
        if (!this.options.strategies.includes('visible')) return;

        const links = container.querySelectorAll('a[href]');
        links.forEach(link => this.observeLink(link));
    }

    /**
     * Eagerly prefetch specific URLs
     */
    prefetchEager(urls) {
        if (!Array.isArray(urls)) urls = [urls];
        
        urls.forEach(url => {
            this.prefetch(url, { priority: 'high' });
        });
    }

    /**
     * Get cached content
     */
    getCached(href) {
        const cached = this.cache.get(href);
        return cached ? cached.data : null;
    }

    /**
     * Check if URL is cached
     */
    isCached(href) {
        return this.cache.has(href);
    }

    /**
     * Clear cache
     */
    clearCache() {
        this.cache.clear();
        this.prefetched.clear();
    }

    /**
     * Get cache statistics
     */
    getStats() {
        return {
            cacheSize: this.cache.size(),
            prefetching: this.prefetching.size,
            prefetched: this.prefetched.size,
            strategies: this.options.strategies
        };
    }

    /**
     * Destroy the prefetcher
     */
    destroy() {
        clearTimeout(this.hoverTimeout);
        clearInterval(this.cleanupInterval);
        
        if (this.observer) {
            this.observer.disconnect();
        }
        
        this.cache.clear();
        this.prefetching.clear();
        this.prefetched.clear();
        
        // Remove all prefetch links
        document.querySelectorAll('link[rel="prefetch"]').forEach(link => link.remove());
        
        Logger.info('[LinkPrefetcher] destroyed');
    }
}

// Export singleton instance
export const linkPrefetcher = new LinkPrefetcher();