from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import select, func
from sqlalchemy.orm import selectinload
from typing import Optional
import secrets

from app.core.deps import DB, CurrentUser, require_any_authenticated
from app.models.game import (
    Game, GameCategory, GameTopic, GameLevel,
    GameSession, SessionPlayer, SessionTeam, PlayerResponse,
)
from app.models.academic import Topic, TopicLevel, Question, AnswerOption, Package
from app.models.progress import PlayerProgress
from app.schemas.game import (
    CreateSessionRequest, JoinSessionRequest, SessionOut,
    SubmitAnswerRequest, CompleteSessionRequest,
)

router = APIRouter(
    prefix="/games", tags=["Games"], dependencies=[Depends(require_any_authenticated)]
)

# ===================== CATALOGUE (READ-ONLY) =====================

@router.get("/categories", summary="List Game Categories")
async def list_categories(db: DB):
    """All active game categories (e.g. Home, School, Market)."""
    result = await db.execute(
        select(GameCategory)
        .where(GameCategory.is_active == True)
        .order_by(GameCategory.name)
    )
    cats = result.scalars().all()
    return [
        {
            "id": c.id, "name": c.name, "slug": c.slug,
            "description": c.description, "icon": c.icon,
            "color_hex": c.color_hex,
        }
        for c in cats
    ]


@router.get("/categories/{cat_id}", summary="Get Category with its Games")
async def get_category_games(cat_id: int, db: DB):
    """Return a single category and all active games that belong to it."""
    cat_res = await db.execute(
        select(GameCategory).where(GameCategory.id == cat_id, GameCategory.is_active == True)
    )
    cat = cat_res.scalar_one_or_none()
    if not cat:
        raise HTTPException(status_code=404, detail="Category not found")

    games_res = await db.execute(
        select(Game)
        .where(Game.category_id == cat_id, Game.is_active == True)
        .order_by(Game.name)
    )
    games = games_res.scalars().all()
    return {
        "id": cat.id,
        "name": cat.name,
        "slug": cat.slug,
        "description": cat.description,
        "icon": cat.icon,
        "color_hex": cat.color_hex,
        "games": [
            {
                "id": g.id,
                "name": g.name,
                "slug": g.slug,
                "description": g.description,
                "artwork_url": g.artwork_url,
                "intro_video_url": g.intro_video_url,
                "game_type_id": g.game_type_id,
            }
            for g in games
        ],
    }


@router.get("/", summary="Browse Available Games")
async def list_games(
    db: DB,
    category_id: Optional[int] = None,
    game_type_id: Optional[int] = None,
):
    """List all active games, optionally filtered by category or type."""
    query = (
        select(Game)
        .options(selectinload(Game.category))
        .where(Game.is_active == True)
    )
    if category_id:
        query = query.where(Game.category_id == category_id)
    if game_type_id:
        query = query.where(Game.game_type_id == game_type_id)
    result = await db.execute(query.order_by(Game.name))
    games = result.scalars().all()
    return [
        {
            "id": g.id,
            "name": g.name,
            "slug": g.slug,
            "description": g.description,
            "artwork_url": g.artwork_url,
            "intro_video_url": g.intro_video_url,
            "game_type_id": g.game_type_id,
            "category_id": g.category_id,
            "category_name": g.category.name if g.category else None,
            "category_icon": g.category.icon if g.category else None,
            "category_color": g.category.color_hex if g.category else None,
        }
        for g in games
    ]


