# ==============================================
# Breakpilot Drive - Game Session & Quiz DB Methods
# ==============================================
# Methods for saving/querying game sessions, quiz answers, and basic leaderboard.

import json
import logging
from typing import Optional, List, Dict, Any

logger = logging.getLogger(__name__)


class SessionsMixin:
    """Mixin providing game session and quiz database methods for GameDatabase."""

    async def save_game_session(
        self,
        student_id: str,
        game_mode: str,
        duration_seconds: int,
        distance_traveled: float,
        score: int,
        questions_answered: int,
        questions_correct: int,
        difficulty_level: int,
        metadata: Optional[Dict[str, Any]] = None,
    ) -> Optional[str]:
        """Save a game session and return the session ID."""
        await self._ensure_connected()
        if not self._pool:
            return None

        try:
            async with self._pool.acquire() as conn:
                row = await conn.fetchrow(
                    """
                    INSERT INTO game_sessions (
                        student_id, game_mode, duration_seconds, distance_traveled,
                        score, questions_answered, questions_correct, difficulty_level,
                        started_at, ended_at, metadata
                    ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8,
                              NOW() - make_interval(secs => $3), NOW(), $9)
                    RETURNING id
                    """,
                    student_id, game_mode, duration_seconds, distance_traveled,
                    score, questions_answered, questions_correct, difficulty_level,
                    json.dumps(metadata) if metadata else None
                )

                if row:
                    return str(row["id"])
        except Exception as e:
            logger.error(f"Failed to save game session: {e}")

        return None

    async def get_user_sessions(
        self,
        student_id: str,
        limit: int = 10
    ) -> List[Dict[str, Any]]:
        """Get recent game sessions for a user."""
        await self._ensure_connected()
        if not self._pool:
            return []

        try:
            async with self._pool.acquire() as conn:
                rows = await conn.fetch(
                    """
                    SELECT id, student_id, game_mode, duration_seconds, distance_traveled,
                           score, questions_answered, questions_correct, difficulty_level,
                           started_at, ended_at, metadata
                    FROM game_sessions
                    WHERE student_id = $1
                    ORDER BY ended_at DESC
                    LIMIT $2
                    """,
                    student_id, limit
                )

                return [
                    {
                        "session_id": str(row["id"]),
                        "user_id": str(row["student_id"]),
                        "game_mode": row["game_mode"],
                        "duration_seconds": row["duration_seconds"],
                        "distance_traveled": float(row["distance_traveled"]) if row["distance_traveled"] else 0.0,
                        "score": row["score"],
                        "questions_answered": row["questions_answered"],
                        "questions_correct": row["questions_correct"],
                        "difficulty_level": row["difficulty_level"],
                        "started_at": row["started_at"].isoformat() if row["started_at"] else None,
                        "ended_at": row["ended_at"].isoformat() if row["ended_at"] else None,
                    }
                    for row in rows
                ]
        except Exception as e:
            logger.error(f"Failed to get user sessions: {e}")

        return []

    async def get_leaderboard(
        self,
        timeframe: str = "day",
        limit: int = 10
    ) -> List[Dict[str, Any]]:
        """Get leaderboard data."""
        await self._ensure_connected()
        if not self._pool:
            return []

        # Timeframe filter
        timeframe_sql = {
            "day": "ended_at > NOW() - INTERVAL '1 day'",
            "week": "ended_at > NOW() - INTERVAL '7 days'",
            "month": "ended_at > NOW() - INTERVAL '30 days'",
            "all": "1=1",
        }.get(timeframe, "1=1")

        try:
            async with self._pool.acquire() as conn:
                rows = await conn.fetch(
                    f"""
                    SELECT student_id, SUM(score) as total_score
                    FROM game_sessions
                    WHERE {timeframe_sql}
                    GROUP BY student_id
                    ORDER BY total_score DESC
                    LIMIT $1
                    """,
                    limit
                )

                return [
                    {
                        "rank": i + 1,
                        "user_id": str(row["student_id"]),
                        "total_score": int(row["total_score"]),
                    }
                    for i, row in enumerate(rows)
                ]
        except Exception as e:
            logger.error(f"Failed to get leaderboard: {e}")

        return []

    async def save_quiz_answer(
        self,
        session_id: str,
        question_id: str,
        subject: str,
        difficulty: int,
        is_correct: bool,
        answer_time_ms: int,
    ) -> bool:
        """Save an individual quiz answer."""
        await self._ensure_connected()
        if not self._pool:
            return False

        try:
            async with self._pool.acquire() as conn:
                await conn.execute(
                    """
                    INSERT INTO game_quiz_answers (
                        session_id, question_id, subject, difficulty,
                        is_correct, answer_time_ms
                    ) VALUES ($1, $2, $3, $4, $5, $6)
                    """,
                    session_id, question_id, subject, difficulty,
                    is_correct, answer_time_ms
                )
                return True
        except Exception as e:
            logger.error(f"Failed to save quiz answer: {e}")

        return False

    async def get_subject_stats(
        self,
        student_id: str
    ) -> Dict[str, Dict[str, Any]]:
        """Get per-subject statistics for a student."""
        await self._ensure_connected()
        if not self._pool:
            return {}

        try:
            async with self._pool.acquire() as conn:
                rows = await conn.fetch(
                    """
                    SELECT
                        qa.subject,
                        COUNT(*) as total,
                        SUM(CASE WHEN qa.is_correct THEN 1 ELSE 0 END) as correct,
                        AVG(qa.answer_time_ms) as avg_time_ms
                    FROM game_quiz_answers qa
                    JOIN game_sessions gs ON qa.session_id = gs.id
                    WHERE gs.student_id = $1
                    GROUP BY qa.subject
                    """,
                    student_id
                )

                return {
                    row["subject"]: {
                        "total": row["total"],
                        "correct": row["correct"],
                        "accuracy": row["correct"] / row["total"] if row["total"] > 0 else 0.0,
                        "avg_time_ms": int(row["avg_time_ms"]) if row["avg_time_ms"] else 0,
                    }
                    for row in rows
                }
        except Exception as e:
            logger.error(f"Failed to get subject stats: {e}")

        return {}
