""" Show Discovery API - smart routing for finding shows. """ from datetime import date, timedelta from typing import List, Optional from fastapi import APIRouter, Depends, Query from sqlmodel import Session, select, desc from pydantic import BaseModel from database import get_session from models import Show, Venue, Vertical, Tour router = APIRouter(prefix="/discover", tags=["discover"]) class DiscoverShow(BaseModel): id: int date: str slug: str | None venue_name: str | None venue_city: str | None vertical_name: str vertical_slug: str tour_name: str | None = None class DiscoverResponse(BaseModel): shows: List[DiscoverShow] total: int filters_applied: dict @router.get("/shows", response_model=DiscoverResponse) def discover_shows( vertical: Optional[str] = None, year: Optional[int] = None, month: Optional[int] = None, venue: Optional[str] = None, tour: Optional[str] = None, city: Optional[str] = None, state: Optional[str] = None, limit: int = 50, offset: int = 0, sort: str = "date_desc", session: Session = Depends(get_session) ): """ Discover shows with smart filtering. Sort options: date_desc, date_asc """ query = select(Show).where(Show.date.isnot(None)) filters = {} # Filter by vertical (band) if vertical: v = session.exec(select(Vertical).where(Vertical.slug == vertical)).first() if v: query = query.where(Show.vertical_id == v.id) filters["vertical"] = vertical # Filter by year if year: start = date(year, 1, 1) end = date(year, 12, 31) query = query.where(Show.date >= start).where(Show.date <= end) filters["year"] = year # Filter by month (requires year) if month and year: start = date(year, month, 1) if month == 12: end = date(year + 1, 1, 1) - timedelta(days=1) else: end = date(year, month + 1, 1) - timedelta(days=1) query = query.where(Show.date >= start).where(Show.date <= end) filters["month"] = month # Filter by tour if tour: t = session.exec(select(Tour).where(Tour.slug == tour)).first() if t: query = query.where(Show.tour_id == t.id) filters["tour"] = tour # Apply sorting if sort == "date_asc": query = query.order_by(Show.date) else: query = query.order_by(desc(Show.date)) # Get total count before pagination all_shows = session.exec(query).all() total = len(all_shows) # Apply pagination paginated = all_shows[offset:offset + limit] # Filter by venue/city/state in Python (more flexible) results = [] for show in paginated: venue_obj = session.get(Venue, show.venue_id) if show.venue_id else None vert_obj = session.get(Vertical, show.vertical_id) tour_obj = session.get(Tour, show.tour_id) if show.tour_id else None # City/state filters if city and venue_obj and city.lower() not in venue_obj.city.lower(): continue if state and venue_obj and venue_obj.state and state.lower() not in venue_obj.state.lower(): continue if venue and venue_obj and venue.lower() not in venue_obj.name.lower(): continue results.append(DiscoverShow( id=show.id, date=show.date.strftime("%Y-%m-%d") if show.date else "", slug=show.slug, venue_name=venue_obj.name if venue_obj else None, venue_city=venue_obj.city if venue_obj else None, vertical_name=vert_obj.name if vert_obj else "Unknown", vertical_slug=vert_obj.slug if vert_obj else "unknown", tour_name=tour_obj.name if tour_obj else None )) if city: filters["city"] = city if state: filters["state"] = state if venue: filters["venue"] = venue return DiscoverResponse( shows=results, total=total, filters_applied=filters ) @router.get("/years") def get_available_years( vertical: Optional[str] = None, session: Session = Depends(get_session) ): """Get list of years with shows for filtering UI""" query = select(Show).where(Show.date.isnot(None)) if vertical: v = session.exec(select(Vertical).where(Vertical.slug == vertical)).first() if v: query = query.where(Show.vertical_id == v.id) shows = session.exec(query).all() years = sorted(set(s.date.year for s in shows if s.date), reverse=True) return {"years": years} @router.get("/recent", response_model=List[DiscoverShow]) def get_recent_shows( limit: int = 10, vertical: Optional[str] = None, session: Session = Depends(get_session) ): """Get most recent shows for quick discovery""" query = select(Show).where(Show.date.isnot(None)) if vertical: v = session.exec(select(Vertical).where(Vertical.slug == vertical)).first() if v: query = query.where(Show.vertical_id == v.id) query = query.order_by(desc(Show.date)).limit(limit) shows = session.exec(query).all() results = [] for show in shows: venue = session.get(Venue, show.venue_id) if show.venue_id else None vert = session.get(Vertical, show.vertical_id) results.append(DiscoverShow( id=show.id, date=show.date.strftime("%Y-%m-%d") if show.date else "", slug=show.slug, venue_name=venue.name if venue else None, venue_city=venue.city if venue else None, vertical_name=vert.name if vert else "Unknown", vertical_slug=vert.slug if vert else "unknown" )) return results