package api

import (
	"context"
	"encoding/json"
	"io"
	"log/slog"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

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

	"git.fabledsword.com/bvandeusen/minstrel/internal/auth"
	"git.fabledsword.com/bvandeusen/minstrel/internal/config"
	"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
	"git.fabledsword.com/bvandeusen/minstrel/internal/eventbus"
	"git.fabledsword.com/bvandeusen/minstrel/internal/playevents"
)

// newLibraryRouter builds a test-only chi router with the library handlers
// mounted at their path-style routes. Tests hit this router rather than
// calling handler methods directly so chi URL params populate correctly.
// RequireUser is NOT applied to most routes — library handlers don't read
// user context.
//
// The stream route is wrapped with a synthetic-user middleware because
// handleGetStream now enforces its own auth check (streamAuthOk) after the
// UPnP slice moved it out of the authed.Group. Real traffic carries either
// a session cookie (resolved by auth.OptionalUser) or a signed query
// token; tests get a fake user-in-context so the cookie path of
// streamAuthOk succeeds without seeding a real session row.
func newLibraryRouter(h *handlers) chi.Router {
	r := chi.NewRouter()
	r.Get("/api/artists", h.handleListArtists)
	r.Get("/api/artists/{id}", h.handleGetArtist)
	r.Get("/api/albums/{id}", h.handleGetAlbum)
	r.Get("/api/albums/{id}/cover", h.handleGetCover)
	r.Get("/api/tracks/{id}", h.handleGetTrack)
	r.With(injectFakeUserForTest).Get("/api/tracks/{id}/stream", h.handleGetStream)
	r.Get("/api/search", h.handleSearch)
	return r
}

