import { getSemanticSearch } from "./semanticSearchService.js";
import { getDatabase } from "./database.js";
import { serverLogger } from "../utils/serverLogger.js";
export class WaveSemanticIntegration {
    semanticSearch = null;
    db = null;
    initialized = false;
    async ensureInitialized() {
        if (this.initialized) return;
        try {
            this.semanticSearch = getSemanticSearch();
            this.db = getDatabase();
            await this.db.waitForInitialization();
            this.initialized = true;
        } catch (error) {
            console.error("WaveSemanticIntegration: Failed to initialize:", error);
            throw error;
        }
    }
    /**
   * Enhanced search for WAVE that combines semantic and standard search
   */ async enhancedSearch(waveQuery) {
        await this.ensureInitialized();
        try {
            const { query, context, limit = 20 } = waveQuery;
            // Determine search strategy based on query type
            const searchStrategy = this.analyzeQuery(query);
            let tracks = [];
            let recommendations = [];
            let confidence = 0;
            let explanation = "";
            if (searchStrategy === "semantic") {
                // Use semantic search for descriptive queries
                const semanticResults = await this.semanticSearch.search(query, limit);
                tracks = semanticResults.map((r)=>r.track);
                confidence = semanticResults[0]?.score || 0;
                explanation = "Found tracks matching your description";
                // Get recommendations based on top result
                if (tracks.length > 0 && context?.currentTrack) {
                    const similar = await this.semanticSearch.findSimilar(context.currentTrack, 5);
                    recommendations = similar.map((r)=>r.track);
                }
            } else if (searchStrategy === "hybrid") {
                // Combine semantic and standard search
                const [semanticResults, standardResults] = await Promise.all([
                    this.semanticSearch.search(query, Math.floor(limit / 2)),
                    this.standardSearch(query, Math.floor(limit / 2))
                ]);
                // Merge and deduplicate results
                const trackMap = new Map();
                semanticResults.forEach((r)=>trackMap.set(r.track.path, r.track));
                standardResults.forEach((t)=>trackMap.set(t.path, t));
                tracks = Array.from(trackMap.values());
                confidence = 0.7;
                explanation = "Combined semantic and keyword search";
                // Context-aware recommendations
                if (context?.currentTrack) {
                    const similar = await this.semanticSearch.findSimilar(context.currentTrack, 5);
                    recommendations = similar.map((r)=>r.track);
                }
            } else {
                // Standard keyword search
                tracks = this.standardSearch(query, limit);
                confidence = 0.5;
                explanation = "Standard keyword search";
            }
            // Apply user preferences if provided
            if (context?.userPreferences) {
                tracks = this.applyUserPreferences(tracks, context.userPreferences);
            }
            // Add contextual recommendations based on recent listening
            if (context?.recentTracks && context.recentTracks.length > 0) {
                const contextualRecs = await this.getContextualRecommendations(context.recentTracks, 5);
                recommendations = [
                    ...recommendations,
                    ...contextualRecs
                ].slice(0, 10);
            }
            return {
                tracks,
                recommendations,
                context: {
                    searchType: searchStrategy,
                    confidence,
                    explanation
                }
            };
        } catch (error) {
            serverLogger.error("WAVE semantic search failed", {
                error
            });
            // Fallback to standard search
            return {
                tracks: this.standardSearch(waveQuery.query, waveQuery.limit || 20),
                recommendations: [],
                context: {
                    searchType: "standard",
                    confidence: 0.3,
                    explanation: "Fallback to standard search"
                }
            };
        }
    }
    /**
   * Analyze query to determine best search strategy
   */ analyzeQuery(query) {
        const semanticIndicators = [
            "like",
            "similar",
            "mood",
            "vibe",
            "feel",
            "energy",
            "chill",
            "upbeat",
            "relaxing",
            "party",
            "workout",
            "morning",
            "evening",
            "night",
            "summer",
            "winter",
            "happy",
            "sad",
            "nostalgic",
            "romantic",
            "aggressive"
        ];
        const hybridIndicators = [
            "genre",
            "style",
            "era",
            "decade",
            "year",
            "remix",
            "cover",
            "live",
            "acoustic",
            "instrumental"
        ];
        const queryLower = query.toLowerCase();
        // Check for semantic indicators
        const hasSemantic = semanticIndicators.some((ind)=>queryLower.includes(ind));
        if (hasSemantic) return "semantic";
        // Check for hybrid indicators
        const hasHybrid = hybridIndicators.some((ind)=>queryLower.includes(ind));
        if (hasHybrid) return "hybrid";
        // Check if query is descriptive (multiple words, not just artist/track name)
        const wordCount = query.split(/\s+/).length;
        if (wordCount >= 3 && !this.looksLikeTrackOrArtist(query)) {
            return "semantic";
        }
        return "standard";
    }
    /**
   * Check if query looks like a track or artist name
   */ looksLikeTrackOrArtist(query) {
        // Simple heuristic: if it's in quotes or has specific patterns
        if (query.includes('"') || query.includes("'")) return true;
        // Check if it matches known artists
        const artistsResult = this.db.getAllArtists(100, 0);
        const artists = Array.isArray(artistsResult) ? artistsResult : artistsResult.artists || [];
        const queryLower = query.toLowerCase();
        return artists.some((a)=>a.name.toLowerCase() === queryLower || queryLower.includes(a.name.toLowerCase()));
    }
    /**
   * Standard database search
   */ standardSearch(query, limit) {
        const result = this.db.searchTracks(query, limit, 0);
        return result.tracks;
    }
    /**
   * Apply user preferences to filter/sort results
   */ applyUserPreferences(tracks, preferences) {
        let filtered = [
            ...tracks
        ];
        // Filter by preferred genres
        if (preferences?.genres && preferences.genres.length > 0) {
            const preferredGenres = preferences.genres.map((g)=>g.toLowerCase());
            filtered = filtered.sort((a, b)=>{
                const aGenre = Array.isArray(a.genre) ? a.genre.join(" ").toLowerCase() : (a.genre || "").toString().toLowerCase();
                const bGenre = Array.isArray(b.genre) ? b.genre.join(" ").toLowerCase() : (b.genre || "").toString().toLowerCase();
                const aMatch = preferredGenres.some((g)=>aGenre.includes(g)) ? 1 : 0;
                const bMatch = preferredGenres.some((g)=>bGenre.includes(g)) ? 1 : 0;
                return bMatch - aMatch;
            });
        }
        // Boost preferred artists
        if (preferences?.artists && preferences.artists.length > 0) {
            const preferredArtists = preferences.artists.map((a)=>a.toLowerCase());
            filtered = filtered.sort((a, b)=>{
                const aMatch = a.artist && preferredArtists.includes(a.artist.toLowerCase()) ? 1 : 0;
                const bMatch = b.artist && preferredArtists.includes(b.artist.toLowerCase()) ? 1 : 0;
                return bMatch - aMatch;
            });
        }
        return filtered;
    }
    /**
   * Get recommendations based on recent listening history
   */ async getContextualRecommendations(recentTracks, limit) {
        const recommendations = new Map();
        // Get similar tracks for each recent track
        for (const trackPath of recentTracks.slice(0, 3)){
            try {
                const similar = await this.semanticSearch.findSimilar(trackPath, 3);
                similar.forEach((r)=>{
                    if (!recentTracks.includes(r.track.path)) {
                        recommendations.set(r.track.path, r.track);
                    }
                });
            } catch (error) {
            // Skip if track not found
            }
        }
        return Array.from(recommendations.values()).slice(0, limit);
    }
    /**
   * Get mood-based playlists for WAVE
   */ async getMoodPlaylist(mood, limit = 30) {
        await this.ensureInitialized();
        try {
            // Build mood-specific query
            const moodQueries = {
                energetic: "upbeat energetic party dance electronic",
                relaxing: "chill ambient relaxing calm peaceful",
                focus: "instrumental classical ambient minimal",
                workout: "pump energy aggressive metal rock electronic",
                romantic: "love romantic ballad soul r&b",
                happy: "happy upbeat positive cheerful pop",
                sad: "melancholic sad emotional ballad",
                nostalgic: "classic oldies retro throwback"
            };
            const query = moodQueries[mood.toLowerCase()] || mood;
            const results = await this.semanticSearch.search(query, limit);
            return results.map((r)=>r.track);
        } catch (error) {
            serverLogger.error("Failed to generate mood playlist", {
                error,
                mood
            });
            return [];
        }
    }
    /**
   * Get auto-complete suggestions for WAVE search
   */ async getWaveSearchSuggestions(partial) {
        await this.ensureInitialized();
        try {
            // Get suggestions from semantic search
            const suggestions = await this.semanticSearch.getSuggestions(partial, 10);
            // Add mood-based suggestions if applicable
            const moods = [
                "energetic",
                "relaxing",
                "focus",
                "workout",
                "romantic"
            ];
            const moodSuggestions = moods.filter((m)=>m.startsWith(partial.toLowerCase())).map((m)=>`Play ${m} music`);
            return [
                ...suggestions,
                ...moodSuggestions
            ].slice(0, 10);
        } catch (error) {
            serverLogger.error("Failed to get WAVE suggestions", {
                error
            });
            return [];
        }
    }
    /**
   * Build smart queue based on current track
   */ async buildSmartQueue(currentTrack, queueSize = 10, options) {
        try {
            const queue = [];
            const usedPaths = new Set([
                currentTrack
            ]);
            // Get similar tracks
            const similar = await this.semanticSearch.findSimilar(currentTrack, queueSize * 2);
            // Add tracks with diversity control
            for (const result of similar){
                if (queue.length >= queueSize) break;
                // Skip if already in queue
                if (usedPaths.has(result.track.path)) continue;
                // Apply diversity filter
                if (options?.diversity) {
                    const threshold = 1 - options.diversity;
                    if (result.score < threshold) continue;
                }
                // Filter by same artist if requested
                if (options?.includeArtist === false) {
                    const currentTrackData = this.db.getTrack(currentTrack);
                    if (currentTrackData?.artist === result.track.artist) continue;
                }
                queue.push(result.track);
                usedPaths.add(result.track.path);
            }
            // Fill remaining slots with mood-based tracks if needed
            if (queue.length < queueSize && options?.mood) {
                const moodTracks = await this.getMoodPlaylist(options.mood, queueSize - queue.length);
                for (const track of moodTracks){
                    if (!usedPaths.has(track.path)) {
                        queue.push(track);
                        usedPaths.add(track.path);
                        if (queue.length >= queueSize) break;
                    }
                }
            }
            return queue;
        } catch (error) {
            serverLogger.error("Failed to build smart queue", {
                error
            });
            return [];
        }
    }
}
// Export lazy singleton
let waveSemanticIntegrationInstance = null;
export function getWaveSemanticIntegration() {
    if (!waveSemanticIntegrationInstance) {
        waveSemanticIntegrationInstance = new WaveSemanticIntegration();
    }
    return waveSemanticIntegrationInstance;
}
export const waveSemanticIntegration = {
    get: getWaveSemanticIntegration
};

//# sourceMappingURL=waveSemanticIntegration.js.map