"""Sound management API endpoints.""" from typing import Annotated from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlmodel.ext.asyncio.session import AsyncSession from app.core.database import get_db, get_session_factory from app.core.dependencies import get_current_active_user_flexible from app.models.user import User from app.repositories.sound import SortOrder, SoundRepository, SoundSortField from app.schemas.sound import SoundResponse, SoundsListResponse from app.services.favorite import FavoriteService from app.services.vlc_player import VLCPlayerService, get_vlc_player_service router = APIRouter(prefix="/sounds", tags=["sounds"]) def get_vlc_player() -> VLCPlayerService: """Get the VLC player service.""" return get_vlc_player_service(get_session_factory()) def get_favorite_service() -> FavoriteService: """Get the favorite service.""" return FavoriteService(get_session_factory()) async def get_sound_repository( session: Annotated[AsyncSession, Depends(get_db)], ) -> SoundRepository: """Get the sound repository.""" return SoundRepository(session) @router.get("/") async def get_sounds( # noqa: PLR0913 current_user: Annotated[User, Depends(get_current_active_user_flexible)], sound_repo: Annotated[SoundRepository, Depends(get_sound_repository)], favorite_service: Annotated[FavoriteService, Depends(get_favorite_service)], types: Annotated[ list[str] | None, Query(description="Filter by sound types (e.g., SDB, TTS, EXT)"), ] = None, search: Annotated[ str | None, Query(description="Search sounds by name"), ] = None, sort_by: Annotated[ SoundSortField | None, Query(description="Sort by field"), ] = None, sort_order: Annotated[ SortOrder, Query(description="Sort order (asc or desc)"), ] = SortOrder.ASC, limit: Annotated[ int | None, Query(description="Maximum number of results", ge=1, le=1000), ] = None, offset: Annotated[ int, Query(description="Number of results to skip", ge=0), ] = 0, favorites_only: Annotated[ # noqa: FBT002 bool, Query(description="Show only favorited sounds"), ] = False, ) -> SoundsListResponse: """Get sounds with optional search, filtering, and sorting.""" try: sounds = await sound_repo.search_and_sort( search_query=search, sound_types=types, sort_by=sort_by, sort_order=sort_order, limit=limit, offset=offset, favorites_only=favorites_only, user_id=current_user.id, ) # Add favorite indicators for each sound sound_responses = [] for sound in sounds: is_favorited = await favorite_service.is_sound_favorited( current_user.id, sound.id, ) favorite_count = await favorite_service.get_sound_favorite_count(sound.id) sound_response = SoundResponse.from_sound( sound, is_favorited, favorite_count, ) sound_responses.append(sound_response) except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to get sounds: {e!s}", ) from e else: return SoundsListResponse(sounds=sound_responses) # VLC PLAYER @router.post("/play/{sound_id}") async def play_sound_with_vlc( sound_id: int, current_user: Annotated[User, Depends(get_current_active_user_flexible)], vlc_player: Annotated[VLCPlayerService, Depends(get_vlc_player)], ) -> dict[str, str | int | bool]: """Play a sound using VLC subprocess (requires 1 credit).""" try: if not current_user.id: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User ID is required", ) return await vlc_player.play_sound_with_credits(sound_id, current_user.id) except HTTPException: raise except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to play sound: {e!s}", ) from e @router.post("/stop") async def stop_all_vlc_instances( current_user: Annotated[User, Depends(get_current_active_user_flexible)], # noqa: ARG001 vlc_player: Annotated[VLCPlayerService, Depends(get_vlc_player)], ) -> dict: """Stop all running VLC instances.""" try: return await vlc_player.stop_all_vlc_instances() except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to stop VLC instances: {e!s}", ) from e