@router.get("/{game_id}", summary="Get Game Details with Topics and Levels")
async def get_game(game_id: int, db: DB):
    """Full game detail including category, all topics, and all levels per topic."""
    g_res = await db.execute(
        select(Game)
        .options(selectinload(Game.category))
        .where(Game.id == game_id, Game.is_active == True)
    )
    g = g_res.scalar_one_or_none()
    if not g:
        raise HTTPException(status_code=404, detail="Game not found")

    # Load topics
    t_res = await db.execute(
        select(GameTopic)
        .where(GameTopic.game_id == game_id, GameTopic.is_active == True)
        .order_by(GameTopic.sequence_order)
    )
    topics = t_res.scalars().all()

    # Load levels per topic with academic metadata
    topics_out = []
    for t in topics:
        l_res = await db.execute(
            select(GameLevel)
            .where(GameLevel.game_topic_id == t.id, GameLevel.is_active == True)
            .order_by(GameLevel.sequence_order)
        )
        levels = l_res.scalars().all()

        levels_out = []
        for gl in levels:
            tl = None
            if gl.topic_level_id:
                tl_res = await db.execute(
                    select(TopicLevel).where(TopicLevel.id == gl.topic_level_id)
                )
                tl = tl_res.scalar_one_or_none()

            # count questions if linked
            q_count = 0
            if tl:
                q_count_res = await db.execute(
                    select(func.count(Question.id)).where(
                        Question.level_id == tl.id, Question.is_active == True
                    )
                )
                q_count = q_count_res.scalar() or 0

            levels_out.append({
                "id": gl.id,
                "title": gl.title,
                "description": gl.description,
                "instructions": gl.instructions,
                "tag": gl.tag,
                "sequence_order": gl.sequence_order,
                "topic_level_id": gl.topic_level_id,
                "level_number": tl.level_number if tl else None,
                "xp_reward": tl.xp_reward if tl else None,
                "passing_score": tl.passing_score if tl else None,
                "time_limit_seconds": tl.time_limit_seconds if tl else None,
                "stars_max": tl.stars_max if tl else None,
                "question_count": q_count,
            })

        topics_out.append({
            "id": t.id,
            "name": t.name,
            "slug": t.slug,
            "description": t.description,
            "location_name": t.location_name,
            "icon_url": t.icon_url,
            "background_url": t.background_url,
            "color_hex": t.color_hex,
            "sequence_order": t.sequence_order,
            "levels": levels_out,
        })

    return {
        "id": g.id,
        "name": g.name,
        "slug": g.slug,
        "description": g.description,
        "instructions": g.instructions,
        "artwork_url": g.artwork_url,
        "intro_video_url": g.intro_video_url,
        "game_type_id": g.game_type_id,
        "category_id": g.category_id,
        "category_name": g.category.name if g.category else None,
        "category_icon": g.category.icon if g.category else None,
        "category_color": g.category.color_hex if g.category else None,
        "topics": topics_out,
    }


@router.get("/{game_id}/topics", summary="List Topics / Locations in a Game")
async def get_game_topics(game_id: int, db: DB):
    """
    Returns all active topics (locations/modules) for a game, ordered by sequence.
    Each topic groups a set of levels.
    """
    result = await db.execute(
        select(GameTopic)
        .where(GameTopic.game_id == game_id, GameTopic.is_active == True)
        .order_by(GameTopic.sequence_order)
    )
    topics = result.scalars().all()
    return [
        {
            "id": t.id,
            "name": t.name,
            "slug": t.slug,
            "description": t.description,
            "location_name": t.location_name,
            "icon_url": t.icon_url,
            "background_url": t.background_url,
            "color_hex": t.color_hex,
            "sequence_order": t.sequence_order,
        }
        for t in topics
    ]


