# ==============================================
# Breakpilot Drive - Game API
# ==============================================
# API-Endpunkte fuer das Lernspiel:
# - Lernniveau aus Breakpilot abrufen
# - Quiz-Fragen bereitstellen
# - Spielsessions protokollieren
# - Offline-Sync unterstuetzen
#
# Mit PostgreSQL-Integration fuer persistente Speicherung.
# Fallback auf In-Memory wenn DB nicht verfuegbar.
#
# Auth: Optional via GAME_REQUIRE_AUTH=true

from fastapi import APIRouter, HTTPException, Query, Depends, Request
from pydantic import BaseModel
from typing import List, Optional, Literal, Dict, Any
from datetime import datetime
import random
import uuid
import os
import logging

logger = logging.getLogger(__name__)

# Feature flags
USE_DATABASE = os.getenv("GAME_USE_DATABASE", "true").lower() == "true"
REQUIRE_AUTH = os.getenv("GAME_REQUIRE_AUTH", "false").lower() == "true"

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


# ==============================================
# Auth Dependency (Optional)
# ==============================================

async def get_optional_current_user(request: Request) -> Optional[Dict[str, Any]]:
    """
    Optional auth dependency for Game API.

    If GAME_REQUIRE_AUTH=true: Requires valid JWT token
    If GAME_REQUIRE_AUTH=false: Returns None (anonymous access)

    In development mode without auth, returns demo user.
    """
    if not REQUIRE_AUTH:
        return None

    try:
        from auth import get_current_user
        return await get_current_user(request)
    except ImportError:
        logger.warning("Auth module not available")
        return None
    except HTTPException:
        raise  # Re-raise auth errors
    except Exception as e:
        logger.error(f"Auth error: {e}")
        raise HTTPException(status_code=401, detail="Authentication failed")


def get_user_id_from_auth(
    user: Optional[Dict[str, Any]],
    requested_user_id: str
) -> str:
    """
    Get the effective user ID, respecting auth when enabled.

    If auth is enabled and user is authenticated:
    - Returns user's own ID if requested_user_id matches
    - For parents: allows access to child IDs from token
    - For teachers: allows access to student IDs (future)

    If auth is disabled: Returns requested_user_id as-is
    """
    if not REQUIRE_AUTH or user is None:
        return requested_user_id

    user_id = user.get("user_id", "")

    # Same user - always allowed
    if requested_user_id == user_id:
        return user_id

    # Check for parent accessing child data
    children_ids = user.get("raw_claims", {}).get("children_ids", [])
    if requested_user_id in children_ids:
        return requested_user_id

    # Check for teacher accessing student data (future)
    realm_roles = user.get("realm_roles", [])
    if "lehrer" in realm_roles or "teacher" in realm_roles:
        # Teachers can access any student in their class (implement class check later)
        return requested_user_id

    # Admin bypass
    if "admin" in realm_roles:
        return requested_user_id

    # Not authorized
    raise HTTPException(
        status_code=403,
        detail="Not authorized to access this user's data"
    )


# ==============================================
# Pydantic Models
# ==============================================

class LearningLevel(BaseModel):
    """Lernniveau eines Benutzers aus dem Breakpilot-System"""
    user_id: str
    overall_level: int  # 1-5 (1=Anfaenger/Klasse 2, 5=Fortgeschritten/Klasse 6)
    math_level: float
    german_level: float
    english_level: float
    last_updated: datetime


class GameDifficulty(BaseModel):
    """Spielschwierigkeit basierend auf Lernniveau"""
    lane_speed: float  # Geschwindigkeit in m/s
    obstacle_frequency: float  # Hindernisse pro Sekunde
    power_up_chance: float  # Wahrscheinlichkeit fuer Power-Ups (0-1)
    question_complexity: int  # 1-5
    answer_time: int  # Sekunden zum Antworten
    hints_enabled: bool
    speech_speed: float  # Sprechgeschwindigkeit fuer Audio-Version


