"""
Prediction API Routes.

This module provides REST endpoints for creating and retrieving match predictions.
"""

from datetime import datetime
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.prediction_service import PredictionService
from app.schemas.prediction import PredictionListResponse, PredictionResponse

router = APIRouter(prefix="/api/v1/predictions", tags=["predictions"])


@router.get("", response_model=PredictionListResponse)
def get_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"),
    team_id: Optional[int] = Query(None, description="Filter by team ID"),
    league: Optional[str] = Query(None, description="Filter by league name (case-insensitive)"),
    date_min: Optional[datetime] = Query(None, description="Filter for matches after this date (ISO 8601)"),
    date_max: Optional[datetime] = Query(None, description="Filter for matches before this date (ISO 8601)"),
    db: Session = Depends(get_db)
):
    """
    Get all predictions with pagination and filters.
    
    This endpoint retrieves predictions joined with match data, applies optional filters,
    and returns paginated results sorted by match date (upcoming matches first).
    
    Args:
        limit: Maximum number of predictions to return (1-100, default: 20)
        offset: Number of predictions to skip (default: 0)
        team_id: Optional filter by team ID (matches where team is home or away)
        league: Optional filter by league name (case-insensitive partial match)
        date_min: Optional filter for matches after this date
        date_max: Optional filter for matches before this date
        db: Database session (injected)
    
    Returns:
        Paginated list of predictions with match details and metadata
    
    Example Requests:
        GET /api/v1/predictions
        GET /api/v1/predictions?limit=10&offset=0
        GET /api/v1/predictions?league=Ligue%201
        GET /api/v1/predictions?team_id=1&limit=5
        GET /api/v1/predictions?date_min=2026-01-15T00:00:00Z&date_max=2026-01-20T23:59:59Z
    
    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=team_id,
        league=league,
        date_min=date_min,
        date_max=date_max
    )
    
    # 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("/match/{match_id}")
def get_prediction_by_match_id(
    match_id: int,
    db: Session = Depends(get_db)
):
    """
    Get prediction details for a specific match.
    
    This endpoint retrieves the latest prediction for a match and includes
    full match details, energy score information, and historical predictions.
    
    Args:
        match_id: ID of the match
        db: Database session (injected)
    
    Returns:
        Prediction with full details including match info and history
    
    Raises:
        404: If match or prediction not found
    
    Example Request:
        GET /api/v1/predictions/match/1
    
    Example Response:
        {
            "id": 3,
            "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",
                "actual_winner": null
            },
            "energy_score": "high",
            "confidence": "70.5%",
            "predicted_winner": "PSG",
            "created_at": "2026-01-17T14:00:00Z",
            "history": [
                {
                    "id": 3,
                    "energy_score": "high",
                    "confidence": "70.5%",
                    "predicted_winner": "PSG",
                    "created_at": "2026-01-17T14:00:00Z"
                },
                {
                    "id": 2,
                    "energy_score": "medium",
                    "confidence": "60.0%",
                    "predicted_winner": "PSG",
                    "created_at": "2026-01-17T12:00:00Z"
                }
            ]
        }
    """
    service = PredictionService(db)
    prediction_details = service.get_prediction_with_details(match_id)
    
    if not prediction_details:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"No predictions found for match {match_id}"
        )
    
    return prediction_details


@router.post("/matches/{match_id}/predict", response_model=PredictionResponse, status_code=status.HTTP_201_CREATED)
def create_prediction(
    match_id: int,
    home_energy: float,
    away_energy: float,
    energy_score_label: str | None = None,
    db: Session = Depends(get_db)
):
    """
    Create a prediction for a specific match.
    
    This endpoint calculates a prediction based on energy scores for both teams
    and stores it in the database.
    
    Args:
        match_id: ID of the match to predict
        home_energy: Energy score of the home team (0.0+)
        away_energy: Energy score of the away team (0.0+)
        energy_score_label: Optional label for energy score (e.g., "high", "medium", "low")
        db: Database session (injected)
    
    Returns:
        Created prediction object
    
    Raises:
        404: If match doesn't exist
        400: If energy scores are invalid
        422: If validation fails
    
    Example Request:
        POST /api/v1/predictions/matches/1/predict?home_energy=65.0&away_energy=45.0
    
    Example Response:
        {
            "id": 1,
            "match_id": 1,
            "energy_score": "high",
            "confidence": "40.0%",
            "predicted_winner": "PSG",
            "created_at": "2026-01-17T12:00:00Z"
        }
    """
    try:
        service = PredictionService(db)
        prediction = service.create_prediction_for_match(
            match_id=match_id,
            home_energy=home_energy,
            away_energy=away_energy,
            energy_score_label=energy_score_label
        )
        return prediction.to_dict()
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to create prediction: {str(e)}"
        )


@router.get("/{prediction_id}", response_model=PredictionResponse)
def get_prediction(
    prediction_id: int,
    db: Session = Depends(get_db)
):
    """
    Get a prediction by its ID.
    
    Args:
        prediction_id: ID of the prediction to retrieve
        db: Database session (injected)
    
    Returns:
        Prediction object
    
    Raises:
        404: If prediction doesn't exist
    
    Example Request:
        GET /api/v1/predictions/1
    
    Example Response:
        {
            "id": 1,
            "match_id": 1,
            "energy_score": "high",
            "confidence": "40.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:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Prediction with id {prediction_id} not found"
        )
    
    return prediction.to_dict()