@router.get("/{game_id}/topics/{topic_id}/levels", summary="List Levels in a Game Topic")
async def get_topic_levels(game_id: int, topic_id: int, db: DB):
    """
    List all active game levels under a specific topic.
    Includes academic level metadata (XP, stars, time limit) when linked.
    """
    # Verify topic belongs to game
    t_res = await db.execute(
        select(GameTopic).where(
            GameTopic.id == topic_id, GameTopic.game_id == game_id, GameTopic.is_active == True
        )
    )
    if not t_res.scalar_one_or_none():
        raise HTTPException(status_code=404, detail="Topic not found in this game")

    result = await db.execute(
        select(GameLevel)
        .where(GameLevel.game_topic_id == topic_id, GameLevel.is_active == True)
        .order_by(GameLevel.sequence_order)
    )
    levels = result.scalars().all()

    out = []
    for gl in levels:
        tl = None
        if gl.topic_level_id:
            tl_res = await db.execute(
                select(TopicLevel).where(TopicLevel.id == gl.topic_level_id)
            )
            tl = tl_res.scalar_one_or_none()
        out.append({
            "id": gl.id,
            "title": gl.title,
            "description": gl.description,
            "instructions": gl.instructions,
            "tag": gl.tag,
            "sequence_order": gl.sequence_order,
            "topic_level_id": gl.topic_level_id,
            # academic metadata (null for game-only levels)
            "level_number": tl.level_number if tl else None,
            "xp_reward": tl.xp_reward if tl else None,
            "passing_score": tl.passing_score if tl else None,
            "time_limit_seconds": tl.time_limit_seconds if tl else None,
            "stars_max": tl.stars_max if tl else None,
        })
    return out


@router.get("/{game_id}/levels", summary="Get All Game Levels (flat list)")
async def get_game_levels(game_id: int, db: DB):
    """Flat list of all active levels for a game, used for session creation."""
    result = await db.execute(
        select(GameLevel)
        .where(GameLevel.game_id == game_id, GameLevel.is_active == True)
        .order_by(GameLevel.sequence_order)
    )
    levels = result.scalars().all()
    out = []
    for gl in levels:
        tl = None
        if gl.topic_level_id:
            tl_res = await db.execute(
                select(TopicLevel).where(TopicLevel.id == gl.topic_level_id)
            )
            tl = tl_res.scalar_one_or_none()
        out.append({
            "id": gl.id,
            "game_topic_id": gl.game_topic_id,
            "title": gl.title,
            "tag": gl.tag,
            "sequence_order": gl.sequence_order,
            "topic_level_id": gl.topic_level_id,
            "level_number": tl.level_number if tl else None,
            "xp_reward": tl.xp_reward if tl else None,
            "passing_score": tl.passing_score if tl else None,
            "time_limit_seconds": tl.time_limit_seconds if tl else None,
            "stars_max": tl.stars_max if tl else None,
        })
    return out


@router.get("/{game_id}/levels/{level_id}", summary="Get Level Detail with Questions")
async def get_game_level_detail(game_id: int, level_id: int, db: DB):
    """
    Full detail for one game level: metadata + all questions with answer options.
    Correct answer flag is NOT included — only revealed after answer submission.
    """
    gl_res = await db.execute(
        select(GameLevel).where(
            GameLevel.id == level_id,
            GameLevel.game_id == game_id,
            GameLevel.is_active == True,
        )
    )
    gl = gl_res.scalar_one_or_none()
    if not gl:
        raise HTTPException(status_code=404, detail="Level not found")

    # Academic metadata
    tl = None
    if gl.topic_level_id:
        tl_res = await db.execute(
            select(TopicLevel).where(TopicLevel.id == gl.topic_level_id)
        )
        tl = tl_res.scalar_one_or_none()

    # Questions + answers
    questions_out = []
    if tl:
        q_res = await db.execute(
            select(Question)
            .where(Question.level_id == tl.id, Question.is_active == True)
            .order_by(Question.sequence_order)
        )
        for q in q_res.scalars().all():
            a_res = await db.execute(
                select(AnswerOption)
                .where(AnswerOption.question_id == q.id)
                .order_by(AnswerOption.display_order)
            )
            questions_out.append({
                "id": q.id,
                "question_text": q.question_text,
                "question_type": q.question_type,
                "difficulty": q.difficulty,
                "time_limit_seconds": q.time_limit_seconds,
                "points": q.points,
                "hint_text": q.hint_text,
                "media_url": q.media_url,
                "tag": q.tag,
                "answers": [
                    {
                        "id": a.id,
                        "answer_text": a.answer_text,
                        "display_order": a.display_order,
                        "asset_2d_id": a.asset_2d_id,
                        "asset_3d_id": a.asset_3d_id,
                        "asset_vr_id": a.asset_vr_id,
                        "asset_group": a.asset_group,
                        "monetary_value": str(a.monetary_value) if a.monetary_value else None,
                        "quantity": a.quantity,
                    }
                    for a in a_res.scalars().all()
                ],
            })

    return {
        "id": gl.id,
        "game_id": gl.game_id,
        "game_topic_id": gl.game_topic_id,
        "title": gl.title,
        "description": gl.description,
        "instructions": gl.instructions,
        "tag": gl.tag,
        "sequence_order": gl.sequence_order,
        "topic_level_id": gl.topic_level_id,
        "level_number": tl.level_number if tl else None,
        "level_name": tl.name if tl else None,
        "xp_reward": tl.xp_reward if tl else None,
        "passing_score": tl.passing_score if tl else None,
        "time_limit_seconds": tl.time_limit_seconds if tl else None,
        "stars_max": tl.stars_max if tl else None,
        "question_count": len(questions_out),
        "questions": questions_out,
    }


