package api

import (
	"time"

	"github.com/jackc/pgx/v5/pgtype"
)

// LoginRequest is the POST /api/auth/login body. Kept boring on purpose —
// web and Flutter both send the same payload.
type LoginRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

// LoginResponse carries the opaque session token AND the authenticated user
// so the SPA can hydrate its auth store in one round-trip. The token is also
// set as a cookie; SPAs ignore the body token, Flutter uses it as bearer.
type LoginResponse struct {
	Token string   `json:"token"`
	User  UserView `json:"user"`
}

// UserView is the /api/* view of a user. Narrower than dbq.User — no hash,
// no api_token, no subsonic_password.
type UserView struct {
	ID       pgtype.UUID `json:"id"`
	Username string      `json:"username"`
	IsAdmin  bool        `json:"is_admin"`
}

// Page is the generic pagination envelope used by list and search endpoints.
// Items is always non-nil at JSON encode time — handlers must initialize
// empty slices explicitly so absent results render as [] rather than null.
type Page[T any] struct {
	Items  []T `json:"items"`
	Total  int `json:"total"`
	Limit  int `json:"limit"`
	Offset int `json:"offset"`
}

// ArtistRef is the lightweight artist shape used in lists and search results.
// SortName is exposed so the SPA's alphabetical-grid divider can group rows
// by the catalogue sort order ("The Beatles" → "B"). CoverURL is derived from
// a representative album (most-recent with cover_art_path); empty when the
// artist's discography has no cover art.
type ArtistRef struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	SortName   string `json:"sort_name"`
	AlbumCount int    `json:"album_count"`
	CoverURL   string `json:"cover_url"`
}

// AlbumRef is the lightweight album shape used in lists, artist details,
// and search results. SortTitle is exposed so the SPA's alphabetical-grid
// divider can group rows by sort order ("The Wall" → "W"). CoverURL points
// to /api/albums/{id}/cover.
type AlbumRef struct {
	ID             string  `json:"id"`
	Title          string  `json:"title"`
	SortTitle      string  `json:"sort_title"`
	ArtistID       string  `json:"artist_id"`
	ArtistName     string  `json:"artist_name"`
	Year           int     `json:"year,omitempty"`
	TrackCount     int     `json:"track_count"`
	DurationSec    int     `json:"duration_sec"`
	CoverURL       string  `json:"cover_url"`
	CoverArtSource *string `json:"cover_art_source"`
}

// TrackRef is the lightweight track shape used in album details and search.
// StreamURL points to /api/tracks/{id}/stream which Plan 3 implements.
type TrackRef struct {
	ID          string `json:"id"`
	Title       string `json:"title"`
	AlbumID     string `json:"album_id"`
	AlbumTitle  string `json:"album_title"`
	ArtistID    string `json:"artist_id"`
	ArtistName  string `json:"artist_name"`
	TrackNumber int    `json:"track_number,omitempty"`
	DiscNumber  int    `json:"disc_number,omitempty"`
	DurationSec int    `json:"duration_sec"`
	StreamURL   string `json:"stream_url"`
}

// ArtistDetail is the response body of GET /api/artists/{id}. Embeds the ref
// so callers read id/name/album_count from the same path as list entries.
type ArtistDetail struct {
	ArtistRef
	Albums []AlbumRef `json:"albums"`
	// Genres carried by this artist's tracks, for quick-jump chips (#367).
	// Always non-nil at JSON so the client can iterate without a null check.
	Genres []string `json:"genres"`
}

// AlbumDetail is the response body of GET /api/albums/{id}.
type AlbumDetail struct {
	AlbumRef
	Tracks []TrackRef `json:"tracks"`
	// Genres carried by this album's tracks, for quick-jump chips (#367).
	// Derived from the tracks rather than stored on the album, because genre
	// lives on tracks and an album's tracks can disagree. Non-nil at JSON.
	Genres []string `json:"genres"`
}

// SearchResponse is the body of GET /api/search. Each facet carries its own
// total + limit + offset; the client sends one shared limit/offset and the
// server applies it uniformly to each facet's LIMIT/OFFSET query.
type SearchResponse struct {
	Artists Page[ArtistRef] `json:"artists"`
	Albums  Page[AlbumRef]  `json:"albums"`
	Tracks  Page[TrackRef]  `json:"tracks"`
}

// HomePayload is the response body of GET /api/home. Field counts:
// 50 (recently_added) / 25 (rediscover_albums) / 25 (rediscover_artists)
// / 75 (most_played) / 25 (last_played). All slices are non-nil at JSON
// encode time so empty sections render as [] rather than null.
type HomePayload struct {
	RecentlyAddedAlbums []AlbumRef  `json:"recently_added_albums"`
	RediscoverAlbums    []AlbumRef  `json:"rediscover_albums"`
	RediscoverArtists   []ArtistRef `json:"rediscover_artists"`
	MostPlayedTracks    []TrackRef  `json:"most_played_tracks"`
	LastPlayedArtists   []ArtistRef `json:"last_played_artists"`
	// You-might-like: in-library albums/artists predicted from the user's
	// listening that they don't actively spin. Built daily; gated on a
	// minimum listening history so a thin profile gets empty rows.
	YouMightLikeAlbums  []AlbumRef  `json:"you_might_like_albums"`
	YouMightLikeArtists []ArtistRef `json:"you_might_like_artists"`
}

// HomeIndexPayload is the response body of GET /api/home/index — the
// per-item rendering variant of /api/home. Same sections, same caps,
// but each section is a flat slice of entity IDs (UUID strings)
// instead of denormalized objects. Slices are non-nil at JSON encode
// time so empty sections render as `[]`.
//
// Client fetches this, then hydrates each tile against the per-entity
// endpoints (/api/albums/{id}, /api/artists/{id}, /api/tracks/{id})
// for genuine progressive rendering. The section name implies the
// entity type so no per-entry type tag is needed.
type HomeIndexPayload struct {
	RecentlyAddedAlbums []string `json:"recently_added_albums"`
	RediscoverAlbums    []string `json:"rediscover_albums"`
	RediscoverArtists   []string `json:"rediscover_artists"`
	MostPlayedTracks    []string `json:"most_played_tracks"`
	LastPlayedArtists   []string `json:"last_played_artists"`
	YouMightLikeAlbums  []string `json:"you_might_like_albums"`
	YouMightLikeArtists []string `json:"you_might_like_artists"`
}

// HistoryEvent is one play in a user's listening history. Used by
// /api/me/history; one event per row from play_events.
type HistoryEvent struct {
	ID       string    `json:"id"`        // play_events.id
	PlayedAt time.Time `json:"played_at"` // play_events.started_at
	Track    TrackRef  `json:"track"`
}

// HistoryResponse is the body of GET /api/me/history.
type HistoryResponse struct {
	Events  []HistoryEvent `json:"events"`
	HasMore bool           `json:"has_more"`
}
