/**
 * MkDocs Search Integration
 * Integrates MkDocs Material's search functionality into the map application
 */

export class MkDocsSearch {
    constructor(config = {}) {
        // Determine if we're in production based on current URL
        const isProduction = window.location.hostname !== 'localhost' && !window.location.hostname.includes('127.0.0.1');
        
        // Use production URL if we're not on localhost
        if (isProduction && config.mkdocsUrl && config.mkdocsUrl.includes('localhost')) {
            // Extract the base domain from the current hostname
            // If we're on map.cmlite.org, we want cmlite.org
            const currentDomain = window.location.hostname.replace(/^map\./, '');
            this.mkdocsUrl = `https://${currentDomain}`;
        } else {
            this.mkdocsUrl = config.mkdocsUrl || window.MKDOCS_URL || 'http://localhost:4002';
        }
        
        this.searchIndex = null;
        this.searchDocs = null;
        this.lunr = null;
        this.debounceTimeout = null;
        this.minSearchLength = config.minSearchLength || 2;
        this.initialized = false;
        
        console.log('MkDocs Search initialized with URL:', this.mkdocsUrl);
    }

    async initialize() {
        try {
            console.log('Initializing MkDocs search...');
            
            // Load Lunr.js dynamically
            await this.loadLunr();
            
            // Try multiple approaches to get the search index
            let searchData = null;
            
            // First try the proxy endpoint
            try {
                console.log('Trying proxy endpoint: /api/docs-search');
                const proxyResponse = await fetch('/api/docs-search');
                if (proxyResponse.ok) {
                    searchData = await proxyResponse.json();
                    console.log('Successfully loaded search index via proxy');
                }
            } catch (proxyError) {
                console.warn('Proxy endpoint failed:', proxyError);
            }
            
            // If proxy fails, try direct access
            if (!searchData) {
                console.log(`Trying direct access: ${this.mkdocsUrl}/search/search_index.json`);
                const response = await fetch(`${this.mkdocsUrl}/search/search_index.json`);
                if (!response.ok) {
                    throw new Error(`Failed to load search index: ${response.status}`);
                }
                searchData = await response.json();
                console.log('Successfully loaded search index directly');
            }
            
            // Build the Lunr index
            this.searchIndex = this.lunr(function() {
                this.ref('location');
                this.field('title', { boost: 10 });
                this.field('text');
                
                searchData.docs.forEach(doc => {
                    this.add(doc);
                });
            });
            
            this.searchDocs = searchData.docs;
            this.initialized = true;
            console.log('MkDocs search initialized with', this.searchDocs.length, 'documents');
            return true;
        } catch (error) {
            console.error('Failed to initialize MkDocs search:', error);
            this.initialized = false;
            return false;
        }
    }

    async loadLunr() {
        if (window.lunr) {
            this.lunr = window.lunr;
            return;
        }

        // Load Lunr.js from CDN
        return new Promise((resolve, reject) => {
            const script = document.createElement('script');
            script.src = 'https://unpkg.com/lunr@2.3.9/lunr.min.js';
            script.onload = () => {
                this.lunr = window.lunr;
                resolve();
            };
            script.onerror = reject;
            document.head.appendChild(script);
        });
    }

    search(query) {
        if (!this.initialized) {
            console.warn('Search not initialized');
            return [];
        }
        
        if (!this.searchIndex || !query || query.length < this.minSearchLength) {
            return [];
        }

        try {
            // Perform the search
            const results = this.searchIndex.search(query);
            
            // Map results to include document data
            return results.slice(0, 10).map(result => {
                const doc = this.searchDocs.find(d => d.location === result.ref);
                if (!doc) return null;

                // Extract a snippet around the matched text
                const snippet = this.extractSnippet(doc.text, query);
                
                return {
                    ...doc,
                    score: result.score,
                    url: `${this.mkdocsUrl}/${doc.location}`,
                    snippet: snippet
                };
            }).filter(Boolean);
        } catch (error) {
            console.error('Search error:', error);
            return [];
        }
    }

    extractSnippet(text, query, maxLength = 150) {
        const lowerText = text.toLowerCase();
        const lowerQuery = query.toLowerCase();
        const index = lowerText.indexOf(lowerQuery);
        
        if (index === -1) {
            return text.substring(0, maxLength) + '...';
        }

        const start = Math.max(0, index - 50);
        const end = Math.min(text.length, index + query.length + 100);
        let snippet = text.substring(start, end);
        
        if (start > 0) snippet = '...' + snippet;
        if (end < text.length) snippet = snippet + '...';
        
        // Highlight the search term
        const regex = new RegExp(`(${query})`, 'gi');
        snippet = snippet.replace(regex, '<mark>$1</mark>');
        
        return snippet;
    }

