"""
Leaderboard API Routes.

This module provides REST endpoints for retrieving user rankings
and leaderboards based on prediction accuracy.
"""

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.leaderboard_service import LeaderboardService
from app.schemas.leaderboard import LeaderboardResponse, LeaderboardEntry, PersonalRankData

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


@router.get("", response_model=LeaderboardResponse)
def get_leaderboard(
    limit: int = Query(100, ge=1, le=100, description="Maximum number of users to return (max 100)"),
    user_id: Optional[int] = Query(None, description="Current user ID to include personal rank data"),
    db: Session = Depends(get_db)
):
    """
    Get leaderboard with top 100 users sorted by accuracy.

    This endpoint retrieves the top users based on their prediction accuracy
    and includes personal rank data if user_id is provided.

    Ranking criteria:
    - Primary: Accuracy percentage (higher is better)
    - Secondary: Number of predictions viewed (more is better, used as tie-breaker)

    Args:
        limit: Maximum number of users to return (1-100, default: 100)
        user_id: Optional current user ID to include personal rank data
        db: Database session (injected)

    Returns:
        Leaderboard with top users and optional personal rank data

    Raises:
        404: If user_id provided but user doesn't exist

    Example Request:
        GET /api/v1/leaderboard
        GET /api/v1/leaderboard?user_id=1

    Example Response:
        {
            "data": [
                {
                    "user_id": 1,
                    "username": "JohnDoe",
                    "accuracy": 95.5,
                    "predictions_count": 100
                },
                {
                    "user_id": 2,
                    "username": "JaneSmith",
                    "accuracy": 90.0,
                    "predictions_count": 85
                }
            ],
            "personal_data": {
                "rank": 42,
                "accuracy": 75.5,
                "predictions_count": 25
            },
            "meta": {
                "total": 2,
                "limit": 100,
                "timestamp": "2026-01-18T10:30:00Z",
                "version": "v1"
            }
        }
    """
    service = LeaderboardService(db)
    leaderboard = service.get_leaderboard(limit=limit)

    # Get personal rank if user_id provided
    personal_data = None
    if user_id:
        personal_rank = service.get_personal_rank(user_id)
        if personal_rank:
            personal_data = PersonalRankData(**personal_rank)

    # Format leaderboard entries
    entries = [LeaderboardEntry(**entry) for entry in leaderboard]

    return {
        "data": entries,
        "personal_data": personal_data,
        "meta": {
            "total": len(entries),
            "limit": limit,
            "timestamp": datetime.utcnow().isoformat() + "Z",
            "version": "v1"
        }
    }


@router.get("/personal/{user_id}", response_model=PersonalRankData)
def get_personal_rank(
    user_id: int,
    db: Session = Depends(get_db)
):
    """
    Get personal rank data for a specific user.

    Args:
        user_id: ID of the user
        db: Database session (injected)

    Returns:
        Personal rank data with rank, accuracy, and predictions count

    Raises:
        404: If user doesn't exist or has no completed predictions

    Example Request:
        GET /api/v1/leaderboard/personal/1

    Example Response:
        {
            "rank": 42,
            "accuracy": 75.5,
            "predictions_count": 25
        }
    """
    service = LeaderboardService(db)
    personal_rank = service.get_personal_rank(user_id)

    if not personal_rank:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"User {user_id} not found or has no completed predictions"
        )

    return PersonalRankData(**personal_rank)
