/**
 * Database Search Module
 * Handles location search functionality through loaded map data
 */

import { map } from './map-manager.js';
import { markers } from './location-manager.js';
import { openEditForm } from './location-manager.js';

export class DatabaseSearch {
    constructor() {
        this.searchCache = new Map();
    }

    /**
     * Search through loaded locations
     * @param {string} query - The search query
     * @returns {Promise<Array>} Array of search results
     */
    async search(query) {
        if (!query || query.trim().length < 2) {
            return [];
        }

        const trimmedQuery = query.trim().toLowerCase();
        
        // Check cache first
        if (this.searchCache.has(trimmedQuery)) {
            return this.searchCache.get(trimmedQuery);
        }

        try {
            // Get all locations from loaded markers
            const locations = this.getLoadedLocations();
            
            // Filter locations based on search query
            const results = locations.filter(location => {
                return this.matchesQuery(location, trimmedQuery);
            }).map(location => {
                return this.formatResult(location, trimmedQuery);
            }).slice(0, 10); // Limit to 10 results

            // Cache the results
            this.searchCache.set(trimmedQuery, results);
            
            // Clean up cache if it gets too large
            if (this.searchCache.size > 50) {
                const firstKey = this.searchCache.keys().next().value;
                this.searchCache.delete(firstKey);
            }

            return results;

        } catch (error) {
            console.error('Database search error:', error);
            throw error;
        }
    }

    /**
     * Get all loaded location data from markers
     * @returns {Array} Array of location objects
     */
    getLoadedLocations() {
        const locations = [];
        
        markers.forEach(marker => {
            if (marker._locationData) {
                locations.push(marker._locationData);
            }
        });

        return locations;
    }

    /**
     * Check if a location matches the search query
     * @param {Object} location - Location object
     * @param {string} query - Search query (lowercase)
     * @returns {boolean} Whether the location matches
     */
    matchesQuery(location, query) {
        const searchFields = [
            location['First Name'],
            location['Last Name'],
            location.Email,
            location.Phone,
            location.Address,
            location['Unit Number'],
            location.Notes
        ];

        // Combine first and last name
        const fullName = [location['First Name'], location['Last Name']]
            .filter(Boolean).join(' ').toLowerCase();

        return searchFields.some(field => {
            if (!field) return false;
            return String(field).toLowerCase().includes(query);
        }) || fullName.includes(query);
    }

    /**
     * Format a location for search results
     * @param {Object} location - Location object
     * @param {string} query - Search query for highlighting
     * @returns {Object} Formatted result
     */
    formatResult(location, query) {
        const name = [location['First Name'], location['Last Name']]
            .filter(Boolean).join(' ') || 'Unknown';
        
        const address = location.Address || 'No address';
        const email = location.Email || '';
        const phone = location.Phone || '';
        const unit = location['Unit Number'] || '';
        const supportLevel = location['Support Level'] || '';
        const notes = location.Notes || '';

        // Create a snippet with highlighted matches
        const snippet = this.createSnippet(location, query);

        return {
            id: location.Id || location.id || location.ID || location._id,
            name,
            address,
            email,
            phone,
            unit,
            supportLevel,
            notes,
            snippet,
            coordinates: {
                lat: parseFloat(location.latitude) || 0,
                lng: parseFloat(location.longitude) || 0
            },
            location: location // Keep full location data for actions
        };
    }

    /**
     * Create a text snippet with highlighted matches
     * @param {Object} location - Location object
     * @param {string} query - Search query
     * @returns {string} Snippet with highlights
     */
    createSnippet(location, query) {
        const searchableText = [
            location['First Name'],
            location['Last Name'],
            location.Email,
            location.Address,
            location['Unit Number'],
            location.Notes
        ].filter(Boolean).join(' • ');

        if (searchableText.length <= 100) {
            return this.highlightQuery(searchableText, query);
        }

        // Find the first occurrence of the query
        const lowerText = searchableText.toLowerCase();
        const index = lowerText.indexOf(query);
        
        if (index === -1) {
            // Return first 100 characters if no match
            return searchableText.substring(0, 100) + (searchableText.length > 100 ? '...' : '');
        }

        // Extract snippet around the match
        const start = Math.max(0, index - 30);
        const end = Math.min(searchableText.length, start + 100);
        
        let snippet = searchableText.substring(start, end);
        
        // Add ellipsis if needed
        if (start > 0) snippet = '...' + snippet;
        if (end < searchableText.length) snippet = snippet + '...';

        return this.highlightQuery(snippet, query);
    }