# ── helper: build a question dict (no is_correct) ─────────────────────────────
async def _fmt_question_for_student(q: Question, db: DB) -> dict:
    a_res = await db.execute(
        select(AnswerOption)
        .where(AnswerOption.question_id == q.id)
        .order_by(AnswerOption.display_order)
    )
    return {
        "id": q.id,
        "question_text": q.question_text,
        "question_type": q.question_type,
        "difficulty": q.difficulty,
        "time_limit_seconds": q.time_limit_seconds,
        "points": q.points,
        "hint_text": q.hint_text,
        "media_url": q.media_url,
        "tag": q.tag,
        "answers": [
            {
                "id": a.id,
                "answer_text": a.answer_text,
                "display_order": a.display_order,
                "asset_2d_id": a.asset_2d_id,
                "asset_3d_id": a.asset_3d_id,
                "asset_vr_id": a.asset_vr_id,
                "asset_group": a.asset_group,
                "monetary_value": str(a.monetary_value) if a.monetary_value else None,
                "quantity": a.quantity,
            }
            for a in a_res.scalars().all()
        ],
    }


async def _get_topic_level_for_game_level(game_id: int, level_id: int, db: DB):
    """Resolve and validate a GameLevel → TopicLevel pair, raising 404 as needed."""
    gl_res = await db.execute(
        select(GameLevel).where(
            GameLevel.id == level_id,
            GameLevel.game_id == game_id,
            GameLevel.is_active == True,
        )
    )
    gl = gl_res.scalar_one_or_none()
    if not gl:
        raise HTTPException(status_code=404, detail="Level not found")
    tl = None
    if gl.topic_level_id:
        tl_res = await db.execute(select(TopicLevel).where(TopicLevel.id == gl.topic_level_id))
        tl = tl_res.scalar_one_or_none()
    return gl, tl


# ── /games/{game_id}/levels/{level_id}/questions ──────────────────────────────

@router.get("/{game_id}/levels/{level_id}/questions",
            summary="List Questions for a Level")
async def list_level_questions(game_id: int, level_id: int, db: DB):
    """All questions for a level. Answer correctness is hidden."""
    gl, tl = await _get_topic_level_for_game_level(game_id, level_id, db)
    if not tl:
        return []
    q_res = await db.execute(
        select(Question)
        .where(Question.level_id == tl.id, Question.is_active == True)
        .order_by(Question.sequence_order)
    )
    return [await _fmt_question_for_student(q, db) for q in q_res.scalars().all()]


@router.get("/{game_id}/levels/{level_id}/questions/{question_id}",
            summary="Get a Single Question")
