package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"time"
)

var imageSearchEngines []SearchEngine

func init() {
	imageSearchEngines = []SearchEngine{
		{Name: "Qwant", Func: wrapImageSearchFunc(PerformQwantImageSearch), Weight: 1},
		{Name: "Bing", Func: wrapImageSearchFunc(PerformBingImageSearch), Weight: 2},
		{Name: "DeviantArt", Func: wrapImageSearchFunc(PerformDeviantArtImageSearch), Weight: 3},
		//{Name: "Imgur", Func: wrapImageSearchFunc(PerformImgurImageSearch), Weight: 4}, // Image proxy not working
	}
}

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

	cacheKey := CacheKey{Query: query, Page: page, Safe: settings.SafeSearch == "active", Lang: settings.Language, Type: "image"}
	combinedResults := getImageResultsFromCacheOrFetch(cacheKey, query, settings.SafeSearch, settings.Language, page)

	elapsedTime := time.Since(startTime)
	tmpl, err := template.New("images.html").Funcs(funcs).ParseFiles("templates/images.html")
	if err != nil {
		log.Printf("Error parsing template: %v", err)
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	data := struct {
		Results         []ImageSearchResult
		Query           string
		Page            int
		Fetched         string
		HasPrevPage     bool
		HasNextPage     bool
		NoResults       bool
		LanguageOptions []LanguageOption
		CurrentLang     string
		Theme           string
		Safe            string
		IsThemeDark     bool
	}{
		Results:         combinedResults,
		Query:           query,
		Page:            page,
		Fetched:         fmt.Sprintf("%.2f seconds", elapsedTime.Seconds()),
		HasPrevPage:     page > 1,
		HasNextPage:     len(combinedResults) >= 50,
		NoResults:       len(combinedResults) == 0,
		LanguageOptions: languageOptions,
		CurrentLang:     settings.Language,
		Theme:           settings.Theme,
		Safe:            settings.SafeSearch,
		IsThemeDark:     settings.IsThemeDark,
	}

	err = tmpl.Execute(w, data)
	if err != nil {
		printErr("Error executing template: %v", err)
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
	}
}

func getImageResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []ImageSearchResult {
	cacheChan := make(chan []SearchResult)
	var combinedResults []ImageSearchResult

	go func() {
		results, exists := resultsCache.Get(cacheKey)
		if exists {
			printInfo("Cache hit")
			cacheChan <- results
		} else {
			printInfo("Cache miss")
			cacheChan <- nil
		}
	}()

	select {
	case results := <-cacheChan:
		if results == nil {
			combinedResults = fetchImageResults(query, safe, lang, page)
			if len(combinedResults) > 0 {
				resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
			}
		} else {
			_, _, imageResults := convertToSpecificResults(results)
			combinedResults = imageResults
		}
	case <-time.After(2 * time.Second):
		printInfo("Cache check timeout")
		combinedResults = fetchImageResults(query, safe, lang, page)
		if len(combinedResults) > 0 {
			resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
		}
	}

	return combinedResults
}

func fetchImageResults(query, safe, lang string, page int) []ImageSearchResult {
	var results []ImageSearchResult

	for _, engine := range imageSearchEngines {
		printInfo("Using image search engine: %s", engine.Name)

		searchResults, duration, err := engine.Func(query, safe, lang, page)
		updateEngineMetrics(&engine, duration, err == nil)
		if err != nil {
			printWarn("Error performing image search with %s: %v", engine.Name, err)
			continue
		}

		for _, result := range searchResults {
			results = append(results, result.(ImageSearchResult))
		}

		// If results are found, break out of the loop
		if len(results) > 0 {
			break
		}
	}

	// If no results found after trying all engines
	if len(results) == 0 {
		printWarn("No image results found for query: %s, trying other nodes", query)
		results = tryOtherNodesForImageSearch(query, safe, lang, page, []string{hostID})
	}

	return results
}

func wrapImageSearchFunc(f func(string, string, string, int) ([]ImageSearchResult, time.Duration, error)) func(string, string, string, int) ([]SearchResult, time.Duration, error) {
	return func(query, safe, lang string, page int) ([]SearchResult, time.Duration, error) {
		imageResults, duration, err := f(query, safe, lang, page)
		if err != nil {
			return nil, duration, err
		}
		searchResults := make([]SearchResult, len(imageResults))
		for i, result := range imageResults {
			searchResults[i] = result
		}
		return searchResults, duration, nil
	}
}