class QuizQuestion(BaseModel):
    """Quiz-Frage fuer das Spiel"""
    id: str
    question_text: str
    audio_url: Optional[str] = None
    options: List[str]  # 2-4 Antwortmoeglichkeiten
    correct_index: int  # 0-3
    difficulty: int  # 1-5
    subject: Literal["math", "german", "english", "general"]
    grade_level: Optional[int] = None  # 2-6
    # NEU: Quiz-Modus
    quiz_mode: Literal["quick", "pause"] = "quick"  # quick=waehrend Fahrt, pause=Spiel haelt an
    visual_trigger: Optional[str] = None  # z.B. "bridge", "house", "tree" - loest Frage aus
    time_limit_seconds: Optional[float] = None  # Zeit bis Antwort noetig (bei quick)


class QuizAnswer(BaseModel):
    """Antwort auf eine Quiz-Frage"""
    question_id: str
    selected_index: int
    answer_time_ms: int  # Zeit bis zur Antwort in ms
    was_correct: bool


class GameSession(BaseModel):
    """Spielsession-Daten fuer Analytics"""
    user_id: str
    game_mode: Literal["video", "audio"]
    duration_seconds: int
    distance_traveled: float
    score: int
    questions_answered: int
    questions_correct: int
    difficulty_level: int
    quiz_answers: Optional[List[QuizAnswer]] = None


class SessionResponse(BaseModel):
    """Antwort nach Session-Speicherung"""
    session_id: str
    status: str
    new_level: Optional[int] = None  # Falls Lernniveau angepasst wurde


# ==============================================
# Schwierigkeits-Mapping
# ==============================================

DIFFICULTY_MAPPING = {
    1: GameDifficulty(
        lane_speed=3.0,
        obstacle_frequency=0.3,
        power_up_chance=0.4,
        question_complexity=1,
        answer_time=15,
        hints_enabled=True,
        speech_speed=0.8
    ),
    2: GameDifficulty(
        lane_speed=4.0,
        obstacle_frequency=0.4,
        power_up_chance=0.35,
        question_complexity=2,
        answer_time=12,
        hints_enabled=True,
        speech_speed=0.9
    ),
    3: GameDifficulty(
        lane_speed=5.0,
        obstacle_frequency=0.5,
        power_up_chance=0.3,
        question_complexity=3,
        answer_time=10,
        hints_enabled=True,
        speech_speed=1.0
    ),
    4: GameDifficulty(
        lane_speed=6.0,
        obstacle_frequency=0.6,
        power_up_chance=0.25,
        question_complexity=4,
        answer_time=8,
        hints_enabled=False,
        speech_speed=1.1
    ),
    5: GameDifficulty(
        lane_speed=7.0,
        obstacle_frequency=0.7,
        power_up_chance=0.2,
        question_complexity=5,
        answer_time=6,
        hints_enabled=False,
        speech_speed=1.2
    ),
}

# ==============================================
# Beispiel Quiz-Fragen (spaeter aus DB laden)
# ==============================================