async def get_level_question(game_id: int, level_id: int, question_id: int, db: DB):
    """Single question detail with answer options (no is_correct flag)."""
    gl, tl = await _get_topic_level_for_game_level(game_id, level_id, db)
    if not tl:
        raise HTTPException(status_code=404, detail="Level has no academic content")
    q_res = await db.execute(
        select(Question).where(
            Question.id == question_id,
            Question.level_id == tl.id,
            Question.is_active == True,
        )
    )
    q = q_res.scalar_one_or_none()
    if not q:
        raise HTTPException(status_code=404, detail="Question not found")
    return await _fmt_question_for_student(q, db)


@router.post("/{game_id}/levels/{level_id}/questions/{question_id}/answer",
             summary="Submit and Check an Answer")
async def check_answer(
    game_id: int, level_id: int, question_id: int,
    data: dict,
    current_user: CurrentUser,
    db: DB,
):
    """
    Submit an answer for a question. Body: { answer_id: int, time_taken_seconds?: int }
    Returns whether it was correct, the correct answer, explanation, and score earned.
    Does NOT require an active session — useful for practice mode.
    """
    gl, tl = await _get_topic_level_for_game_level(game_id, level_id, db)
    if not tl:
        raise HTTPException(status_code=404, detail="Level has no academic content")

    answer_id = data.get("answer_id")
    if not answer_id:
        raise HTTPException(status_code=400, detail="answer_id is required")
    time_taken = int(data.get("time_taken_seconds", 0))

    # Validate question belongs to this level
    q_res = await db.execute(
        select(Question).where(
            Question.id == question_id,
            Question.level_id == tl.id,
            Question.is_active == True,
        )
    )
    q = q_res.scalar_one_or_none()
    if not q:
        raise HTTPException(status_code=404, detail="Question not found")

    # Validate submitted answer belongs to this question
    submitted_res = await db.execute(
        select(AnswerOption).where(
            AnswerOption.id == answer_id,
            AnswerOption.question_id == question_id,
        )
    )
    submitted = submitted_res.scalar_one_or_none()
    if not submitted:
        raise HTTPException(status_code=400, detail="Invalid answer_id for this question")

    # Fetch correct answer
    correct_res = await db.execute(
        select(AnswerOption).where(
            AnswerOption.question_id == question_id,
            AnswerOption.is_correct == True,
        )
    )
    correct = correct_res.scalar_one_or_none()

    is_correct = submitted.is_correct
    base_score = q.points or 10
    time_bonus = max(0, (q.time_limit_seconds or 30) - time_taken) // 5
    score_earned = (base_score + time_bonus) if is_correct else 0

    return {
        "is_correct": is_correct,
        "score_earned": score_earned,
        "correct_answer": {
            "id": correct.id,
            "answer_text": correct.answer_text,
            "explanation": correct.explanation,
        } if correct else None,
        "your_answer": {
            "id": submitted.id,
            "answer_text": submitted.answer_text,
        },
        "question_explanation": q.explanation,
    }


# ── legacy standalone endpoint (kept for session-question flow) ───────────────

@router.get("/levels/{game_level_id}/questions", summary="Get Questions for a Level (legacy)")
async def get_level_questions(game_level_id: int, db: DB):
    """
    Return all active questions for a game level, with answer options.
    Correct answer indicator is NOT included — revealed only after submit.
    """
    gl_res = await db.execute(
        select(GameLevel).where(GameLevel.id == game_level_id, GameLevel.is_active == True)
    )
    gl = gl_res.scalar_one_or_none()
    if not gl:
        raise HTTPException(status_code=404, detail="Level not found")
    if not gl.topic_level_id:
        return []  # game-only level with no academic questions yet

    q_res = await db.execute(
        select(Question)
        .where(Question.level_id == gl.topic_level_id, Question.is_active == True)
        .order_by(Question.sequence_order)
    )
    return [await _fmt_question_for_student(q, db) for q in q_res.scalars().all()]


