import logging from typing import Literal from fastapi import APIRouter, Depends, Query, HTTPException from api.v1.schemas.home import ( HomeResponse, HomeIntegrationStatus, GenreDetailResponse, GenreArtistResponse, GenreArtistsBatchResponse, TrendingArtistsResponse, TrendingArtistsRangeResponse, PopularAlbumsResponse, PopularAlbumsRangeResponse, ) from core.dependencies import get_home_service, get_home_charts_service from infrastructure.degradation import try_get_degradation_context from infrastructure.msgspec_fastapi import MsgSpecRoute import msgspec.structs from services.home_service import HomeService from services.home_charts_service import HomeChartsService logger = logging.getLogger(__name__) router = APIRouter(route_class=MsgSpecRoute, prefix="/home", tags=["home"]) @router.get("", response_model=HomeResponse) async def get_home_data( source: Literal["listenbrainz", "lastfm"] | None = Query(default=None, description="Data source: listenbrainz or lastfm"), home_service: HomeService = Depends(get_home_service), ): result = await home_service.get_home_data(source=source) ctx = try_get_degradation_context() if ctx is not None and ctx.has_degradation(): result = msgspec.structs.replace(result, service_status=ctx.degraded_summary()) return result @router.get("/integration-status", response_model=HomeIntegrationStatus) async def get_integration_status( home_service: HomeService = Depends(get_home_service) ): return home_service.get_integration_status() @router.get("/genre/{genre_name}", response_model=GenreDetailResponse) async def get_genre_detail( genre_name: str, limit: int = Query(default=50, ge=1, le=200), artist_offset: int = Query(default=0, ge=0), album_offset: int = Query(default=0, ge=0), charts_service: HomeChartsService = Depends(get_home_charts_service) ): return await charts_service.get_genre_artists( genre=genre_name, limit=limit, artist_offset=artist_offset, album_offset=album_offset, ) @router.get("/trending/artists", response_model=TrendingArtistsResponse) async def get_trending_artists( limit: int = Query(default=10, ge=1, le=25), source: Literal["listenbrainz", "lastfm"] | None = Query(default=None), charts_service: HomeChartsService = Depends(get_home_charts_service) ): return await charts_service.get_trending_artists(limit=limit, source=source) @router.get("/trending/artists/{range_key}", response_model=TrendingArtistsRangeResponse) async def get_trending_artists_by_range( range_key: str, limit: int = Query(default=25, ge=1, le=100), offset: int = Query(default=0, ge=0), source: Literal["listenbrainz", "lastfm"] | None = Query(default=None), charts_service: HomeChartsService = Depends(get_home_charts_service) ): return await charts_service.get_trending_artists_by_range( range_key=range_key, limit=limit, offset=offset, source=source ) @router.get("/popular/albums", response_model=PopularAlbumsResponse) async def get_popular_albums( limit: int = Query(default=10, ge=1, le=25), source: Literal["listenbrainz", "lastfm"] | None = Query(default=None), charts_service: HomeChartsService = Depends(get_home_charts_service) ): return await charts_service.get_popular_albums(limit=limit, source=source) @router.get("/popular/albums/{range_key}", response_model=PopularAlbumsRangeResponse) async def get_popular_albums_by_range( range_key: str, limit: int = Query(default=25, ge=1, le=100), offset: int = Query(default=0, ge=0), source: Literal["listenbrainz", "lastfm"] | None = Query(default=None), charts_service: HomeChartsService = Depends(get_home_charts_service) ): return await charts_service.get_popular_albums_by_range( range_key=range_key, limit=limit, offset=offset, source=source ) @router.get("/your-top/albums", response_model=PopularAlbumsResponse) async def get_your_top_albums( limit: int = Query(default=10, ge=1, le=25), source: Literal["listenbrainz", "lastfm"] | None = Query(default=None), charts_service: HomeChartsService = Depends(get_home_charts_service) ): return await charts_service.get_your_top_albums(limit=limit, source=source) @router.get("/your-top/albums/{range_key}", response_model=PopularAlbumsRangeResponse) async def get_your_top_albums_by_range( range_key: str, limit: int = Query(default=25, ge=1, le=100), offset: int = Query(default=0, ge=0), source: Literal["listenbrainz", "lastfm"] | None = Query(default=None), charts_service: HomeChartsService = Depends(get_home_charts_service) ): return await charts_service.get_your_top_albums_by_range( range_key=range_key, limit=limit, offset=offset, source=source ) @router.get("/genre-artist/{genre_name}", response_model=GenreArtistResponse) async def get_genre_artist( genre_name: str, home_service: HomeService = Depends(get_home_service) ): artist_mbid = await home_service.get_genre_artist(genre_name) return GenreArtistResponse(artist_mbid=artist_mbid) @router.post("/genre-artists", response_model=GenreArtistsBatchResponse) async def get_genre_artists_batch( genres: list[str], home_service: HomeService = Depends(get_home_service) ): results = await home_service.get_genre_artists_batch(genres) return GenreArtistsBatchResponse(genre_artists=results)