package api

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

func TestHandleSearch_ThreeFacets(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	artist := seedArtist(t, pool, "Beatles")
	album := seedAlbum(t, pool, artist.ID, "Beatles Greatest", 1982)
	seedTrack(t, pool, album.ID, artist.ID, "Beatles Jam", 1, 60_000)

	req := httptest.NewRequest(http.MethodGet, "/api/search?q=beatles", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d body = %s", w.Code, w.Body.String())
	}
	var got SearchResponse
	if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
		t.Fatalf("decode: %v", err)
	}
	if got.Artists.Total != 1 || len(got.Artists.Items) != 1 {
		t.Errorf("artists = %+v", got.Artists)
	}
	if got.Albums.Total != 1 || len(got.Albums.Items) != 1 {
		t.Errorf("albums = %+v", got.Albums)
	}
	if got.Tracks.Total != 1 || len(got.Tracks.Items) != 1 {
		t.Errorf("tracks = %+v", got.Tracks)
	}
	if got.Artists.Items[0].Name != "Beatles" {
		t.Errorf("artist name = %q", got.Artists.Items[0].Name)
	}
	if got.Albums.Items[0].ArtistName != "Beatles" {
		t.Errorf("album.artist_name = %q", got.Albums.Items[0].ArtistName)
	}
	if got.Tracks.Items[0].AlbumTitle != "Beatles Greatest" {
		t.Errorf("track.album_title = %q", got.Tracks.Items[0].AlbumTitle)
	}
}

func TestHandleSearch_NoMatches(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	seedArtist(t, pool, "Beatles")

	req := httptest.NewRequest(http.MethodGet, "/api/search?q=nothinghere", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	var got SearchResponse
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if got.Artists.Total != 0 || got.Albums.Total != 0 || got.Tracks.Total != 0 {
		t.Errorf("totals = %+v", got)
	}
	// All three item slices must JSON-encode as [] not null.
	if got.Artists.Items == nil || got.Albums.Items == nil || got.Tracks.Items == nil {
		t.Errorf("nil item slice: %+v", got)
	}
}

func TestHandleSearch_EmptyQuery(t *testing.T) {
	h, _ := testHandlers(t)
	req := httptest.NewRequest(http.MethodGet, "/api/search", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)
	if w.Code != http.StatusBadRequest {
		t.Errorf("status = %d, want 400", w.Code)
	}
}

func TestHandleSearch_BlankQuery(t *testing.T) {
	h, _ := testHandlers(t)
	req := httptest.NewRequest(http.MethodGet, "/api/search?q=%20%20", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)
	if w.Code != http.StatusBadRequest {
		t.Errorf("status = %d, want 400", w.Code)
	}
}

func TestHandleSearch_PagingAppliedPerFacet(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	// Create three matching artists so paging shows.
	a1 := seedArtist(t, pool, "Match One")
	a2 := seedArtist(t, pool, "Match Two")
	a3 := seedArtist(t, pool, "Match Three")
	_ = a1
	_ = a2
	_ = a3

	req := httptest.NewRequest(http.MethodGet, "/api/search?q=Match&limit=2&offset=1", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	var got SearchResponse
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if got.Artists.Total != 3 {
		t.Errorf("total = %d, want 3", got.Artists.Total)
	}
	if got.Artists.Limit != 2 || got.Artists.Offset != 1 {
		t.Errorf("page = limit=%d offset=%d", got.Artists.Limit, got.Artists.Offset)
	}
	if len(got.Artists.Items) != 2 {
		t.Errorf("items len = %d, want 2", len(got.Artists.Items))
	}
}