// injectFakeUserForTest attaches an empty dbq.User to request context via
// auth.UserCtxKeyForTest(), letting handleGetStream's streamAuthOk succeed
// on the session path without the test having to seed a real session row.
// Production traffic uses auth.OptionalUser instead; this is the test-only
// equivalent that bypasses the DB lookup.
func injectFakeUserForTest(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := context.WithValue(r.Context(), auth.UserCtxKeyForTest(), dbq.User{})
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func TestHandleGetTrack_HappyPath(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	artist := seedArtist(t, pool, "Beatles")
	album := seedAlbum(t, pool, artist.ID, "Abbey Road", 1969)
	track := seedTrack(t, pool, album.ID, artist.ID, "Something", 3, 183_000)

	req := httptest.NewRequest(http.MethodGet, "/api/tracks/"+uuidToString(track.ID), 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 TrackRef
	if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
		t.Fatalf("decode: %v body=%s", err, w.Body.String())
	}
	if got.Title != "Something" || got.AlbumTitle != "Abbey Road" || got.ArtistName != "Beatles" {
		t.Errorf("ref = %+v", got)
	}
	if got.TrackNumber != 3 || got.DurationSec != 183 {
		t.Errorf("positions = %+v", got)
	}
	want := "/api/tracks/" + uuidToString(track.ID) + "/stream"
	if got.StreamURL != want {
		t.Errorf("stream_url = %q, want %q", got.StreamURL, want)
	}
}

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

func TestHandleGetTrack_NotFound(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	req := httptest.NewRequest(http.MethodGet,
		"/api/tracks/00000000-0000-0000-0000-000000000001", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)
	if w.Code != http.StatusNotFound {
		t.Errorf("status = %d, want 404", w.Code)
	}
}

func TestHandleGetAlbum_HappyPath(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	artist := seedArtist(t, pool, "Beatles")
	album := seedAlbum(t, pool, artist.ID, "Abbey Road", 1969)
	seedTrack(t, pool, album.ID, artist.ID, "Come Together", 1, 259_000)
	seedTrack(t, pool, album.ID, artist.ID, "Something", 2, 183_000)

	req := httptest.NewRequest(http.MethodGet, "/api/albums/"+uuidToString(album.ID), 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 AlbumDetail
	if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
		t.Fatalf("decode: %v body=%s", err, w.Body.String())
	}
	if got.Title != "Abbey Road" || got.ArtistName != "Beatles" || got.Year != 1969 {
		t.Errorf("album = %+v", got)
	}
	if len(got.Tracks) != 2 {
		t.Fatalf("tracks len = %d, want 2", len(got.Tracks))
	}
	if got.Tracks[0].Title != "Come Together" || got.Tracks[1].Title != "Something" {
		t.Errorf("tracks = %+v", got.Tracks)
	}
	if got.TrackCount != 2 || got.DurationSec != 442 { // 259 + 183
		t.Errorf("counts = track=%d duration=%d", got.TrackCount, got.DurationSec)
	}
	want := "/api/albums/" + uuidToString(album.ID) + "/cover"
	if got.CoverURL != want {
		t.Errorf("cover_url = %q", got.CoverURL)
	}
	// StreamURL on nested tracks must be set
	if got.Tracks[0].StreamURL == "" {
		t.Error("nested track missing stream_url")
	}
}

func TestHandleGetAlbum_NoTracks(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	artist := seedArtist(t, pool, "Beatles")
	album := seedAlbum(t, pool, artist.ID, "Empty", 0)

	req := httptest.NewRequest(http.MethodGet, "/api/albums/"+uuidToString(album.ID), 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 AlbumDetail
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if got.Tracks == nil {
		t.Error("tracks = nil, want [] for JSON encoding")
	}
	if len(got.Tracks) != 0 {
		t.Errorf("tracks len = %d, want 0", len(got.Tracks))
	}
	// Year omitempty: releaseYear=0 => Year=0 => field should be absent from JSON
	if got.Year != 0 {
		t.Errorf("year = %d, want 0", got.Year)
	}
}

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

func TestHandleGetAlbum_NotFound(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	req := httptest.NewRequest(http.MethodGet,
		"/api/albums/00000000-0000-0000-0000-000000000001", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)
	if w.Code != http.StatusNotFound {
		t.Errorf("status = %d, want 404", w.Code)
	}
}

func TestHandleGetArtist_HappyPath(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	artist := seedArtist(t, pool, "Beatles")
	album1 := seedAlbum(t, pool, artist.ID, "Abbey Road", 1969)
	album2 := seedAlbum(t, pool, artist.ID, "Let It Be", 1970)
	seedTrack(t, pool, album1.ID, artist.ID, "Something", 3, 183_000)
	seedTrack(t, pool, album2.ID, artist.ID, "Get Back", 1, 189_000)

	req := httptest.NewRequest(http.MethodGet, "/api/artists/"+uuidToString(artist.ID), 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 ArtistDetail
	if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
		t.Fatalf("decode: %v body=%s", err, w.Body.String())
	}
	if got.Name != "Beatles" {
		t.Errorf("name = %q", got.Name)
	}
	if got.AlbumCount != 2 {
		t.Errorf("album_count = %d, want 2", got.AlbumCount)
	}
	if len(got.Albums) != 2 {
		t.Fatalf("albums len = %d, want 2", len(got.Albums))
	}
	// ListAlbumsByArtist orders by release_date then sort_title; Abbey Road (1969) first.
	if got.Albums[0].Title != "Abbey Road" {
		t.Errorf("first album = %q, want Abbey Road", got.Albums[0].Title)
	}
	for _, a := range got.Albums {
		if a.ArtistName != "Beatles" {
			t.Errorf("album.artist_name = %q", a.ArtistName)
		}
		if a.CoverURL == "" {
			t.Error("album missing cover_url")
		}
		if a.TrackCount != 1 {
			t.Errorf("album.track_count = %d, want 1", a.TrackCount)
		}
	}
}

func TestHandleGetArtist_NoAlbums(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	artist := seedArtist(t, pool, "Solo")

	req := httptest.NewRequest(http.MethodGet, "/api/artists/"+uuidToString(artist.ID), nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	var got ArtistDetail
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if got.Albums == nil {
		t.Error("albums = nil, want []")
	}
	if got.AlbumCount != 0 {
		t.Errorf("album_count = %d, want 0", got.AlbumCount)
	}
}

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

func TestHandleGetArtist_NotFound(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	req := httptest.NewRequest(http.MethodGet,
		"/api/artists/00000000-0000-0000-0000-000000000001", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)
	if w.Code != http.StatusNotFound {
		t.Errorf("status = %d, want 404", w.Code)
	}
}

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

	req := httptest.NewRequest(http.MethodGet, "/api/artists", 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 Page[ArtistRef]
	if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
		t.Fatalf("decode: %v", err)
	}
	if got.Total != 3 {
		t.Errorf("total = %d, want 3", got.Total)
	}
	if got.Limit != 50 || got.Offset != 0 {
		t.Errorf("pagination defaults = limit=%d offset=%d, want 50/0", got.Limit, got.Offset)
	}
	if len(got.Items) != 3 {
		t.Fatalf("items len = %d", len(got.Items))
	}
	if got.Items[0].Name != "ABBA" || got.Items[2].Name != "Zeppelin" {
		t.Errorf("alpha order wrong: %q, %q, %q", got.Items[0].Name, got.Items[1].Name, got.Items[2].Name)
	}
}

func TestHandleListArtists_SortNewest(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	// Seeded in this order; created_at DESC means Third first.
	seedArtist(t, pool, "First")
	seedArtist(t, pool, "Second")
	seedArtist(t, pool, "Third")

	req := httptest.NewRequest(http.MethodGet, "/api/artists?sort=newest", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	var got Page[ArtistRef]
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if len(got.Items) != 3 {
		t.Fatalf("items len = %d", len(got.Items))
	}
	if got.Items[0].Name != "Third" || got.Items[2].Name != "First" {
		t.Errorf("newest order wrong: %q, %q, %q", got.Items[0].Name, got.Items[1].Name, got.Items[2].Name)
	}
}

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

	req := httptest.NewRequest(http.MethodGet, "/api/artists?sort=garbage", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)

	if w.Code != http.StatusBadRequest {
		t.Errorf("status = %d, want 400", w.Code)
	}
}

func TestHandleListArtists_Pagination(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	for _, n := range []string{"A", "B", "C", "D", "E"} {
		seedArtist(t, pool, n)
	}

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

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	var got Page[ArtistRef]
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if got.Total != 5 {
		t.Errorf("total = %d, want 5", got.Total)
	}
	if got.Limit != 2 || got.Offset != 2 {
		t.Errorf("page = limit=%d offset=%d", got.Limit, got.Offset)
	}
	if len(got.Items) != 2 {
		t.Fatalf("items len = %d", len(got.Items))
	}
	if got.Items[0].Name != "C" || got.Items[1].Name != "D" {
		t.Errorf("slice = %q, %q", got.Items[0].Name, got.Items[1].Name)
	}
}

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

	req := httptest.NewRequest(http.MethodGet, "/api/artists?limit=9999", nil)
	w := httptest.NewRecorder()
	newLibraryRouter(h).ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	var got Page[ArtistRef]
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if got.Limit != 200 {
		t.Errorf("limit = %d, want 200 (max clamp)", got.Limit)
	}
}

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

func TestHandleListArtists_AlbumCount(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)
	artist := seedArtist(t, pool, "A")
	seedAlbum(t, pool, artist.ID, "X", 0)
	seedAlbum(t, pool, artist.ID, "Y", 0)

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

	var got Page[ArtistRef]
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if len(got.Items) != 1 || got.Items[0].AlbumCount != 2 {
		t.Errorf("items = %+v", got.Items)
	}
}