# ===================== SESSIONS =====================

@router.post("/sessions", summary="Create a Game Session", status_code=201)
async def create_session(data: CreateSessionRequest, current_user: CurrentUser, db: DB):
    """
    Create a new game session.
    play_mode: single | pvp | multiplayer | team_vs_team
    """
    # Verify game level exists
    game_level = await db.execute(
        select(GameLevel).where(GameLevel.id == data.game_level_id)
    )
    game_level_obj = game_level.scalar_one_or_none()
    if not game_level_obj:
        raise HTTPException(status_code=404, detail="Game level not found")

    # Check subscription for premium content
    topic_level = await db.execute(
        select(TopicLevel).where(TopicLevel.id == game_level_obj.topic_level_id)
    )
    topic_level_obj = topic_level.scalar_one_or_none()
    if topic_level_obj:
        topic = await db.execute(select(Topic).where(Topic.id == topic_level_obj.topic_id))
        topic_obj = topic.scalar_one_or_none()
        if topic_obj:
            pkg = await db.execute(select(Package).where(Package.id == topic_obj.package_id))
            pkg_obj = pkg.scalar_one_or_none()
            if pkg_obj and pkg_obj.name == "premium":
                from app.services.subscription_service import check_premium_access
                access = await check_premium_access(db, current_user.id)
                if not access["is_premium"]:
                    raise HTTPException(
                        status_code=403,
                        detail="Premium subscription required to access this content"
                    )

    session_code = secrets.token_hex(4).upper()
    session = GameSession(
        game_level_id=data.game_level_id,
        host_user_id=current_user.id,
        session_code=session_code,
        play_mode=data.play_mode,
        max_players=data.max_players or 1,
        is_offline=data.is_offline or False,
        questions_count=data.questions_count or 10,
    )
    db.add(session)
    await db.flush()

    # Auto-join as player
    player = SessionPlayer(
        session_id=session.id,
        user_id=current_user.id,
        is_host=True,
    )
    db.add(player)

    if data.play_mode == "team_vs_team":
        for team_name in ["Team A", "Team B"]:
            team = SessionTeam(session_id=session.id, team_name=team_name)
            db.add(team)

    await db.commit()
    await db.refresh(session)
    return {
        "session_id": session.id,
        "session_code": session_code,
        "play_mode": session.play_mode,
        "status": session.status,
    }


@router.post("/sessions/join", summary="Join a Game Session")
async def join_session(data: JoinSessionRequest, current_user: CurrentUser, db: DB):
    """Join an existing session using the session code."""
    session = await db.execute(
        select(GameSession).where(
            GameSession.session_code == data.session_code.upper(),
            GameSession.status == "waiting",
        )
    )
    session_obj = session.scalar_one_or_none()
    if not session_obj:
        raise HTTPException(status_code=404, detail="Session not found or already started")

    # Check player limit
    current_count = (await db.execute(
        select(func.count(SessionPlayer.id)).where(SessionPlayer.session_id == session_obj.id)
    )).scalar()
    if current_count >= session_obj.max_players:
        raise HTTPException(status_code=400, detail="Session is full")

    # Check not already joined
    existing = await db.execute(
        select(SessionPlayer).where(
            SessionPlayer.session_id == session_obj.id,
            SessionPlayer.user_id == current_user.id,
        )
    )
    if existing.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="Already in this session")

    player = SessionPlayer(
        session_id=session_obj.id,
        user_id=current_user.id,
        team_id=data.team_id,
    )
    db.add(player)
    await db.commit()
    return {"message": "Joined session", "session_id": session_obj.id}


@router.get("/sessions/{session_id}", summary="Get Session Details")
async def get_session(session_id: int, current_user: CurrentUser, db: DB):
    session = await db.execute(select(GameSession).where(GameSession.id == session_id))
    session_obj = session.scalar_one_or_none()
    if not session_obj:
        raise HTTPException(status_code=404, detail="Session not found")
    return session_obj


