package api

import (
	"net/http"

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

// genreCount is one row of the genre browse index (#367).
//
// Genres are the tag's own strings, split on [;,] but otherwise untouched — no
// case folding and no synonym mapping. So "Rock" and "rock" can both appear,
// as can "Rock/Pop" alongside "Rock" and "Pop". That's deliberate for v1: the
// alternative is a normalisation table to invent and maintain, and the raw
// spread has to be visible before anyone can judge whether it's a problem.
//
// The first look at that spread found it dominated by welded tokens like
// "Alternative RockRock" — the scanner's own bug, not the operator's tagging
// (#2499). Judge the "is a taxonomy needed" question (#2468) only against a
// library re-scanned since that fix.
type genreCount struct {
	Genre      string `json:"genre"`
	TrackCount int    `json:"track_count"`
}

// yearCount is one row of the year browse index.
type yearCount struct {
	Year       int `json:"year"`
	AlbumCount int `json:"album_count"`
}

// handleListGenres implements GET /api/library/genres.
//
// Unpaged on purpose. Even a messy library yields hundreds of distinct tag
// strings, not thousands, and the client needs the whole set at once to render
// a browsable index — paging it would mean the UI could only ever show a
// prefix of an ordering the user didn't choose.
func (h *handlers) handleListGenres(w http.ResponseWriter, r *http.Request) {
	rows, err := dbq.New(h.pool).ListGenresWithCount(r.Context())
	if err != nil {
		h.logger.Error("api: list genres", "err", err)
		writeErr(w, apierror.InternalMsg("lookup failed", err))
		return
	}
	out := make([]genreCount, 0, len(rows))
	for _, row := range rows {
		out = append(out, genreCount{Genre: row.Genre, TrackCount: int(row.TrackCount)})
	}
	writeJSON(w, http.StatusOK, out)
}

// handleListAlbumYears implements GET /api/library/years.
//
// Albums with no release_date are absent rather than bucketed under 0 — "year
// unknown" isn't a year, and inventing a row for it would put a fake entry at
// one end of a chronological list.
func (h *handlers) handleListAlbumYears(w http.ResponseWriter, r *http.Request) {
	rows, err := dbq.New(h.pool).ListAlbumYearsWithCount(r.Context())
	if err != nil {
		h.logger.Error("api: list album years", "err", err)
		writeErr(w, apierror.InternalMsg("lookup failed", err))
		return
	}
	out := make([]yearCount, 0, len(rows))
	for _, row := range rows {
		out = append(out, yearCount{Year: int(row.Year), AlbumCount: int(row.AlbumCount)})
	}
	writeJSON(w, http.StatusOK, out)
}
