package search

import (
	"context"
	"fmt"
	"log"
	"sync"
)

// SearchResult represents a single web search result.
type SearchResult struct {
	Title   string `json:"title"`
	URL     string `json:"url"`
	Snippet string `json:"snippet"`
}

// Provider is the interface for web search backends.
type Provider interface {
	// Search performs a web search and returns up to maxResults results.
	Search(ctx context.Context, query string, maxResults int) ([]SearchResult, error)

	// Name returns the provider identifier (e.g. "duckduckgo", "searxng").
	Name() string
}

// ── Provider Registry ───────────────────────

var (
	mu        sync.RWMutex
	providers = map[string]Provider{}
	active    string
)

// RegisterProvider adds a search provider to the registry.
func RegisterProvider(p Provider) {
	mu.Lock()
	defer mu.Unlock()
	providers[p.Name()] = p
	log.Printf("🔍 Registered search provider: %s", p.Name())
}

// SetActive sets the active search provider by name.
func SetActive(name string) error {
	mu.Lock()
	defer mu.Unlock()
	if _, ok := providers[name]; !ok {
		return fmt.Errorf("unknown search provider: %s", name)
	}
	active = name
	log.Printf("🔍 Active search provider: %s", name)
	return nil
}

// Active returns the currently active provider, or nil if none configured.
func Active() Provider {
	mu.RLock()
	defer mu.RUnlock()
	if active == "" {
		return nil
	}
	return providers[active]
}

// Available returns the names of all registered providers.
func Available() []string {
	mu.RLock()
	defer mu.RUnlock()
	names := make([]string, 0, len(providers))
	for name := range providers {
		names = append(names, name)
	}
	return names
}

// Config holds the persisted search configuration.
type Config struct {
	Provider   string `json:"provider"`    // "duckduckgo" or "searxng"
	Endpoint   string `json:"endpoint"`    // SearXNG endpoint URL
	APIKey     string `json:"api_key"`     // SearXNG API key (optional)
	MaxResults int    `json:"max_results"` // default results per search
}

// DefaultConfig returns the default search config (DuckDuckGo, no key needed).
func DefaultConfig() Config {
	return Config{Provider: "duckduckgo", MaxResults: 5}
}

// ApplyConfig applies a Config to the active provider registry.
// Called on startup and when admin saves settings.
func ApplyConfig(cfg Config) error {
	if cfg.Provider == "" {
		cfg.Provider = "duckduckgo"
	}

	// Configure SearXNG if selected
	mu.RLock()
	if sxng, ok := providers["searxng"].(*SearXNG); ok {
		sxng.Configure(cfg.Endpoint, cfg.APIKey)
	}
	mu.RUnlock()

	return SetActive(cfg.Provider)
}
