import uuid from datetime import datetime, timezone from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from app.crud import crud_championship, crud_registration from app.database import get_db from app.dependencies import get_approved_user, get_organizer from app.models.user import User from app.schemas.registration import RegistrationCreate, RegistrationOut, RegistrationStatusUpdate router = APIRouter(prefix="/registrations", tags=["registrations"]) @router.post("", response_model=RegistrationOut, status_code=status.HTTP_201_CREATED) async def submit_registration( body: RegistrationCreate, current_user: User = Depends(get_approved_user), db: AsyncSession = Depends(get_db), ): champ = await crud_championship.get(db, body.championship_id) if not champ: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Championship not found") if champ.status != "open": raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Registration is not open" ) if champ.registration_close_at and champ.registration_close_at < datetime.now(timezone.utc): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Registration deadline has passed" ) existing = await crud_registration.get_by_champ_and_user( db, body.championship_id, current_user.id ) if existing: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="You have already registered for this championship", ) return await crud_registration.create( db, championship_id=uuid.UUID(body.championship_id), user_id=current_user.id, category=body.category, level=body.level, notes=body.notes, ) @router.get("/my", response_model=list[RegistrationOut]) async def my_registrations( current_user: User = Depends(get_approved_user), db: AsyncSession = Depends(get_db), ): return await crud_registration.list_by_user(db, current_user.id) @router.get("/{registration_id}", response_model=RegistrationOut) async def get_registration( registration_id: str, current_user: User = Depends(get_approved_user), db: AsyncSession = Depends(get_db), ): reg = await crud_registration.get(db, registration_id) if not reg: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) if str(reg.user_id) != str(current_user.id) and current_user.role not in ( "organizer", "admin", ): raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) return reg @router.get("/championship/{championship_id}", response_model=list[RegistrationOut]) async def championship_registrations( championship_id: str, _organizer: User = Depends(get_organizer), db: AsyncSession = Depends(get_db), ): champ = await crud_championship.get(db, championship_id) if not champ: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) return await crud_registration.list_by_championship(db, championship_id) @router.patch("/{registration_id}/status", response_model=RegistrationOut) async def update_registration_status( registration_id: str, body: RegistrationStatusUpdate, _organizer: User = Depends(get_organizer), db: AsyncSession = Depends(get_db), ): allowed = {"accepted", "rejected", "waitlisted"} if body.status not in allowed: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Status must be one of: {', '.join(allowed)}", ) reg = await crud_registration.get(db, registration_id) if not reg: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) return await crud_registration.update_status(db, reg, body.status) @router.delete("/{registration_id}", status_code=status.HTTP_204_NO_CONTENT) async def withdraw_registration( registration_id: str, current_user: User = Depends(get_approved_user), db: AsyncSession = Depends(get_db), ): reg = await crud_registration.get(db, registration_id) if not reg: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) if str(reg.user_id) != str(current_user.id): raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) if reg.status != "submitted": raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Only submitted registrations can be withdrawn", ) await crud_registration.delete(db, reg)