func TestHandleListArtists_EmptyDB(t *testing.T) {
	h, pool := testHandlers(t)
	truncateLibrary(t, pool)

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

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	var got Page[ArtistRef]
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if got.Items == nil {
		t.Error("items = nil, want []")
	}
	if got.Total != 0 {
		t.Errorf("total = %d", got.Total)
	}
}

// TestRoutesRegisteredInMount verifies the production Mount() wires every
// library route. We hit each path through the real Mount (no RequireUser
// stripped — we expect 401 from the middleware, which is fine — that
// proves the route reached the authenticated group).
func TestRoutesRegisteredInMount(t *testing.T) {
	h, _ := testHandlers(t)
	r := chi.NewRouter()
	w := playevents.NewWriter(h.pool, slog.New(slog.NewTextHandler(io.Discard, nil)),
		30*time.Minute, 0.5, 30000)
	Mount(r, h.pool, h.logger, w, config.RecommendationConfig{RadioSize: 50, RadioSizeMax: 200, RecentlyPlayedHours: 1}, h.recSettings, h.lidarrCfg, h.lidarrRequests, h.lidarrQuarantine, h.tracks, h.playlists, h.coverart, h.coverSettings, h.tagSettings, h.scanner, h.scanCfg, h.dataDir, nil, eventbus.New(), nil, nil, h.netSettings)

	paths := []string{
		"/api/artists",
		"/api/artists/00000000-0000-0000-0000-000000000001",
		"/api/albums/00000000-0000-0000-0000-000000000001",
		"/api/albums/00000000-0000-0000-0000-000000000001/cover",
		"/api/tracks/00000000-0000-0000-0000-000000000001",
		"/api/tracks/00000000-0000-0000-0000-000000000001/stream",
		"/api/search?q=x",
		// Browse indexes (#367).
		"/api/library/genres",
		"/api/library/years",
	}
	for _, p := range paths {
		req := httptest.NewRequest(http.MethodGet, p, nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)
		// Unauthenticated → 401. What we must NOT see is 404 (route missing).
		if w.Code == http.StatusNotFound {
			t.Errorf("path %s returned 404 — route not registered", p)
		}
		if w.Code != http.StatusUnauthorized {
			t.Errorf("path %s status = %d, want 401 (unauth)", p, w.Code)
		}
	}
}

