"""Artist endpoints.""" import uuid from typing import Any from fastapi import APIRouter, Query from app.api.deps import AlbumRepoDep, ArtistRepoDep, CurrentUser, TrackRepoDep from app.api.schemas.album import AlbumOut from app.api.schemas.artist import ArtistOut from app.api.schemas.pagination import PagedResponse from app.api.schemas.track import TrackOut from app.api.v1.albums import _build_album_out from app.api.v1.tracks import _build_track_out from app.domain.errors import NotFoundError router = APIRouter(prefix="/artists", tags=["artists"]) @router.get("") async def list_artists( artist_repo: ArtistRepoDep, _: CurrentUser, q: str | None = None, limit: int = Query(50, ge=1, le=200), offset: int = Query(0, ge=0), ) -> PagedResponse[ArtistOut]: artists = await artist_repo.list(q=q, limit=limit, offset=offset) total = await artist_repo.count(q=q) items = [] for a in artists: album_cnt = await artist_repo.album_count(a.id) track_cnt = await artist_repo.track_count(a.id) items.append( ArtistOut( id=a.id, name=a.name, album_count=album_cnt, track_count=track_cnt, created_at=a.created_at, ) ) return PagedResponse(items=items, total=total, limit=limit, offset=offset) @router.get("/{artist_id}") async def get_artist( artist_id: uuid.UUID, artist_repo: ArtistRepoDep, _: CurrentUser, ) -> ArtistOut: artist = await artist_repo.get_by_id(artist_id) if artist is None: raise NotFoundError(f"Artist {artist_id} not found.") album_cnt = await artist_repo.album_count(artist_id) track_cnt = await artist_repo.track_count(artist_id) return ArtistOut( id=artist.id, name=artist.name, album_count=album_cnt, track_count=track_cnt, created_at=artist.created_at, ) @router.get("/{artist_id}/albums") async def get_artist_albums( artist_id: uuid.UUID, artist_repo: ArtistRepoDep, album_repo: AlbumRepoDep, _: CurrentUser, limit: int = Query(50, ge=1, le=200), offset: int = Query(0, ge=0), ) -> PagedResponse[AlbumOut]: artist = await artist_repo.get_by_id(artist_id) if artist is None: raise NotFoundError(f"Artist {artist_id} not found.") albums = await album_repo.list(artist_id=artist_id, q=None, limit=limit, offset=offset) total = await album_repo.count(artist_id=artist_id, q=None) artists_map = {artist.id: artist} track_counts = await album_repo.track_count_many([a.id for a in albums]) items = await _build_album_out(albums, artists_map, track_counts) return PagedResponse(items=items, total=total, limit=limit, offset=offset) @router.get("/{artist_id}/tracks") async def get_artist_tracks( artist_id: uuid.UUID, artist_repo: ArtistRepoDep, track_repo: TrackRepoDep, album_repo: AlbumRepoDep, _: CurrentUser, limit: int = Query(50, ge=1, le=200), offset: int = Query(0, ge=0), ) -> PagedResponse[TrackOut]: artist = await artist_repo.get_by_id(artist_id) if artist is None: raise NotFoundError(f"Artist {artist_id} not found.") tracks = await track_repo.list( artist_id=artist_id, album_id=None, q=None, sort_by="title", order="asc", limit=limit, offset=offset, ) total = await track_repo.count(artist_id=artist_id, album_id=None, q=None) album_ids = list({t.album_id for t in tracks if t.album_id is not None}) artists_map = {artist.id: artist} albums_map = {a.id: a for a in await album_repo.get_many(album_ids)} items = await _build_track_out(tracks, artists_map, albums_map) return PagedResponse(items=items, total=total, limit=limit, offset=offset) @router.get("/{artist_id}/similar") async def get_similar_artists(artist_id: uuid.UUID, _: CurrentUser) -> Any: ...