from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from typing import List, Optional from ..db.database import get_db from ..models.playlist import Playlist, PlaylistSong from ..models.song import Song from ..schemas.playlist import PlaylistCreate, PlaylistResponse, PlaylistWithSongs, PlaylistBase from ..schemas.song import SongResponse import uuid router = APIRouter(prefix="/api/playlists", tags=["playlists"]) @router.get("", response_model=List[PlaylistResponse]) def list_playlists(db: Session = Depends(get_db)): playlists = db.query(Playlist).order_by(Playlist.updated_at.desc()).all() result = [] for p in playlists: song_count = db.query(PlaylistSong).filter(PlaylistSong.playlist_id == p.id).count() data = PlaylistResponse.model_validate(p) data.song_count = song_count result.append(data) return result @router.post("", response_model=PlaylistResponse) def create_playlist(playlist: PlaylistCreate, db: Session = Depends(get_db)): playlist_id = str(uuid.uuid4()) p = Playlist( id=playlist_id, name=playlist.name, description=playlist.description or "", mood_category=playlist.mood_category, ) db.add(p) if playlist.song_ids: for i, song_id in enumerate(playlist.song_ids): ps = PlaylistSong(playlist_id=playlist_id, song_id=song_id, position=i) db.add(ps) db.commit() db.refresh(p) return PlaylistResponse.model_validate(p) @router.get("/{playlist_id}", response_model=PlaylistWithSongs) def get_playlist(playlist_id: str, db: Session = Depends(get_db)): playlist = db.query(Playlist).filter(Playlist.id == playlist_id).first() if not playlist: raise HTTPException(status_code=404, detail="Playlist not found") songs_query = db.query(Song, PlaylistSong.position).join(PlaylistSong, PlaylistSong.song_id == Song.id).filter(PlaylistSong.playlist_id == playlist_id).order_by(PlaylistSong.position).all() data = PlaylistWithSongs.model_validate(playlist) data.songs = [SongResponse.model_validate(s) for s, _ in songs_query] data.song_count = len(songs_query) return data @router.put("/{playlist_id}", response_model=PlaylistResponse) def update_playlist(playlist_id: str, data: PlaylistBase, db: Session = Depends(get_db)): playlist = db.query(Playlist).filter(Playlist.id == playlist_id).first() if not playlist: raise HTTPException(status_code=404, detail="Playlist not found") playlist.name = data.name playlist.description = data.description or "" db.commit() db.refresh(playlist) return PlaylistResponse.model_validate(playlist) @router.delete("/{playlist_id}") def delete_playlist(playlist_id: str, db: Session = Depends(get_db)): playlist = db.query(Playlist).filter(Playlist.id == playlist_id).first() if not playlist: raise HTTPException(status_code=404, detail="Playlist not found") db.query(PlaylistSong).filter(PlaylistSong.playlist_id == playlist_id).delete() db.delete(playlist) db.commit() return {"message": "Playlist deleted"} @router.post("/{playlist_id}/songs") def add_song_to_playlist(playlist_id: str, song_id: str, db: Session = Depends(get_db)): playlist = db.query(Playlist).filter(Playlist.id == playlist_id).first() if not playlist: raise HTTPException(status_code=404, detail="Playlist not found") song = db.query(Song).filter(Song.id == song_id).first() if not song: raise HTTPException(status_code=404, detail="Song not found") existing = db.query(PlaylistSong).filter(PlaylistSong.playlist_id == playlist_id, PlaylistSong.song_id == song_id).first() if existing: raise HTTPException(status_code=400, detail="Song already in playlist") max_pos = db.query(PlaylistSong).filter(PlaylistSong.playlist_id == playlist_id).count() ps = PlaylistSong(playlist_id=playlist_id, song_id=song_id, position=max_pos) db.add(ps) db.commit() return {"message": "Song added"} @router.delete("/{playlist_id}/songs/{song_id}") def remove_song_from_playlist(playlist_id: str, song_id: str, db: Session = Depends(get_db)): ps = db.query(PlaylistSong).filter(PlaylistSong.playlist_id == playlist_id, PlaylistSong.song_id == song_id).first() if not ps: raise HTTPException(status_code=404, detail="Song not in playlist") db.delete(ps) db.commit() return {"message": "Song removed"} @router.post("/{playlist_id}/share") def share_playlist(playlist_id: str, db: Session = Depends(get_db)): playlist = db.query(Playlist).filter(Playlist.id == playlist_id).first() if not playlist: raise HTTPException(status_code=404, detail="Playlist not found") token = str(uuid.uuid4())[:12] playlist.share_token = token playlist.is_shared = True db.commit() return {"token": token, "url": f"/playlists/shared/{token}"} @router.get("/shared/{token}", response_model=PlaylistWithSongs) def get_shared_playlist(token: str, db: Session = Depends(get_db)): playlist = db.query(Playlist).filter(Playlist.share_token == token).first() if not playlist: raise HTTPException(status_code=404, detail="Shared playlist not found") songs_query = db.query(Song, PlaylistSong.position).join(PlaylistSong, PlaylistSong.song_id == Song.id).filter(PlaylistSong.playlist_id == playlist.id).order_by(PlaylistSong.position).all() data = PlaylistWithSongs.model_validate(playlist) data.songs = [SongResponse.model_validate(s) for s, _ in songs_query] data.song_count = len(songs_query) return data