from fastapi import APIRouter, Depends, HTTPException from sqlmodel import Session, select, func from typing import List, Optional from database import get_session from models import ( Vertical, Artist, Musician, BandMembership, PerformanceGuest, Performance, Show, Song, Venue ) router = APIRouter(prefix="/bands", tags=["bands"]) @router.get("") async def list_bands( scene: Optional[str] = None, is_featured: Optional[bool] = None, session: Session = Depends(get_session) ): """List all active bands, optionally filtered""" query = select(Vertical).where(Vertical.is_active == True) if is_featured is not None: query = query.where(Vertical.is_featured == is_featured) bands = session.exec(query.order_by(Vertical.name)).all() return bands @router.get("/{slug}") async def get_band_profile(slug: str, session: Session = Depends(get_session)): """Get comprehensive band profile including members and stats""" vertical = session.exec( select(Vertical).where(Vertical.slug == slug) ).first() if not vertical: raise HTTPException(status_code=404, detail="Band not found") # Get members via BandMembership if primary_artist_id exists current_members = [] past_members = [] if vertical.primary_artist_id: # Get all memberships for this band's artist memberships = session.exec( select(BandMembership, Musician) .join(Musician, BandMembership.musician_id == Musician.id) .where(BandMembership.artist_id == vertical.primary_artist_id) .order_by(BandMembership.start_date) ).all() for membership, musician in memberships: member_data = { "id": musician.id, "name": musician.name, "slug": musician.slug, "image_url": musician.image_url, "role": membership.role, "primary_instrument": musician.primary_instrument, "start_date": membership.start_date, "end_date": membership.end_date, "notes": membership.notes, } if membership.end_date is None: current_members.append(member_data) else: past_members.append(member_data) # Get stats show_count = session.exec( select(func.count(Show.id)).where(Show.vertical_id == vertical.id) ).one() song_count = session.exec( select(func.count(Song.id)).where(Song.vertical_id == vertical.id) ).one() # Get venue count (distinct venues from shows) venue_count = session.exec( select(func.count(func.distinct(Show.venue_id))) .where(Show.vertical_id == vertical.id) ).one() # Get first and last show dates first_show = session.exec( select(Show.date) .where(Show.vertical_id == vertical.id) .order_by(Show.date.asc()) .limit(1) ).first() last_show = session.exec( select(Show.date) .where(Show.vertical_id == vertical.id) .order_by(Show.date.desc()) .limit(1) ).first() stats = { "total_shows": show_count, "total_songs": song_count, "total_venues": venue_count, "first_show": first_show, "last_show": last_show, } return { "band": vertical, "current_members": current_members, "past_members": past_members, "stats": stats, }