""" Public API endpoints for predictions. This module provides public endpoints for retrieving predictions without authentication. """ from datetime import datetime from typing import Optional from fastapi import APIRouter, Query, Depends from sqlalchemy.orm import Session from app.database import get_db from app.services.prediction_service import PredictionService from app.schemas.public import ( PublicPredictionResponse, SuccessResponse, SuccessMeta ) router = APIRouter(prefix="/api/public/v1", tags=["public-predictions"]) @router.get("/predictions", response_model=SuccessResponse) def get_public_predictions( limit: int = Query(20, ge=1, le=100, description="Maximum number of predictions to return (max 100)"), offset: int = Query(0, ge=0, description="Number of predictions to skip"), league: Optional[str] = Query(None, description="Filter by league name (case-insensitive)"), db: Session = Depends(get_db) ): """ Get public predictions with pagination and filters. This endpoint provides publicly accessible predictions without authentication. Data is limited to non-sensitive information only. Args: limit: Maximum number of predictions to return (1-100, default: 20) offset: Number of predictions to skip (default: 0) league: Optional filter by league name (case-insensitive partial match) db: Database session (injected) Returns: Paginated list of public predictions with match details Example Requests: GET /api/public/v1/predictions GET /api/public/v1/predictions?limit=10&offset=0 GET /api/public/v1/predictions?league=Ligue%201 Example Response: { "data": [ { "id": 1, "match_id": 1, "match": { "id": 1, "home_team": "PSG", "away_team": "Olympique de Marseille", "date": "2026-01-18T20:00:00Z", "league": "Ligue 1", "status": "scheduled" }, "energy_score": "high", "confidence": "65.0%", "predicted_winner": "PSG", "created_at": "2026-01-17T12:00:00Z" } ], "meta": { "total": 45, "limit": 20, "offset": 0, "timestamp": "2026-01-17T14:30:00Z", "version": "v1" } } """ service = PredictionService(db) predictions, total = service.get_predictions_with_pagination( limit=limit, offset=offset, team_id=None, # No team filter for public API league=league, date_min=None, # No date filter for public API date_max=None ) # Build response with match details prediction_responses = [] for prediction in predictions: match = prediction.match prediction_responses.append({ "id": prediction.id, "match_id": prediction.match_id, "match": { "id": match.id, "home_team": match.home_team, "away_team": match.away_team, "date": match.date.isoformat() if match.date else None, "league": match.league, "status": match.status }, "energy_score": prediction.energy_score, "confidence": prediction.confidence, "predicted_winner": prediction.predicted_winner, "created_at": prediction.created_at.isoformat() if prediction.created_at else None }) return { "data": prediction_responses, "meta": { "total": total, "limit": limit, "offset": offset, "timestamp": datetime.utcnow().isoformat() + "Z", "version": "v1" } } @router.get("/predictions/{prediction_id}", response_model=PublicPredictionResponse) def get_public_prediction( prediction_id: int, db: Session = Depends(get_db) ): """ Get a specific public prediction by ID. This endpoint provides a publicly accessible prediction without authentication. Args: prediction_id: ID of the prediction db: Database session (injected) Returns: Public prediction with match details Raises: 404: If prediction doesn't exist Example Request: GET /api/public/v1/predictions/1 Example Response: { "id": 1, "match_id": 1, "match": { "id": 1, "home_team": "PSG", "away_team": "Olympique de Marseille", "date": "2026-01-18T20:00:00Z", "league": "Ligue 1", "status": "scheduled" }, "energy_score": "high", "confidence": "65.0%", "predicted_winner": "PSG", "created_at": "2026-01-17T12:00:00Z" } """ service = PredictionService(db) prediction = service.get_prediction_by_id(prediction_id) if not prediction: from fastapi import HTTPException, status raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Prediction with id {prediction_id} not found" ) match = prediction.match return { "id": prediction.id, "match_id": prediction.match_id, "match": { "id": match.id, "home_team": match.home_team, "away_team": match.away_team, "date": match.date.isoformat() if match.date else None, "league": match.league, "status": match.status }, "energy_score": prediction.energy_score, "confidence": prediction.confidence, "predicted_winner": prediction.predicted_winner, "created_at": prediction.created_at.isoformat() if prediction.created_at else None }