package api

import (
	"net/http"

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

// handleGetHome implements GET /api/home. Returns five sections in one
// payload; sections that have no rows render as []. 500 on any underlying
// DB failure — the SPA should render either empty states or full content,
// not a half-broken page.
func (h *handlers) handleGetHome(w http.ResponseWriter, r *http.Request) {
	user, ok := requireUser(w, r)
	if !ok {
		return
	}
	data, err := recommendation.HomeData(r.Context(), h.pool, user.ID)
	if err != nil {
		h.logger.Error("api: home data", "err", err)
		writeErr(w, apierror.InternalMsg("failed to load home", err))
		return
	}

	out := HomePayload{
		RecentlyAddedAlbums: make([]AlbumRef, 0, len(data.RecentlyAddedAlbums)),
		RediscoverAlbums:    make([]AlbumRef, 0, len(data.RediscoverAlbums)),
		RediscoverArtists:   make([]ArtistRef, 0, len(data.RediscoverArtists)),
		MostPlayedTracks:    make([]TrackRef, 0, len(data.MostPlayedTracks)),
		LastPlayedArtists:   make([]ArtistRef, 0, len(data.LastPlayedArtists)),
		YouMightLikeAlbums:  make([]AlbumRef, 0, len(data.YouMightLikeAlbums)),
		YouMightLikeArtists: make([]ArtistRef, 0, len(data.YouMightLikeArtists)),
	}
	for _, row := range data.RecentlyAddedAlbums {
		out.RecentlyAddedAlbums = append(out.RecentlyAddedAlbums, albumRefFrom(row.Album, row.ArtistName, 0, 0))
	}
	for _, row := range data.RediscoverAlbums {
		out.RediscoverAlbums = append(out.RediscoverAlbums, albumRefFrom(row.Album, row.ArtistName, 0, 0))
	}
	for _, row := range data.RediscoverArtists {
		out.RediscoverArtists = append(out.RediscoverArtists, artistRefFromCovered(row.Artist, int(row.AlbumCount), row.CoverAlbumID))
	}
	for _, row := range data.MostPlayedTracks {
		out.MostPlayedTracks = append(out.MostPlayedTracks, trackRefFrom(row.Track, row.AlbumTitle, row.ArtistName))
	}
	for _, row := range data.LastPlayedArtists {
		out.LastPlayedArtists = append(out.LastPlayedArtists, artistRefFromCovered(row.Artist, int(row.AlbumCount), row.CoverAlbumID))
	}
	for _, row := range data.YouMightLikeAlbums {
		out.YouMightLikeAlbums = append(out.YouMightLikeAlbums, albumRefFrom(row.Album, row.ArtistName, 0, 0))
	}
	for _, row := range data.YouMightLikeArtists {
		out.YouMightLikeArtists = append(out.YouMightLikeArtists, artistRefFromCovered(row.Artist, int(row.AlbumCount), row.CoverAlbumID))
	}
	writeJSON(w, http.StatusOK, out)
}

// handleGetHomeIndex implements GET /api/home/index. Returns the same
// five sections /api/home computes, but as flat slices of entity IDs
// rather than denormalized objects. Drives the Flutter per-item
// rendering path — the client hydrates each tile against the
// per-entity endpoints, so this response is tiny (a few KB at most)
// and the cold-visit round-trip is correspondingly short.
//
// Shares the recommendation.HomeData computation with /api/home; the
// DB cost is identical. A future optimisation could add ID-only
// query variants, but the JSON savings already shrink the wire
// payload by roughly an order of magnitude on populated libraries.
func (h *handlers) handleGetHomeIndex(w http.ResponseWriter, r *http.Request) {
	user, ok := requireUser(w, r)
	if !ok {
		return
	}
	data, err := recommendation.HomeData(r.Context(), h.pool, user.ID)
	if err != nil {
		h.logger.Error("api: home index data", "err", err)
		writeErr(w, apierror.InternalMsg("failed to load home", err))
		return
	}

	out := HomeIndexPayload{
		RecentlyAddedAlbums: make([]string, 0, len(data.RecentlyAddedAlbums)),
		RediscoverAlbums:    make([]string, 0, len(data.RediscoverAlbums)),
		RediscoverArtists:   make([]string, 0, len(data.RediscoverArtists)),
		MostPlayedTracks:    make([]string, 0, len(data.MostPlayedTracks)),
		LastPlayedArtists:   make([]string, 0, len(data.LastPlayedArtists)),
		YouMightLikeAlbums:  make([]string, 0, len(data.YouMightLikeAlbums)),
		YouMightLikeArtists: make([]string, 0, len(data.YouMightLikeArtists)),
	}
	for _, row := range data.RecentlyAddedAlbums {
		out.RecentlyAddedAlbums = append(out.RecentlyAddedAlbums, uuidToString(row.Album.ID))
	}
	for _, row := range data.RediscoverAlbums {
		out.RediscoverAlbums = append(out.RediscoverAlbums, uuidToString(row.Album.ID))
	}
	for _, row := range data.RediscoverArtists {
		out.RediscoverArtists = append(out.RediscoverArtists, uuidToString(row.Artist.ID))
	}
	for _, row := range data.MostPlayedTracks {
		out.MostPlayedTracks = append(out.MostPlayedTracks, uuidToString(row.Track.ID))
	}
	for _, row := range data.LastPlayedArtists {
		out.LastPlayedArtists = append(out.LastPlayedArtists, uuidToString(row.Artist.ID))
	}
	for _, row := range data.YouMightLikeAlbums {
		out.YouMightLikeAlbums = append(out.YouMightLikeAlbums, uuidToString(row.Album.ID))
	}
	for _, row := range data.YouMightLikeArtists {
		out.YouMightLikeArtists = append(out.YouMightLikeArtists, uuidToString(row.Artist.ID))
	}
	writeJSON(w, http.StatusOK, out)
}

// Compile-time guard that dbq has the row types we need; if the SQL is
// regenerated with a different name, this fails fast at build time.
var _ = dbq.ListMostPlayedTracksForUserRow{}.Track