SAMPLE_QUESTIONS = [
    # ==============================================
    # QUICK QUESTIONS (waehrend der Fahrt, visuell getriggert)
    # ==============================================

    # Englisch Vokabeln - Objekte im Spiel (QUICK MODE)
    QuizQuestion(
        id="vq-bridge", question_text="What is this?",
        options=["Bridge", "House"], correct_index=0,
        difficulty=1, subject="english", grade_level=3,
        quiz_mode="quick", visual_trigger="bridge", time_limit_seconds=3.0
    ),
    QuizQuestion(
        id="vq-tree", question_text="What is this?",
        options=["Tree", "Flower"], correct_index=0,
        difficulty=1, subject="english", grade_level=3,
        quiz_mode="quick", visual_trigger="tree", time_limit_seconds=3.0
    ),
    QuizQuestion(
        id="vq-house", question_text="What is this?",
        options=["House", "Car"], correct_index=0,
        difficulty=1, subject="english", grade_level=3,
        quiz_mode="quick", visual_trigger="house", time_limit_seconds=3.0
    ),
    QuizQuestion(
        id="vq-car", question_text="What is this?",
        options=["Car", "Bus"], correct_index=0,
        difficulty=1, subject="english", grade_level=3,
        quiz_mode="quick", visual_trigger="car", time_limit_seconds=2.5
    ),
    QuizQuestion(
        id="vq-mountain", question_text="What is this?",
        options=["Hill", "Mountain", "Valley"], correct_index=1,
        difficulty=2, subject="english", grade_level=4,
        quiz_mode="quick", visual_trigger="mountain", time_limit_seconds=3.5
    ),
    QuizQuestion(
        id="vq-river", question_text="What is this?",
        options=["Lake", "River", "Sea"], correct_index=1,
        difficulty=2, subject="english", grade_level=4,
        quiz_mode="quick", visual_trigger="river", time_limit_seconds=3.5
    ),

    # Schnelle Rechenaufgaben (QUICK MODE)
    QuizQuestion(
        id="mq-1", question_text="3 + 4 = ?",
        options=["6", "7"], correct_index=1,
        difficulty=1, subject="math", grade_level=2,
        quiz_mode="quick", time_limit_seconds=4.0
    ),
    QuizQuestion(
        id="mq-2", question_text="5 x 2 = ?",
        options=["10", "12"], correct_index=0,
        difficulty=1, subject="math", grade_level=2,
        quiz_mode="quick", time_limit_seconds=4.0
    ),
    QuizQuestion(
        id="mq-3", question_text="8 - 3 = ?",
        options=["4", "5"], correct_index=1,
        difficulty=1, subject="math", grade_level=2,
        quiz_mode="quick", time_limit_seconds=3.5
    ),
    QuizQuestion(
        id="mq-4", question_text="6 x 7 = ?",
        options=["42", "48"], correct_index=0,
        difficulty=2, subject="math", grade_level=3,
        quiz_mode="quick", time_limit_seconds=5.0
    ),
    QuizQuestion(
        id="mq-5", question_text="9 x 8 = ?",
        options=["72", "64"], correct_index=0,
        difficulty=3, subject="math", grade_level=4,
        quiz_mode="quick", time_limit_seconds=5.0
    ),

    # ==============================================
    # PAUSE QUESTIONS (Spiel haelt an, mehr Zeit)
    # ==============================================

    # Mathe Level 1-2 (Klasse 2-3) - PAUSE MODE
    QuizQuestion(
        id="mp1-1", question_text="Anna hat 5 Aepfel. Sie bekommt 3 dazu. Wie viele hat sie jetzt?",
        options=["6", "7", "8", "9"], correct_index=2,
        difficulty=1, subject="math", grade_level=2,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="mp2-1", question_text="Ein Bus hat 24 Sitze. 18 sind besetzt. Wie viele sind frei?",
        options=["4", "5", "6", "7"], correct_index=2,
        difficulty=2, subject="math", grade_level=3,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="mp2-2", question_text="Was ist 45 + 27?",
        options=["72", "62", "82", "70"], correct_index=0,
        difficulty=2, subject="math", grade_level=3,
        quiz_mode="pause"
    ),

    # Mathe Level 3-4 (Klasse 4-5) - PAUSE MODE
    QuizQuestion(
        id="mp3-1", question_text="Was ist 7 x 8?",
        options=["54", "56", "58", "48"], correct_index=1,
        difficulty=3, subject="math", grade_level=4,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="mp3-2", question_text="Ein Rechteck ist 8m lang und 5m breit. Wie gross ist die Flaeche?",
        options=["35 m2", "40 m2", "45 m2", "26 m2"], correct_index=1,
        difficulty=3, subject="math", grade_level=4,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="mp4-1", question_text="Was ist 15% von 80?",
        options=["10", "12", "8", "15"], correct_index=1,
        difficulty=4, subject="math", grade_level=5,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="mp4-2", question_text="Was ist 3/4 + 1/2?",
        options=["5/4", "4/6", "1", "5/6"], correct_index=0,
        difficulty=4, subject="math", grade_level=5,
        quiz_mode="pause"
    ),

    # Mathe Level 5 (Klasse 6) - PAUSE MODE
    QuizQuestion(
        id="mp5-1", question_text="Was ist (-5) x (-3)?",
        options=["-15", "15", "-8", "8"], correct_index=1,
        difficulty=5, subject="math", grade_level=6,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="mp5-2", question_text="Loesung von 2x + 5 = 11?",
        options=["2", "3", "4", "6"], correct_index=1,
        difficulty=5, subject="math", grade_level=6,
        quiz_mode="pause"
    ),

    # Deutsch - PAUSE MODE (brauchen Lesezeit)
    QuizQuestion(
        id="dp1-1", question_text="Welches Wort ist ein Nomen?",
        options=["laufen", "schnell", "Hund", "und"], correct_index=2,
        difficulty=1, subject="german", grade_level=2,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="dp2-1", question_text="Was ist die Mehrzahl von 'Haus'?",
        options=["Haeuse", "Haeuser", "Hausern", "Haus"], correct_index=1,
        difficulty=2, subject="german", grade_level=3,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="dp3-1", question_text="Welches Verb steht im Praeteritum?",
        options=["geht", "ging", "gegangen", "gehen"], correct_index=1,
        difficulty=3, subject="german", grade_level=4,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="dp3-2", question_text="Finde den Rechtschreibfehler: 'Der Hund leuft schnell.'",
        options=["Hund", "leuft", "schnell", "Der"], correct_index=1,
        difficulty=3, subject="german", grade_level=4,
        quiz_mode="pause"
    ),

    # Englisch Saetze - PAUSE MODE
    QuizQuestion(
        id="ep3-1", question_text="How do you say 'Schmetterling'?",
        options=["bird", "bee", "butterfly", "beetle"], correct_index=2,
        difficulty=3, subject="english", grade_level=4,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="ep4-1", question_text="Choose the correct form: She ___ to school.",
        options=["go", "goes", "going", "gone"], correct_index=1,
        difficulty=4, subject="english", grade_level=5,
        quiz_mode="pause"
    ),
    QuizQuestion(
        id="ep4-2", question_text="What is the past tense of 'run'?",
        options=["runned", "ran", "runed", "running"], correct_index=1,
        difficulty=4, subject="english", grade_level=5,
        quiz_mode="pause"
    ),
]

