from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from app.auth import get_current_admin_user from app.database import get_session from app.models import Show, ShowSchedule from app.schemas import ShowCreate, ShowUpdate, ShowResponse from app.user_models import User router = APIRouter() @router.get("", response_model=list[ShowResponse]) async def list_shows(session: AsyncSession = Depends(get_session)): query = ( select(Show) .where(Show.active == True) .options(selectinload(Show.schedules)) .order_by(Show.display_order, Show.title) ) result = await session.execute(query) return list(result.scalars().all()) @router.get("/{show_id}", response_model=ShowResponse) async def get_show( show_id: int, session: AsyncSession = Depends(get_session), ): result = await session.execute( select(Show) .options(selectinload(Show.schedules)) .where(Show.id == show_id) ) show = result.scalar_one_or_none() if not show: raise HTTPException(status_code=404, detail="Show not found") return show @router.post("", response_model=ShowResponse, status_code=201) async def create_show( payload: ShowCreate, session: AsyncSession = Depends(get_session), _: User = Depends(get_current_admin_user), ): data = payload.model_dump(exclude={"schedules"}) show = Show(**data) for slot in payload.schedules: show.schedules.append(ShowSchedule(**slot.model_dump())) session.add(show) await session.commit() await session.refresh(show) await session.refresh(show) # Re-query with eager load to return schedules result = await session.execute( select(Show) .options(selectinload(Show.schedules)) .where(Show.id == show.id) ) return result.scalar_one() @router.put("/{show_id}", response_model=ShowResponse) async def update_show( show_id: int, payload: ShowUpdate, session: AsyncSession = Depends(get_session), _: User = Depends(get_current_admin_user), ): result = await session.execute( select(Show) .options(selectinload(Show.schedules)) .where(Show.id == show_id) ) show = result.scalar_one_or_none() if not show: raise HTTPException(status_code=404, detail="Show not found") update_data = payload.model_dump(exclude_unset=True, exclude={"schedules"}) for key, value in update_data.items(): setattr(show, key, value) if payload.schedules is not None: # Replace all schedule slots for sched in show.schedules: await session.delete(sched) await session.flush() # execute deletes before inserts to avoid UNIQUE conflict for slot in payload.schedules: session.add(ShowSchedule(show_id=show.id, **slot.model_dump())) await session.commit() await session.refresh(show) # Re-query with eager load result = await session.execute( select(Show) .options(selectinload(Show.schedules)) .where(Show.id == show.id) ) return result.scalar_one() @router.delete("/{show_id}", status_code=204) async def delete_show( show_id: int, session: AsyncSession = Depends(get_session), _: User = Depends(get_current_admin_user), ): result = await session.execute(select(Show).where(Show.id == show_id)) show = result.scalar_one_or_none() if not show: raise HTTPException(status_code=404, detail="Show not found") await session.delete(show) await session.commit()