@router.post("/sessions/{session_id}/start", summary="Start a Game Session")
async def start_session(session_id: int, current_user: CurrentUser, db: DB):
    """Start the session (host only). Loads questions."""
    from datetime import datetime, timezone
    session = await db.execute(select(GameSession).where(GameSession.id == session_id))
    session_obj = session.scalar_one_or_none()
    if not session_obj:
        raise HTTPException(status_code=404, detail="Session not found")
    if session_obj.host_user_id != current_user.id:
        raise HTTPException(status_code=403, detail="Only the host can start the session")
    if session_obj.status != "waiting":
        raise HTTPException(status_code=400, detail="Session already started")

    session_obj.status = "in_progress"
    session_obj.started_at = datetime.now(timezone.utc)
    await db.commit()
    return {"message": "Session started", "status": "in_progress"}


@router.get("/sessions/{session_id}/questions", summary="Get Session Questions")
async def get_session_questions(session_id: int, current_user: CurrentUser, db: DB):
    """Get randomized questions for this session."""
    import random
    session = await db.execute(select(GameSession).where(GameSession.id == session_id))
    session_obj = session.scalar_one_or_none()
    if not session_obj:
        raise HTTPException(status_code=404, detail="Session not found")

    game_level = await db.execute(
        select(GameLevel).where(GameLevel.id == session_obj.game_level_id)
    )
    game_level_obj = game_level.scalar_one_or_none()

    questions = await db.execute(
        select(Question).where(
            Question.level_id == game_level_obj.topic_level_id,
            Question.is_active == True,
        )
    )
    q_list = questions.scalars().all()
    random.shuffle(q_list)
    q_list = q_list[: session_obj.questions_count]

    result = []
    for q in q_list:
        answers = await db.execute(
            select(AnswerOption).where(AnswerOption.question_id == q.id)
            .order_by(AnswerOption.display_order)
        )
        result.append({
            "question_id": q.id,
            "question_text": q.question_text,
            "question_type": q.question_type,
            "asset_2d_url": q.asset_2d_url,
            "hint_text": q.hint_text,
            "time_limit_seconds": q.time_limit_seconds,
            "answers": [
                {"id": a.id, "text": a.answer_text, "asset_2d_url": a.asset_2d_url}
                for a in answers.scalars().all()
            ],
        })
    return result