# In-Memory Session Storage (Fallback wenn DB nicht verfuegbar)
_sessions: dict[str, GameSession] = {}
_user_levels: dict[str, LearningLevel] = {}

# Database integration
_game_db = None

async def get_game_database():
    """Get game database instance with lazy initialization."""
    global _game_db
    if not USE_DATABASE:
        return None
    if _game_db is None:
        try:
            from game.database import get_game_db
            _game_db = await get_game_db()
            logger.info("Game database initialized")
        except Exception as e:
            logger.warning(f"Game database not available, using in-memory: {e}")
    return _game_db


# ==============================================
# API Endpunkte
# ==============================================

@router.get("/learning-level/{user_id}", response_model=LearningLevel)
async def get_learning_level(
    user_id: str,
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> LearningLevel:
    """
    Holt das aktuelle Lernniveau eines Benutzers aus Breakpilot.

    - Wird beim Spielstart aufgerufen um Schwierigkeit anzupassen
    - Gibt Level 1-5 zurueck (1=Anfaenger, 5=Fortgeschritten)
    - Cached Werte fuer schnellen Zugriff
    - Speichert in PostgreSQL wenn verfuegbar
    - 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:
        state = await db.get_learning_state(user_id)
        if state:
            return LearningLevel(
                user_id=user_id,
                overall_level=state.overall_level,
                math_level=state.math_level,
                german_level=state.german_level,
                english_level=state.english_level,
                last_updated=state.updated_at or datetime.now()
            )

        # Create new state in database
        new_state = await db.create_or_update_learning_state(
            student_id=user_id,
            overall_level=3,
            math_level=3.0,
            german_level=3.0,
            english_level=3.0
        )
        if new_state:
            return LearningLevel(
                user_id=user_id,
                overall_level=new_state.overall_level,
                math_level=new_state.math_level,
                german_level=new_state.german_level,
                english_level=new_state.english_level,
                last_updated=new_state.updated_at or datetime.now()
            )

    # Fallback to in-memory
    if user_id in _user_levels:
        return _user_levels[user_id]

    # Standard-Level fuer neue Benutzer
    default_level = LearningLevel(
        user_id=user_id,
        overall_level=3,  # Mittleres Level als Default
        math_level=3.0,
        german_level=3.0,
        english_level=3.0,
        last_updated=datetime.now()
    )
    _user_levels[user_id] = default_level
    return default_level


@router.get("/difficulty/{level}", response_model=GameDifficulty)
async def get_game_difficulty(level: int) -> GameDifficulty:
    """
    Gibt Spielparameter basierend auf Lernniveau zurueck.

    Level 1-5 werden auf Spielgeschwindigkeit, Hindernisfrequenz,
    Fragen-Schwierigkeit etc. gemappt.
    """
    if level < 1 or level > 5:
        raise HTTPException(status_code=400, detail="Level muss zwischen 1 und 5 sein")

    return DIFFICULTY_MAPPING[level]


@router.get("/quiz/questions", response_model=List[QuizQuestion])
async def get_quiz_questions(
    difficulty: int = Query(3, ge=1, le=5, description="Schwierigkeitsgrad 1-5"),
    count: int = Query(10, ge=1, le=50, description="Anzahl der Fragen"),
    subject: Optional[str] = Query(None, description="Fach: math, german, english, oder None fuer gemischt"),
    mode: Optional[str] = Query(None, description="Quiz-Modus: quick (waehrend Fahrt), pause (Spiel pausiert), oder None fuer beide")
) -> List[QuizQuestion]:
    """
    Holt Quiz-Fragen fuer das Spiel.

    - Filtert nach Schwierigkeitsgrad (+/- 1 Level)
    - Optional nach Fach filterbar
    - Optional nach Modus: "quick" (visuelle Fragen waehrend Fahrt) oder "pause" (Denkaufgaben)
    - Gibt zufaellige Auswahl zurueck
    """
    # Fragen nach Schwierigkeit filtern (+/- 1 Level Toleranz)
    filtered = [
        q for q in SAMPLE_QUESTIONS
        if abs(q.difficulty - difficulty) <= 1
        and (subject is None or q.subject == subject)
        and (mode is None or q.quiz_mode == mode)
    ]

    if not filtered:
        # Fallback: Alle Fragen wenn keine passenden gefunden
        filtered = [q for q in SAMPLE_QUESTIONS if mode is None or q.quiz_mode == mode]

    # Zufaellige Auswahl
    selected = random.sample(filtered, min(count, len(filtered)))
    return selected


@router.get("/quiz/visual-triggers")
async def get_visual_triggers() -> List[dict]:
    """
    Gibt alle verfuegbaren visuellen Trigger zurueck.

    Unity verwendet diese Liste um zu wissen, welche Objekte
    im Spiel Quiz-Fragen ausloesen koennen.
    """
    triggers = {}
    for q in SAMPLE_QUESTIONS:
        if q.visual_trigger and q.quiz_mode == "quick":
            if q.visual_trigger not in triggers:
                triggers[q.visual_trigger] = {
                    "trigger": q.visual_trigger,
                    "question_count": 0,
                    "difficulties": set(),
                    "subjects": set()
                }
            triggers[q.visual_trigger]["question_count"] += 1
            triggers[q.visual_trigger]["difficulties"].add(q.difficulty)
            triggers[q.visual_trigger]["subjects"].add(q.subject)

    # Sets zu Listen konvertieren fuer JSON
    return [
        {
            "trigger": t["trigger"],
            "question_count": t["question_count"],
            "difficulties": list(t["difficulties"]),
            "subjects": list(t["subjects"])
        }
        for t in triggers.values()
    ]


@router.post("/quiz/answer")
async def submit_quiz_answer(answer: QuizAnswer) -> dict:
    """
    Verarbeitet eine Quiz-Antwort (fuer Echtzeit-Feedback).

    In der finalen Version: Speichert in Session, updated Analytics.
    """
    return {
        "question_id": answer.question_id,
        "was_correct": answer.was_correct,
        "points": 500 if answer.was_correct else -100,
        "message": "Richtig! Weiter so!" if answer.was_correct else "Nicht ganz, versuch es nochmal!"
    }


@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)
    }


# ==============================================
# Phase 5: Erweiterte Features
# ==============================================

@router.get("/achievements/{user_id}")
async def get_achievements(
    user_id: str,
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> dict:
    """
    Gibt Achievements mit Fortschritt fuer einen Benutzer zurueck.

    Achievements werden basierend auf Spielstatistiken berechnet.
    """
    # Verify access rights
    user_id = get_user_id_from_auth(user, user_id)

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

    try:
        achievements = await db.get_student_achievements(user_id)

        unlocked = [a for a in achievements if a.unlocked]
        locked = [a for a in achievements if not a.unlocked]

        return {
            "user_id": user_id,
            "total": len(achievements),
            "unlocked_count": len(unlocked),
            "achievements": [
                {
                    "id": a.id,
                    "name": a.name,
                    "description": a.description,
                    "icon": a.icon,
                    "category": a.category,
                    "threshold": a.threshold,
                    "progress": a.progress,
                    "unlocked": a.unlocked,
                }
                for a in achievements
            ]
        }
    except Exception as e:
        logger.error(f"Failed to get achievements: {e}")
        return {"achievements": [], "message": str(e)}


@router.get("/progress/{user_id}")
async def get_progress(
    user_id: str,
    days: int = Query(30, ge=7, le=90, description="Anzahl Tage zurueck"),
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> dict:
    """
    Gibt Lernfortschritt ueber Zeit zurueck (fuer Charts).

    - Taegliche Statistiken
    - Fuer Eltern-Dashboard und Fortschrittsanzeige
    """
    # Verify access rights
    user_id = get_user_id_from_auth(user, user_id)

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

    try:
        progress = await db.get_progress_over_time(user_id, days)
        return {
            "user_id": user_id,
            "days": days,
            "data_points": len(progress),
            "progress": progress,
        }
    except Exception as e:
        logger.error(f"Failed to get progress: {e}")
        return {"progress": [], "message": str(e)}


@router.get("/parent/children")
async def get_children_dashboard(
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> dict:
    """
    Eltern-Dashboard: Statistiken fuer alle Kinder.

    Erfordert Auth mit Eltern-Rolle und children_ids Claim.
    """
    if not REQUIRE_AUTH or user is None:
        return {
            "message": "Auth required for parent dashboard",
            "children": []
        }

    # Get children IDs from token
    children_ids = user.get("raw_claims", {}).get("children_ids", [])

    if not children_ids:
        return {
            "message": "No children associated with this account",
            "children": []
        }

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

    try:
        children_stats = await db.get_children_stats(children_ids)
        return {
            "parent_id": user.get("user_id"),
            "children_count": len(children_ids),
            "children": children_stats,
        }
    except Exception as e:
        logger.error(f"Failed to get children stats: {e}")
        return {"children": [], "message": str(e)}


@router.get("/leaderboard/class/{class_id}")
async def get_class_leaderboard(
    class_id: str,
    timeframe: str = Query("week", description="day, week, month, all"),
    limit: int = Query(10, ge=1, le=50),
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> List[dict]:
    """
    Klassenspezifische Rangliste.

    Nur fuer Lehrer oder Schueler der Klasse sichtbar.
    """
    db = await get_game_database()
    if not db:
        return []

    try:
        leaderboard = await db.get_class_leaderboard(class_id, timeframe, limit)
        return leaderboard
    except Exception as e:
        logger.error(f"Failed to get class leaderboard: {e}")
        return []


@router.get("/leaderboard/display")
async def get_display_leaderboard(
    timeframe: str = Query("day", description="day, week, month, all"),
    limit: int = Query(10, ge=1, le=100),
    anonymize: bool = Query(True, description="Namen anonymisieren")
) -> List[dict]:
    """
    Oeffentliche Rangliste mit Anzeigenamen.

    Standardmaessig anonymisiert fuer Datenschutz.
    """
    db = await get_game_database()
    if not db:
        return []

    try:
        return await db.get_leaderboard_with_names(timeframe, limit, anonymize)
    except Exception as e:
        logger.error(f"Failed to get display leaderboard: {e}")
        return []
