# backend/app/routes/courts.py from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from datetime import datetime, date from .. import crud, schemas, models from ..constants import SUCCESS from ..core.auth import get_admin_user from ..database import get_db router = APIRouter(prefix="/courts", tags=["Courts"]) @router.get("", response_model=list[schemas.CourtSchema]) def get_all_courts(db: Session = Depends(get_db)): """Public route to list all global courts""" return db.query(models.Court).all() @router.post("", response_model=schemas.CourtSchema) def create_global_court( data: schemas.CourtCreate, db: Session = Depends(get_db), user: dict = Depends(get_admin_user), ): """Admin route to register a new physical court""" return crud.create_court(db, data) @router.delete("/{court_id}") def delete_global_court( court_id: int, db: Session = Depends(get_db), user: dict = Depends(get_admin_user) ): success = crud.delete_court(db, court_id) if not success: raise HTTPException(404, "Court not found") return SUCCESS @router.get("/{court_id}/schedule") def get_court_schedule(court_id: int, db: Session = Depends(get_db)): court = db.query(models.Court).filter(models.Court.id == court_id).first() if not court: raise HTTPException(404, "Court not found") today = date.today() matches = ( db.query(models.Match) .join(models.Tournament) .filter(models.Match.court_id == court_id) .filter( models.Tournament.timestamp >= datetime.combine(today, datetime.min.time()) ) .filter( models.Tournament.timestamp < datetime.combine(today, datetime.max.time()) ) .order_by(models.Match.start_time) .all() ) t_ids = {m.tournament_id for m in matches} if t_ids: all_t_matches = db.query(models.Match).filter(models.Match.tournament_id.in_(t_ids)).all() else: all_t_matches = [] match_by_id = {str(tm.id).lower(): tm for tm in all_t_matches} parent_map = {} for tm in all_t_matches: if tm.winner_next_match_id: parent_map[(str(tm.winner_next_match_id).lower(), tm.winner_next_match_slot)] = f"Winner of #{tm.match_number}" if tm.loser_next_match_id: parent_map[(str(tm.loser_next_match_id).lower(), tm.loser_next_match_slot)] = f"Loser of #{tm.match_number}" def resolve_ref(m: models.Match): if m.ref_team: return m.ref_team.name if m.ref_label and ":" in m.ref_label: outcome, ref_id = m.ref_label.split(":") ref_match = match_by_id.get(ref_id.strip().lower()) if ref_match: role = "Winner" if outcome.upper() == "W" else "Loser" return f"{role} of #{ref_match.match_number}" return m.ref_label or "TBD" def get_team_label(m: models.Match, slot: int, team): if team: return team.name return parent_map.get((str(m.id).lower(), slot), "TBD") return { "court": court.name, "matches": [ { "id": m.id, "tournament_id": m.tournament.id, "tournament_name": m.tournament.name, "duration": m.tournament.duration, "time": m.start_time.strftime("%H:%M") if m.start_time else None, "status": m.status.value if hasattr(m.status, 'value') else m.status, "match_number": m.match_number, "p1": get_team_label(m, 0, m.p1_team), "p2": get_team_label(m, 1, m.p2_team), "p1_is_real": bool(m.p1_team), "p2_is_real": bool(m.p2_team), "p1_sets": len([s for s in m.sets if s.get("p1", 0) > s.get("p2", 0)]), "p2_sets": len([s for s in m.sets if s.get("p2", 0) > s.get("p1", 0)]), "ref_name": resolve_ref(m), } for m in matches if m.start_time ], }