@router.post("/sessions/{session_id}/answer", summary="Submit an Answer")
async def submit_answer(session_id: int, data: SubmitAnswerRequest, current_user: CurrentUser, db: DB):
    """Submit an answer for a question in this session."""
    from datetime import datetime, timezone
    # Verify correct answer
    question = await db.execute(select(Question).where(Question.id == data.question_id))
    question_obj = question.scalar_one_or_none()
    if not question_obj:
        raise HTTPException(status_code=404, detail="Question not found")

    correct_answer = await db.execute(
        select(AnswerOption).where(
            AnswerOption.question_id == data.question_id,
            AnswerOption.is_correct == True,
        )
    )
    correct = correct_answer.scalar_one_or_none()
    is_correct = correct and str(data.answer_option_id) == str(correct.id)

    # Calculate score based on time
    base_score = question_obj.points or 10
    time_bonus = max(0, (question_obj.time_limit_seconds or 30) - (data.time_taken_seconds or 0))
    score = base_score + (time_bonus // 5) if is_correct else 0

    # Get session player
    player = await db.execute(
        select(SessionPlayer).where(
            SessionPlayer.session_id == session_id,
            SessionPlayer.user_id == current_user.id,
        )
    )
    player_obj = player.scalar_one_or_none()
    if not player_obj:
        raise HTTPException(status_code=400, detail="Not a player in this session")

    response = PlayerResponse(
        session_id=session_id,
        player_id=player_obj.id,
        question_id=data.question_id,
        answer_option_id=data.answer_option_id,
        answer_text=data.answer_text,
        is_correct=is_correct,
        score_earned=score,
        time_taken_seconds=data.time_taken_seconds,
    )
    db.add(response)

    # Update player score
    player_obj.total_score += score
    if is_correct:
        player_obj.correct_answers += 1

    await db.commit()
    return {
        "is_correct": is_correct,
        "score_earned": score,
        "correct_answer_id": correct.id if correct else None,
        "explanation": question_obj.explanation,
    }


@router.post("/sessions/{session_id}/complete", summary="Complete a Game Session")
async def complete_session(session_id: int, current_user: CurrentUser, db: DB):
    """Mark a session as completed and award XP."""
    from datetime import datetime, timezone
    session = await db.execute(select(GameSession).where(GameSession.id == session_id))
    session_obj = session.scalar_one_or_none()
    if not session_obj:
        raise HTTPException(status_code=404, detail="Session not found")

    player = await db.execute(
        select(SessionPlayer).where(
            SessionPlayer.session_id == session_id,
            SessionPlayer.user_id == current_user.id,
        )
    )
    player_obj = player.scalar_one_or_none()

    # Calculate results
    total_questions = session_obj.questions_count or 10
    correct = player_obj.correct_answers if player_obj else 0
    score = player_obj.total_score if player_obj else 0
    score_percent = (correct / total_questions * 100) if total_questions > 0 else 0

    # Get game level config
    game_level = await db.execute(select(GameLevel).where(GameLevel.id == session_obj.game_level_id))
    game_level_obj = game_level.scalar_one_or_none()
    topic_level = await db.execute(
        select(TopicLevel).where(TopicLevel.id == game_level_obj.topic_level_id)
    ) if game_level_obj else None
    topic_level_obj = topic_level.scalar_one_or_none() if topic_level else None

    # Award XP
    xp_earned = 0
    stars_earned = 0
    if topic_level_obj:
        if score_percent >= topic_level_obj.passing_score:
            xp_earned = topic_level_obj.xp_reward
            stars_earned = (
                3 if score_percent >= 90 else
                2 if score_percent >= 75 else
                1
            )

        # Update player progress
        existing_progress = await db.execute(
            select(PlayerProgress).where(
                PlayerProgress.student_user_id == current_user.id,
                PlayerProgress.topic_level_id == topic_level_obj.id,
            )
        )
        progress = existing_progress.scalar_one_or_none()
        if progress:
            if score > progress.best_score:
                progress.best_score = score
            if stars_earned > progress.best_stars:
                progress.best_stars = stars_earned
            progress.attempts_count += 1
            progress.total_time_seconds += data.time_taken_seconds if hasattr(data, 'time_taken_seconds') else 0
            if score_percent >= topic_level_obj.passing_score:
                progress.is_completed = True
        else:
            progress = PlayerProgress(
                student_user_id=current_user.id,
                topic_level_id=topic_level_obj.id,
                best_score=score,
                best_stars=stars_earned,
                is_completed=score_percent >= topic_level_obj.passing_score,
                attempts_count=1,
            )
            db.add(progress)

    # Update student XP
    if xp_earned > 0 and current_user.role == "student":
        from app.models.user import StudentProfile
        profile = await db.execute(
            select(StudentProfile).where(StudentProfile.user_id == current_user.id)
        )
        student_profile = profile.scalar_one_or_none()
        if student_profile:
            student_profile.total_xp += xp_earned

    # Close session if all done (single player)
    if session_obj.play_mode == "single":
        session_obj.status = "completed"
        session_obj.completed_at = datetime.now(timezone.utc)

    await db.commit()
    return {
        "session_id": session_id,
        "score": score,
        "correct_answers": correct,
        "total_questions": total_questions,
        "score_percent": round(score_percent, 1),
        "stars_earned": stars_earned,
        "xp_earned": xp_earned,
        "passed": score_percent >= (topic_level_obj.passing_score if topic_level_obj else 60),
    }