    bindToInput(inputElement, resultsElement) {
        const resultsContainer = resultsElement.querySelector('.docs-search-results-list');
        const resultsCount = resultsElement.querySelector('.results-count');
        const closeBtn = resultsElement.querySelector('.close-results');
        
        // Handle input with debouncing
        inputElement.addEventListener('input', (e) => {
            clearTimeout(this.debounceTimeout);
            this.debounceTimeout = setTimeout(() => {
                this.performSearch(e.target.value, resultsContainer, resultsCount, resultsElement);
            }, 300);
        });

        // Handle keyboard shortcuts
        inputElement.addEventListener('keydown', (e) => {
            if (e.key === 'Escape') {
                this.closeResults(inputElement, resultsElement);
            }
        });

        // Global keyboard shortcut (Ctrl+K or Cmd+K)
        document.addEventListener('keydown', (e) => {
            if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
                e.preventDefault();
                inputElement.focus();
                inputElement.select();
            }
        });

        // Close button
        closeBtn.addEventListener('click', () => {
            this.closeResults(inputElement, resultsElement);
        });

        // Click outside to close
        document.addEventListener('click', (e) => {
            if (!inputElement.contains(e.target) && !resultsElement.contains(e.target)) {
                resultsElement.classList.add('hidden');
            }
        });
    }

    performSearch(query, resultsContainer, resultsCount, resultsElement) {
        if (!query || query.length < this.minSearchLength) {
            resultsElement.classList.add('hidden');
            return;
        }

        const results = this.search(query);
        
        if (results.length === 0) {
            resultsContainer.innerHTML = '<div class="no-results">No results found</div>';
            resultsCount.textContent = 'No results';
        } else {
            resultsCount.textContent = `${results.length} result${results.length > 1 ? 's' : ''}`;
            resultsContainer.innerHTML = results.map((result, index) => `
                <div class="search-result-item">
                    <a href="${result.url}" class="search-result" target="_blank" rel="noopener">
                        <div class="search-result-title">${this.escapeHtml(result.title)}</div>
                        <div class="search-result-snippet">${result.snippet}</div>
                        <div class="search-result-path">${result.location}</div>
                    </a>
                    <button class="btn btn-sm btn-secondary make-qr-btn" data-url="${result.url}" data-index="${index}">
                        <span class="btn-icon">📱</span>
                        <span class="btn-text">Make QR</span>
                    </button>
                </div>
            `).join('');
            
            // Add event listeners to QR buttons
            this.attachQRButtonListeners();
        }
        
        resultsElement.classList.remove('hidden');
    }

    // Add new method to handle QR button clicks
    attachQRButtonListeners() {
        const qrButtons = document.querySelectorAll('.make-qr-btn');
        qrButtons.forEach(button => {
            button.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();
                const url = button.getAttribute('data-url');
                this.showQRCodeModal(url);
            });
        });
    }

    // Add method to show QR code modal
    showQRCodeModal(url) {
        // Create or get existing QR modal
        let modal = document.getElementById('qr-code-modal');
        if (!modal) {
            modal = this.createQRModal();
            document.body.appendChild(modal);
        }
        // Ensure modal has correct z-index and class
        modal.classList.add('qr-modal');
        modal.style.zIndex = '11000'; // Force above all overlays

        // Update modal content
        const qrImage = modal.querySelector('.qr-code-image');
        const qrUrl = modal.querySelector('.qr-code-url');
        const qrLoading = modal.querySelector('.qr-loading');
        
        // Show modal and loading state
        modal.classList.remove('hidden');
        qrLoading.style.display = 'block';
        qrImage.style.display = 'none';
        
        // Update URL display
        qrUrl.textContent = url;
        qrUrl.href = url;
        
        // Generate QR code
        const qrApiUrl = `/api/qr?text=${encodeURIComponent(url)}&size=256`;
        qrImage.src = qrApiUrl;
        
        qrImage.onload = () => {
            qrLoading.style.display = 'none';
            qrImage.style.display = 'block';
        };
        
        qrImage.onerror = () => {
            qrLoading.innerHTML = '<p style="color: var(--danger-color);">Failed to generate QR code</p>';
        };
    }

    // Add method to create QR modal
    createQRModal() {
        const modal = document.createElement('div');
        modal.id = 'qr-code-modal';
        modal.className = 'modal qr-modal'; // Ensure both classes for styling
        modal.innerHTML = `
            <div class="modal-content qr-modal-content">
                <div class="modal-header">
                    <h2>QR Code</h2>
                    <button class="modal-close" id="close-qr-modal">&times;</button>
                </div>
                <div class="modal-body qr-modal-body">
                    <div class="qr-loading">
                        <div class="spinner"></div>
                        <p>Generating QR code...</p>
                    </div>
                    <img class="qr-code-image" alt="QR Code" style="display: none;">
                    <div class="qr-code-info">
                        <p>Scan this QR code to open:</p>
                        <a class="qr-code-url" target="_blank" rel="noopener"></a>
                    </div>
                </div>
            </div>
        `;
        
        // Add close functionality
        const closeBtn = modal.querySelector('#close-qr-modal');
        closeBtn.addEventListener('click', () => {
            modal.classList.add('hidden');
        });
        
        // Close on background click
        modal.addEventListener('click', (e) => {
            if (e.target === modal) {
                modal.classList.add('hidden');
            }
        });
        
        // Close on Escape key
        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape' && !modal.classList.contains('hidden')) {
                modal.classList.add('hidden');
            }
        });
        
        return modal;
    }

    closeResults(inputElement, resultsElement) {
        resultsElement.classList.add('hidden');
        inputElement.value = '';
        inputElement.blur();
    }

    escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }
}