package api

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

	"github.com/go-chi/chi/v5"

	"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
)

func newHomeRouter(h *handlers) chi.Router {
	r := chi.NewRouter()
	r.Get("/api/home", h.handleGetHome)
	return r
}

func doGetHome(h *handlers, user dbq.User) *httptest.ResponseRecorder {
	req := httptest.NewRequest(http.MethodGet, "/api/home", nil)
	req = withUser(req, user)
	w := httptest.NewRecorder()
	newHomeRouter(h).ServeHTTP(w, req)
	return w
}

func TestHome_EmptyForNewUser(t *testing.T) {
	h, pool := testHandlers(t)
	user := seedUser(t, pool, "alice", "pw", false)

	w := doGetHome(h, user)
	if w.Code != http.StatusOK {
		t.Fatalf("status = %d, want 200; body = %s", w.Code, w.Body.String())
	}
	var got HomePayload
	if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
		t.Fatalf("decode: %v", err)
	}
	// All slices must be non-nil so the SPA branches consistently on
	// length rather than dealing with null.
	if got.RecentlyAddedAlbums == nil || got.RediscoverAlbums == nil ||
		got.RediscoverArtists == nil || got.MostPlayedTracks == nil ||
		got.LastPlayedArtists == nil {
		t.Errorf("payload has nil slice: %+v", got)
	}
	if len(got.RecentlyAddedAlbums) != 0 {
		t.Errorf("RecentlyAddedAlbums len = %d, want 0", len(got.RecentlyAddedAlbums))
	}
}

func TestHome_RecentlyAddedSurfacesAlbums(t *testing.T) {
	h, pool := testHandlers(t)
	user := seedUser(t, pool, "alice", "pw", false)
	q := dbq.New(pool)
	artist, _ := q.UpsertArtist(context.Background(), dbq.UpsertArtistParams{
		Name: "ArtistOne", SortName: "ArtistOne",
	})
	_, _ = q.UpsertAlbum(context.Background(), dbq.UpsertAlbumParams{
		Title: "Newest", SortTitle: "Newest", ArtistID: artist.ID,
	})

	w := doGetHome(h, user)
	if w.Code != http.StatusOK {
		t.Fatalf("status = %d, body = %s", w.Code, w.Body.String())
	}
	var got HomePayload
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if len(got.RecentlyAddedAlbums) != 1 {
		t.Fatalf("len = %d, want 1", len(got.RecentlyAddedAlbums))
	}
	if got.RecentlyAddedAlbums[0].Title != "Newest" {
		t.Errorf("title = %q, want Newest", got.RecentlyAddedAlbums[0].Title)
	}
	if got.RecentlyAddedAlbums[0].ArtistName != "ArtistOne" {
		t.Errorf("artist_name = %q, want ArtistOne", got.RecentlyAddedAlbums[0].ArtistName)
	}
}

func newHomeIndexRouter(h *handlers) chi.Router {
	r := chi.NewRouter()
	r.Get("/api/home/index", h.handleGetHomeIndex)
	return r
}

func doGetHomeIndex(h *handlers, user dbq.User) *httptest.ResponseRecorder {
	req := httptest.NewRequest(http.MethodGet, "/api/home/index", nil)
	req = withUser(req, user)
	w := httptest.NewRecorder()
	newHomeIndexRouter(h).ServeHTTP(w, req)
	return w
}

func TestHomeIndex_EmptyForNewUser(t *testing.T) {
	h, pool := testHandlers(t)
	user := seedUser(t, pool, "alice", "pw", false)

	w := doGetHomeIndex(h, user)
	if w.Code != http.StatusOK {
		t.Fatalf("status = %d, want 200; body = %s", w.Code, w.Body.String())
	}
	var got HomeIndexPayload
	if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
		t.Fatalf("decode: %v", err)
	}
	// Same non-nil slice contract as /api/home so client parsers can
	// trust `length == 0` instead of branching on null.
	if got.RecentlyAddedAlbums == nil || got.RediscoverAlbums == nil ||
		got.RediscoverArtists == nil || got.MostPlayedTracks == nil ||
		got.LastPlayedArtists == nil {
		t.Errorf("payload has nil slice: %+v", got)
	}
	if len(got.RecentlyAddedAlbums) != 0 {
		t.Errorf("RecentlyAddedAlbums len = %d, want 0", len(got.RecentlyAddedAlbums))
	}
}

func TestHomeIndex_RecentlyAddedReturnsIDs(t *testing.T) {
	h, pool := testHandlers(t)
	user := seedUser(t, pool, "alice", "pw", false)
	q := dbq.New(pool)
	artist, _ := q.UpsertArtist(context.Background(), dbq.UpsertArtistParams{
		Name: "ArtistOne", SortName: "ArtistOne",
	})
	album, _ := q.UpsertAlbum(context.Background(), dbq.UpsertAlbumParams{
		Title: "Newest", SortTitle: "Newest", ArtistID: artist.ID,
	})

	w := doGetHomeIndex(h, user)
	if w.Code != http.StatusOK {
		t.Fatalf("status = %d, body = %s", w.Code, w.Body.String())
	}
	var got HomeIndexPayload
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if len(got.RecentlyAddedAlbums) != 1 {
		t.Fatalf("len = %d, want 1", len(got.RecentlyAddedAlbums))
	}
	want := uuidToString(album.ID)
	if got.RecentlyAddedAlbums[0] != want {
		t.Errorf("id = %q, want %q", got.RecentlyAddedAlbums[0], want)
	}
}
