package service

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestSemanticSearchService_Search(t *testing.T) {
	// Mock Ollama server
	ollamaServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/api/embeddings" {
			t.Errorf("expected /api/embeddings, got %s", r.URL.Path)
		}
		var req ollamaEmbedRequest
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			t.Fatalf("failed to decode request: %v", err)
		}
		if req.Model != "nomic-embed-text" {
			t.Errorf("expected model nomic-embed-text, got %s", req.Model)
		}
		if req.Prompt == "" {
			t.Error("expected non-empty prompt")
		}
		// Return a 768-dim embedding (truncated for test)
		embedding := make([]float64, 768)
		embedding[0] = 0.1
		embedding[1] = -0.2
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(ollamaEmbedResponse{Embedding: embedding})
	}))
	defer ollamaServer.Close()

	// Mock Qdrant server
	qdrantServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/collections/media/points/search" {
			t.Errorf("expected /collections/media/points/search, got %s", r.URL.Path)
		}
		var req qdrantSearchRequest
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			t.Fatalf("failed to decode request: %v", err)
		}
		if req.Limit != 5 {
			t.Errorf("expected limit 5, got %d", req.Limit)
		}
		if !req.WithPayload {
			t.Error("expected WithPayload=true")
		}
		payload, _ := json.Marshal(qdrantPayload{
			ID:        42,
			Title:     "Blade Runner 2049",
			MediaType: "movie",
			Year:      intPtr(2017),
			Overview:  "A young blade runner's discovery of a long-buried secret leads him to track down former blade runner Rick Deckard.",
		})
		resp := qdrantSearchResponse{
			Result: []qdrantHit{
				{ID: "42", Score: 0.8712, Payload: payload},
			},
		}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(resp)
	}))
	defer qdrantServer.Close()

	svc := NewSemanticSearchService(ollamaServer.URL, qdrantServer.URL)
	results, err := svc.Search(context.Background(), "sci-fi noir film", 5)
	if err != nil {
		t.Fatalf("Search failed: %v", err)
	}

	if len(results) != 1 {
		t.Fatalf("expected 1 result, got %d", len(results))
	}
	if results[0].ID != 42 {
		t.Errorf("expected ID 42, got %d", results[0].ID)
	}
	if results[0].Title != "Blade Runner 2049" {
		t.Errorf("expected title 'Blade Runner 2049', got %s", results[0].Title)
	}
	if results[0].MediaType != "movie" {
		t.Errorf("expected media_type 'movie', got %s", results[0].MediaType)
	}
	if results[0].Score != 0.8712 {
		t.Errorf("expected score 0.8712, got %f", results[0].Score)
	}
	if results[0].Year == nil || *results[0].Year != 2017 {
		t.Error("expected year 2017")
	}
}

// Note: empty query validation happens at the API handler level (search.go),
// not in the service. The service layer trusts its callers.
func TestSemanticSearchService_embed_emptyQuery(t *testing.T) {
	ollamaServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Empty string is passed through to Ollama — Ollama may return an error
		w.WriteHeader(http.StatusBadRequest)
	}))
	defer ollamaServer.Close()

	svc := NewSemanticSearchService(ollamaServer.URL, "http://localhost:6333")
	_, err := svc.embed(context.Background(), "")
	if err == nil {
		t.Error("expected error for empty query passed to Ollama")
	}
}

func TestSemanticSearchService_qdrantError(t *testing.T) {
	ollamaServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		embedding := make([]float64, 768)
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(ollamaEmbedResponse{Embedding: embedding})
	}))
	defer ollamaServer.Close()

	qdrantServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusServiceUnavailable)
	}))
	defer qdrantServer.Close()

	svc := NewSemanticSearchService(ollamaServer.URL, qdrantServer.URL)
	_, err := svc.Search(context.Background(), "test query", 5)
	if err == nil {
		t.Fatal("expected error when Qdrant is unavailable")
	}
}

func TestSemanticSearchService_ollamaError(t *testing.T) {
	ollamaServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusServiceUnavailable)
	}))
	defer ollamaServer.Close()

	svc := NewSemanticSearchService(ollamaServer.URL, "http://localhost:6333")
	_, err := svc.Search(context.Background(), "test query", 5)
	if err == nil {
		t.Fatal("expected error when Ollama is unavailable")
	}
}

func intPtr(i int) *int { return &i }
