// music.go - Central music search handler
package main

import (
	"net/http"
	"sync"
	"time"
)

type MusicSearchEngine struct {
	Name string
	Func func(query string, page int) ([]MusicResult, error)
}

var (
	musicSearchEngines []MusicSearchEngine
	cacheMutex         = &sync.Mutex{}
)

var allMusicSearchEngines = []MusicSearchEngine{
	{Name: "SoundCloud", Func: SearchSoundCloud},
	{Name: "YouTube", Func: SearchMusicViaPiped},
	{Name: "Bandcamp", Func: SearchBandcamp},
	//{Name: "Spotify", Func: SearchSpotify},
}

func initMusicEngines() {
	// Initialize with all engines if no specific config
	musicSearchEngines = allMusicSearchEngines
}

func handleMusicSearch(w http.ResponseWriter, settings UserSettings, query string, page int) {
	start := time.Now()

	cacheKey := CacheKey{
		Query: query,
		Page:  page,
		Type:  "music",
		Lang:  settings.SearchLanguage,
		Safe:  settings.SafeSearch == "active",
	}

	var results []MusicResult

	if cached, found := resultsCache.Get(cacheKey); found {
		if musicResults, ok := convertCacheToMusicResults(cached); ok {
			results = musicResults
		}
	}

	if len(results) == 0 {
		results = fetchMusicResults(query, page)
		if len(results) > 0 {
			resultsCache.Set(cacheKey, convertMusicResultsToCache(results))
		}
	}

	go prefetchMusicPages(query, page)

	elapsed := time.Since(start) // Calculate duration

	data := map[string]interface{}{
		"Results":        results,
		"Query":          query,
		"Page":           page,
		"HasPrevPage":    page > 1,
		"HasNextPage":    len(results) >= 10, // Default page size
		"MusicServices":  getMusicServiceNames(),
		"CurrentService": "all", // Default service
		"Theme":          settings.Theme,
		"IsThemeDark":    settings.IsThemeDark,
		"Trans":          Translate,
		"Fetched":        FormatElapsedTime(elapsed),
	}

	renderTemplate(w, "music.html", data)
}

// Helper to get music service names
func getMusicServiceNames() []string {
	names := make([]string, len(allMusicSearchEngines))
	for i, engine := range allMusicSearchEngines {
		names[i] = engine.Name
	}
	return names
}

func convertMusicResultsToCache(results []MusicResult) []SearchResult {
	cacheResults := make([]SearchResult, len(results))
	for i, r := range results {
		cacheResults[i] = r
	}
	return cacheResults
}

func convertCacheToMusicResults(cached []SearchResult) ([]MusicResult, bool) {
	results := make([]MusicResult, 0, len(cached))
	for _, item := range cached {
		if musicResult, ok := item.(MusicResult); ok {
			results = append(results, musicResult)
		} else {
			return nil, false
		}
	}
	return results, true
}

func fetchMusicResults(query string, page int) []MusicResult {
	var results []MusicResult
	resultsChan := make(chan []MusicResult, len(musicSearchEngines))
	var wg sync.WaitGroup

	for _, engine := range musicSearchEngines {
		wg.Add(1)
		go func(e MusicSearchEngine) {
			defer wg.Done()
			res, err := e.Func(query, page)
			if err == nil && len(res) > 0 {
				resultsChan <- res
			}
		}(engine)
	}

	go func() {
		wg.Wait()
		close(resultsChan)
	}()

	for res := range resultsChan {
		results = append(results, res...)
		if len(results) >= 50 { // Default max results
			break
		}
	}

	return deduplicateResults(results)
}

func prefetchMusicPages(query string, currentPage int) {
	for _, page := range []int{currentPage - 1, currentPage + 1} {
		if page < 1 {
			continue
		}
		cacheKey := CacheKey{
			Query: query,
			Page:  page,
			Type:  "music",
		}
		if _, found := resultsCache.Get(cacheKey); !found {
			go fetchMusicResults(query, page)
		}
	}
}

func deduplicateResults(results []MusicResult) []MusicResult {
	seen := make(map[string]bool)
	var unique []MusicResult

	for _, res := range results {
		if !seen[res.URL] {
			seen[res.URL] = true
			unique = append(unique, res)
		}
	}
	return unique
}

// func generatePlayerHTML(result MusicResult) template.HTML {
// 	if result.IframeSrc != "" {
// 		return template.HTML(fmt.Sprintf(
// 			`<iframe width="100%%" height="166" scrolling="no" frameborder="no" src="%s"></iframe>`,
// 			result.IframeSrc,
// 		))
// 	}
// 	return template.HTML("")
// }