func TestGetArtistTracks_HappyPath(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: "ArtistA", SortName: "ArtistA",
	})
	album, _ := q.UpsertAlbum(context.Background(), dbq.UpsertAlbumParams{
		Title: "AlbumA", SortTitle: "AlbumA", ArtistID: artist.ID,
	})
	_, _ = q.UpsertTrack(context.Background(), dbq.UpsertTrackParams{
		Title: "T1", AlbumID: album.ID, ArtistID: artist.ID,
		DurationMs: 1000, FilePath: "/tmp/m6a-T1.mp3",
		FileSize: 1, FileFormat: "mp3",
	})
	_, _ = q.UpsertTrack(context.Background(), dbq.UpsertTrackParams{
		Title: "T2", AlbumID: album.ID, ArtistID: artist.ID,
		DurationMs: 1000, FilePath: "/tmp/m6a-T2.mp3",
		FileSize: 1, FileFormat: "mp3",
	})

	r := chi.NewRouter()
	r.Get("/api/artists/{id}/tracks", h.handleGetArtistTracks)
	req := httptest.NewRequest(http.MethodGet, "/api/artists/"+uuidToString(artist.ID)+"/tracks", nil)
	req = withUser(req, user)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d, body = %s", w.Code, w.Body.String())
	}
	var got []TrackRef
	if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
		t.Fatalf("decode: %v", err)
	}
	if len(got) != 2 {
		t.Fatalf("len = %d, want 2", len(got))
	}
	if got[0].ArtistName != "ArtistA" || got[0].AlbumTitle != "AlbumA" {
		t.Errorf("got = %+v", got[0])
	}
}

func TestGetArtistTracks_HonorsQuarantine(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: "ArtistB", SortName: "ArtistB",
	})
	album, _ := q.UpsertAlbum(context.Background(), dbq.UpsertAlbumParams{
		Title: "AlbumB", SortTitle: "AlbumB", ArtistID: artist.ID,
	})
	track, _ := q.UpsertTrack(context.Background(), dbq.UpsertTrackParams{
		Title: "Q", AlbumID: album.ID, ArtistID: artist.ID,
		DurationMs: 1000, FilePath: "/tmp/m6a-Q.mp3",
		FileSize: 1, FileFormat: "mp3",
	})
	if _, err := pool.Exec(context.Background(),
		`INSERT INTO lidarr_quarantine (user_id, track_id, reason) VALUES ($1, $2, 'bad_rip')`,
		user.ID, track.ID,
	); err != nil {
		t.Fatalf("quarantine insert: %v", err)
	}

	r := chi.NewRouter()
	r.Get("/api/artists/{id}/tracks", h.handleGetArtistTracks)
	req := httptest.NewRequest(http.MethodGet, "/api/artists/"+uuidToString(artist.ID)+"/tracks", nil)
	req = withUser(req, user)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d", w.Code)
	}
	var got []TrackRef
	_ = json.Unmarshal(w.Body.Bytes(), &got)
	if len(got) != 0 {
		t.Errorf("len = %d, want 0 (quarantined)", len(got))
	}
}

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

	r := chi.NewRouter()
	r.Get("/api/artists/{id}/tracks", h.handleGetArtistTracks)
	// Random UUID — no such artist exists.
	req := httptest.NewRequest(http.MethodGet, "/api/artists/00000000-0000-0000-0000-000000000000/tracks", nil)
	req = withUser(req, user)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	if w.Code != http.StatusNotFound {
		t.Errorf("status = %d, want 404", w.Code)
	}
	_ = pool
}
