# ==============================================
# Breakpilot Drive - Game Session & Stats Routes
# ==============================================
# Session saving, leaderboard, stats, suggestions,
# quiz generation, and health check.
# Extracted from game_routes.py for file-size compliance.

from fastapi import APIRouter, HTTPException, Query, Depends, Request
from typing import List, Optional, Dict, Any
from datetime import datetime
import uuid
import logging

from .game_models import (
    LearningLevel,
    QuizQuestion,
    GameSession,
    SessionResponse,
    SAMPLE_QUESTIONS,
)

logger = logging.getLogger(__name__)

# Import shared state and helpers from game_routes
# (these are the canonical instances)
from .routes import (
    get_optional_current_user,
    get_user_id_from_auth,
    get_game_database,
    get_quiz_questions,
    _sessions,
    _user_levels,
    REQUIRE_AUTH,
)

router = APIRouter(prefix="/api/game", tags=["Breakpilot Drive"])


@router.post("/session", response_model=SessionResponse)
async def save_game_session(
    session: GameSession,
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> SessionResponse:
    """
    Speichert eine komplette Spielsession.

    - Protokolliert Score, Distanz, Fragen-Performance
    - Aktualisiert Lernniveau bei genuegend Daten
    - Wird am Ende jedes Spiels aufgerufen
    - Speichert in PostgreSQL wenn verfuegbar
    - Bei GAME_REQUIRE_AUTH=true: User-ID aus Token
    """
    # If auth is enabled, use user_id from token (ignore session.user_id)
    effective_user_id = session.user_id
    if REQUIRE_AUTH and user:
        effective_user_id = user.get("user_id", session.user_id)

    session_id = str(uuid.uuid4())

    # Lernniveau-Anpassung basierend auf Performance
    new_level = None
    old_level = 3  # Default

    # Try to get current level first
    db = await get_game_database()
    if db:
        state = await db.get_learning_state(effective_user_id)
        if state:
            old_level = state.overall_level
        else:
            # Create initial state if not exists
            await db.create_or_update_learning_state(effective_user_id)
            old_level = 3
    elif effective_user_id in _user_levels:
        old_level = _user_levels[effective_user_id].overall_level

    # Calculate level adjustment
    if session.questions_answered >= 5:
        accuracy = session.questions_correct / session.questions_answered

        # Anpassung: Wenn >80% korrekt und max nicht erreicht -> Level up
        if accuracy >= 0.8 and old_level < 5:
            new_level = old_level + 1
        # Wenn <40% korrekt und min nicht erreicht -> Level down
        elif accuracy < 0.4 and old_level > 1:
            new_level = old_level - 1

    # Save to database
    if db:
        # Save session
        db_session_id = await db.save_game_session(
            student_id=effective_user_id,
            game_mode=session.game_mode,
            duration_seconds=session.duration_seconds,
            distance_traveled=session.distance_traveled,
            score=session.score,
            questions_answered=session.questions_answered,
            questions_correct=session.questions_correct,
            difficulty_level=session.difficulty_level,
        )
        if db_session_id:
            session_id = db_session_id

            # Save individual quiz answers if provided
            if session.quiz_answers:
                for answer in session.quiz_answers:
                    await db.save_quiz_answer(
                        session_id=session_id,
                        question_id=answer.question_id,
                        subject="general",  # Could be enhanced to track actual subject
                        difficulty=session.difficulty_level,
                        is_correct=answer.was_correct,
                        answer_time_ms=answer.answer_time_ms,
                    )

        # Update learning stats
        duration_minutes = session.duration_seconds // 60
        await db.update_learning_stats(
            student_id=effective_user_id,
            duration_minutes=duration_minutes,
            questions_answered=session.questions_answered,
            questions_correct=session.questions_correct,
            new_level=new_level,
        )
    else:
        # Fallback to in-memory
        _sessions[session_id] = session

        if new_level:
            _user_levels[effective_user_id] = LearningLevel(
                user_id=effective_user_id,
                overall_level=new_level,
                math_level=float(new_level),
                german_level=float(new_level),
                english_level=float(new_level),
                last_updated=datetime.now()
            )

    return SessionResponse(
        session_id=session_id,
        status="saved",
        new_level=new_level
    )


@router.get("/sessions/{user_id}")
async def get_user_sessions(
    user_id: str,
    limit: int = Query(10, ge=1, le=100),
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> List[dict]:
    """
    Holt die letzten Spielsessions eines Benutzers.

    Fuer Statistiken und Fortschrittsanzeige.
    Bei GAME_REQUIRE_AUTH=true: Nur eigene oder Kind-Daten.
    """
    # Verify access rights
    user_id = get_user_id_from_auth(user, user_id)

    # Try database first
    db = await get_game_database()
    if db:
        sessions = await db.get_user_sessions(user_id, limit)
        if sessions:
            return sessions

    # Fallback to in-memory
    user_sessions = [
        {"session_id": sid, **s.model_dump()}
        for sid, s in _sessions.items()
        if s.user_id == user_id
    ]
    return user_sessions[:limit]


@router.get("/leaderboard")
async def get_leaderboard(
    timeframe: str = Query("day", description="day, week, month, all"),
    limit: int = Query(10, ge=1, le=100)
) -> List[dict]:
    """
    Gibt Highscore-Liste zurueck.

    - Sortiert nach Punktzahl
    - Optional nach Zeitraum filterbar
    """
    # Try database first
    db = await get_game_database()
    if db:
        leaderboard = await db.get_leaderboard(timeframe, limit)
        if leaderboard:
            return leaderboard

    # Fallback to in-memory
    # Aggregiere Scores pro User
    user_scores: dict[str, int] = {}
    for session in _sessions.values():
        if session.user_id not in user_scores:
            user_scores[session.user_id] = 0
        user_scores[session.user_id] += session.score

    # Sortieren und limitieren
    leaderboard = [
        {"rank": i + 1, "user_id": uid, "total_score": score}
        for i, (uid, score) in enumerate(
            sorted(user_scores.items(), key=lambda x: x[1], reverse=True)[:limit]
        )
    ]

    return leaderboard


@router.get("/stats/{user_id}")
async def get_user_stats(
    user_id: str,
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> dict:
    """
    Gibt detaillierte Statistiken fuer einen Benutzer zurueck.

    - Gesamtstatistiken
    - Fach-spezifische Statistiken
    - Lernniveau-Verlauf
    - Bei GAME_REQUIRE_AUTH=true: Nur eigene oder Kind-Daten
    """
    # Verify access rights
    user_id = get_user_id_from_auth(user, user_id)

    db = await get_game_database()
    if db:
        state = await db.get_learning_state(user_id)
        subject_stats = await db.get_subject_stats(user_id)

        if state:
            return {
                "user_id": user_id,
                "overall_level": state.overall_level,
                "math_level": state.math_level,
                "german_level": state.german_level,
                "english_level": state.english_level,
                "total_play_time_minutes": state.total_play_time_minutes,
                "total_sessions": state.total_sessions,
                "questions_answered": state.questions_answered,
                "questions_correct": state.questions_correct,
                "accuracy": state.accuracy,
                "subjects": subject_stats,
            }

    # Fallback - return defaults
    return {
        "user_id": user_id,
        "overall_level": 3,
        "math_level": 3.0,
        "german_level": 3.0,
        "english_level": 3.0,
        "total_play_time_minutes": 0,
        "total_sessions": 0,
        "questions_answered": 0,
        "questions_correct": 0,
        "accuracy": 0.0,
        "subjects": {},
    }


@router.get("/suggestions/{user_id}")
async def get_learning_suggestions(
    user_id: str,
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> dict:
    """
    Gibt adaptive Lernvorschlaege fuer einen Benutzer zurueck.

    Basierend auf aktueller Performance und Lernhistorie.
    Bei GAME_REQUIRE_AUTH=true: Nur eigene oder Kind-Daten.
    """
    # Verify access rights
    user_id = get_user_id_from_auth(user, user_id)

    db = await get_game_database()
    if not db:
        return {"suggestions": [], "message": "Database not available"}

    state = await db.get_learning_state(user_id)
    if not state:
        return {"suggestions": [], "message": "No learning state found"}

    try:
        from game.learning_rules import (
            LearningContext,
            get_rule_engine,
        )

        # Create context from state
        context = LearningContext.from_learning_state(state)

        # Get suggestions from rule engine
        engine = get_rule_engine()
        suggestions = engine.evaluate(context)

        return {
            "user_id": user_id,
            "overall_level": state.overall_level,
            "suggestions": [
                {
                    "title": s.title,
                    "description": s.description,
                    "action": s.action.value,
                    "priority": s.priority.name.lower(),
                    "metadata": s.metadata or {},
                }
                for s in suggestions[:3]  # Top 3 suggestions
            ]
        }
    except ImportError:
        return {"suggestions": [], "message": "Learning rules not available"}
    except Exception as e:
        logger.warning(f"Failed to get suggestions: {e}")
        return {"suggestions": [], "message": str(e)}


@router.get("/quiz/generate")
async def generate_quiz_questions(
    difficulty: int = Query(3, ge=1, le=5, description="Schwierigkeitsgrad 1-5"),
    count: int = Query(5, ge=1, le=20, description="Anzahl der Fragen"),
    subject: Optional[str] = Query(None, description="Fach: math, german, english"),
    mode: str = Query("quick", description="Quiz-Modus: quick oder pause"),
    visual_trigger: Optional[str] = Query(None, description="Visueller Trigger: bridge, tree, house, etc.")
) -> List[dict]:
    """
    Generiert Quiz-Fragen dynamisch via LLM.

    Fallback auf statische Fragen wenn LLM nicht verfuegbar.
    """
    try:
        from game.quiz_generator import get_quiz_generator

        generator = await get_quiz_generator()
        questions = await generator.get_questions(
            difficulty=difficulty,
            subject=subject or "general",
            mode=mode,
            count=count,
            visual_trigger=visual_trigger
        )

        if questions:
            return [
                {
                    "id": f"gen-{i}",
                    "question_text": q.question_text,
                    "options": q.options,
                    "correct_index": q.correct_index,
                    "difficulty": q.difficulty,
                    "subject": q.subject,
                    "grade_level": q.grade_level,
                    "quiz_mode": q.quiz_mode,
                    "visual_trigger": q.visual_trigger,
                    "time_limit_seconds": q.time_limit_seconds,
                }
                for i, q in enumerate(questions)
            ]
    except ImportError:
        logger.info("Quiz generator not available, using static questions")
    except Exception as e:
        logger.warning(f"Quiz generation failed: {e}")

    # Fallback to static questions
    return await get_quiz_questions(difficulty, count, subject, mode)


@router.get("/health")
async def health_check() -> dict:
    """Health-Check fuer das Spiel-Backend."""
    db = await get_game_database()
    db_status = "connected" if db and db._connected else "disconnected"

    # Check LLM availability
    llm_status = "disabled"
    try:
        from game.quiz_generator import get_quiz_generator
        generator = await get_quiz_generator()
        llm_status = "connected" if generator._llm_available else "disconnected"
    except:
        pass

    return {
        "status": "healthy",
        "service": "breakpilot-drive",
        "database": db_status,
        "llm_generator": llm_status,
        "auth_required": REQUIRE_AUTH,
        "questions_available": len(SAMPLE_QUESTIONS),
        "active_sessions": len(_sessions)
    }