    /**
     * Highlight search query in text
     * @param {string} text - Text to highlight
     * @param {string} query - Query to highlight
     * @returns {string} Text with highlights
     */
    highlightQuery(text, query) {
        if (!query || !text) return text;
        
        const regex = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
        return text.replace(regex, '<mark>$1</mark>');
    }

    /**
     * Create HTML for a search result
     * @param {Object} result - Search result object
     * @returns {HTMLElement} Result element
     */
    createResultElement(result) {
        const resultEl = document.createElement('div');
        resultEl.className = 'search-result-item search-result-database';
        
        const supportLevelText = result.supportLevel ? `Level ${result.supportLevel}` : '';
        const unitText = result.unit ? `Unit ${result.unit}` : '';
        
        resultEl.innerHTML = `
            <div class="result-name">${this.escapeHtml(result.name)}</div>
            <div class="result-address">${this.escapeHtml(result.address)} ${this.escapeHtml(unitText)}</div>
            <div class="result-snippet">${result.snippet}</div>
            <div class="result-details">
                ${result.email ? `📧 ${this.escapeHtml(result.email)}` : ''}
                ${result.phone ? ` 📞 ${this.escapeHtml(result.phone)}` : ''}
                ${supportLevelText ? ` 🎯 ${supportLevelText}` : ''}
            </div>
        `;

        resultEl.addEventListener('click', () => {
            this.selectResult(result);
        });

        return resultEl;
    }

    /**
     * Handle selection of a search result
     * @param {Object} result - Selected result
     */
    selectResult(result) {
        if (!map) {
            console.error('Map not available');
            return;
        }

        const { lat, lng } = result.coordinates;

        if (isNaN(lat) || isNaN(lng)) {
            console.error('Invalid coordinates in result:', result);
            return;
        }

        // Pan and zoom to the location
        map.setView([lat, lng], 17);

        // Find and open the marker popup
        const marker = markers.find(m => {
            if (!m._locationData) return false;
            const markerId = m._locationData.Id || m._locationData.id || m._locationData.ID || m._locationData._id;
            return markerId == result.id;
        });

        if (marker) {
            // Open the popup
            marker.openPopup();
            
            // Optionally highlight the marker temporarily
            this.highlightMarker(marker);
        }
    }

    /**
     * Temporarily highlight a marker
     * @param {Object} marker - Leaflet marker
     */
    highlightMarker(marker) {
        if (!marker || !marker.setStyle) return;

        const originalStyle = {
            fillColor: marker.options.fillColor,
            color: marker.options.color,
            weight: marker.options.weight,
            radius: marker.options.radius
        };

        // Highlight style
        marker.setStyle({
            fillColor: '#FFD700',
            color: '#FF6B35',
            weight: 4,
            radius: 12
        });

        // Restore original style after 3 seconds
        setTimeout(() => {
            marker.setStyle(originalStyle);
        }, 3000);
    }

    /**
     * Escape HTML to prevent XSS
     * @param {string} text - Text to escape
     * @returns {string} Escaped text
     */
    escapeHtml(text) {
        if (!text) return '';
        const div = document.createElement('div');
        div.textContent = String(text);
        return div.innerHTML;
    }

    /**
     * Clear the search cache
     */
    clearCache() {
        this.searchCache.clear();
    }
}

// Create a global instance
window.databaseSearchInstance = new DatabaseSearch();

export default window.databaseSearchInstance;