""" User Prediction API Routes. This module provides REST endpoints for tracking user predictions and retrieving user statistics. """ from typing import Optional from fastapi import APIRouter, Depends, HTTPException, status, Query from sqlalchemy.orm import Session from app.database import get_db from app.services.user_prediction_service import UserPredictionService from app.schemas.user_prediction import ( UserPredictionResponse, UserPredictionListResponse, UserStatsResponse ) router = APIRouter(prefix="/api/v1/user-predictions", tags=["user-predictions"]) @router.post("", status_code=status.HTTP_201_CREATED) def record_prediction_view( user_id: int, prediction_id: int, db: Session = Depends(get_db) ): """ Record that a user viewed a prediction. This endpoint tracks when a user views a prediction for ROI and accuracy calculations. Duplicate views are ignored (unique constraint on user_id + prediction_id). Args: user_id: ID of the user prediction_id: ID of the prediction viewed db: Database session (injected) Returns: Created user prediction record Raises: 404: If user or prediction doesn't exist 422: If validation fails Example Request: POST /api/v1/user-predictions?user_id=1&prediction_id=5 Example Response: { "id": 1, "user_id": 1, "prediction_id": 5, "viewed_at": "2026-01-18T10:00:00Z", "was_correct": null } """ try: service = UserPredictionService(db) user_prediction = service.record_prediction_view(user_id, prediction_id) return user_prediction.to_dict() except ValueError as e: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=str(e) ) except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to record prediction view: {str(e)}" ) @router.get("/history/{user_id}", response_model=UserPredictionListResponse) def get_prediction_history( user_id: int, limit: int = Query(50, ge=1, le=100, description="Maximum number of records to return (max 100)"), offset: int = Query(0, ge=0, description="Number of records to skip"), db: Session = Depends(get_db) ): """ Get a user's prediction viewing history. This endpoint retrieves all predictions a user has viewed, sorted by most recent. Includes full prediction and match details. Args: user_id: ID of the user limit: Maximum number of records to return (1-100, default: 50) offset: Number of records to skip (default: 0) db: Database session (injected) Returns: Paginated list of user predictions with full details Example Request: GET /api/v1/user-predictions/history/1?limit=10&offset=0 Example Response: { "data": [ { "id": 5, "user_id": 1, "prediction_id": 10, "viewed_at": "2026-01-18T10:00:00Z", "was_correct": true, "prediction": { "id": 10, "match_id": 3, "energy_score": "high", "confidence": "75.0%", "predicted_winner": "PSG", "created_at": "2026-01-17T12:00:00Z" }, "match": { "id": 3, "home_team": "PSG", "away_team": "Marseille", "date": "2026-01-18T20:00:00Z", "league": "Ligue 1", "status": "completed", "actual_winner": "PSG" } } ], "meta": { "total": 25, "limit": 10, "offset": 0, "timestamp": "2026-01-18T15:30:00Z" } } """ from datetime import datetime service = UserPredictionService(db) predictions, total = service.get_user_prediction_history( user_id=user_id, limit=limit, offset=offset ) return { "data": predictions, "meta": { "total": total, "limit": limit, "offset": offset, "timestamp": datetime.utcnow().isoformat() + "Z" } } @router.get("/stats/{user_id}", response_model=UserStatsResponse) def get_user_statistics( user_id: int, db: Session = Depends(get_db) ): """ Get user statistics including accuracy and ROI. This endpoint calculates: - Total predictions viewed - Number of correct/incorrect predictions - Accuracy rate percentage - ROI (Return on Investment) in EUR Args: user_id: ID of the user db: Database session (injected) Returns: User statistics Raises: 404: If user doesn't exist Example Request: GET /api/v1/user-predictions/stats/1 Example Response: { "total_predictions_viewed": 25, "correct_predictions": 18, "incorrect_predictions": 5, "accuracy_rate": 78.3, "roi": 1550.0 } """ service = UserPredictionService(db) stats = service.get_user_stats(user_id) return UserStatsResponse(**stats) @router.put("/result/{prediction_id}") def update_prediction_result( prediction_id: int, actual_winner: Optional[str] = Query(None, description="Actual winner: home, away, draw, or null"), db: Session = Depends(get_db) ): """ Update prediction result when match completes. This endpoint is called when a match finishes to update all user predictions that referenced this prediction. Args: prediction_id: ID of the prediction actual_winner: Actual winner of the match (home/away/draw or null) db: Database session (injected) Returns: Success message Example Request: PUT /api/v1/user-predictions/result/10?actual_winner=home Example Response: { "message": "Prediction results updated successfully", "prediction_id": 10, "actual_winner": "home" } """ try: service = UserPredictionService(db) service.update_prediction_result(prediction_id, actual_winner) return { "message": "Prediction results updated successfully", "prediction_id": prediction_id, "actual_winner": actual_winner } except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to update prediction result: {str(e)}" )