@router.get("/matches/{match_id}", response_model=PredictionListResponse)
def get_predictions_for_match(
    match_id: int,
    db: Session = Depends(get_db)
):
    """
    Get all predictions for a specific match.
    
    Args:
        match_id: ID of the match
        db: Database session (injected)
    
    Returns:
        List of predictions for the match
    
    Example Request:
        GET /api/v1/predictions/matches/1
    
    Example Response:
        {
            "data": [
                {
                    "id": 1,
                    "match_id": 1,
                    "energy_score": "high",
                    "confidence": "40.0%",
                    "predicted_winner": "PSG",
                    "created_at": "2026-01-17T12:00:00Z"
                }
            ],
            "count": 1,
            "meta": {}
        }
    """
    service = PredictionService(db)
    predictions = service.get_predictions_for_match(match_id)
    
    return {
        "data": [pred.to_dict() for pred in predictions],
        "count": len(predictions),
        "meta": {
            "match_id": match_id
        }
    }


@router.get("/matches/{match_id}/latest", response_model=PredictionResponse)
def get_latest_prediction_for_match(
    match_id: int,
    db: Session = Depends(get_db)
):
    """
    Get the most recent prediction for a specific match.
    
    Args:
        match_id: ID of the match
        db: Database session (injected)
    
    Returns:
        Latest prediction object
    
    Raises:
        404: If no predictions exist for the match
    
    Example Request:
        GET /api/v1/predictions/matches/1/latest
    
    Example Response:
        {
            "id": 3,
            "match_id": 1,
            "energy_score": "high",
            "confidence": "45.0%",
            "predicted_winner": "PSG",
            "created_at": "2026-01-17T14:00:00Z"
        }
    """
    service = PredictionService(db)
    prediction = service.get_latest_prediction_for_match(match_id)
    
    if not prediction:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"No predictions found for match {match_id}"
        )
    
    return prediction.to_dict()


@router.delete("/{prediction_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_prediction(
    prediction_id: int,
    db: Session = Depends(get_db)
):
    """
    Delete a prediction by its ID.
    
    Args:
        prediction_id: ID of the prediction to delete
        db: Database session (injected)
    
    Returns:
        No content (204)
    
    Raises:
        404: If prediction doesn't exist
    
    Example Request:
        DELETE /api/v1/predictions/1
    
    Example Response:
        (HTTP 204 No Content)
    """
    service = PredictionService(db)
    deleted = service.delete_prediction(prediction_id)
    
    if not deleted:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Prediction with id {prediction_id} not found"
        )
    
    return None
