from uuid import UUID

from fastapi import APIRouter, Depends, Query
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from app.auth.demo_auth import get_current_user
from app.database import get_db
from app.models.activity import ActivityCompletion
from app.models.gamification import Badge, Level, UserBadge
from app.models.user import Department, User

router = APIRouter(prefix="/gamification", tags=["Gamification"])


@router.get("/badges")
async def list_badges(db: AsyncSession = Depends(get_db), _=Depends(get_current_user)):
    """List all active badges."""
    result = await db.execute(
        select(Badge).where(Badge.is_active == True).order_by(Badge.sort_order, Badge.name)  # noqa: E712
    )
    badges = result.scalars().all()
    return [
        {
            "id": str(b.id),
            "name": b.name,
            "description": b.description,
            "icon": b.icon,
            "category": b.category,
            "condition_type": b.condition_type,
            "condition_value": b.condition_value,
            "sort_order": b.sort_order,
        }
        for b in badges
    ]


@router.get("/levels")
async def list_levels(db: AsyncSession = Depends(get_db), _=Depends(get_current_user)):
    """List all XP levels in ascending order."""
    result = await db.execute(select(Level).order_by(Level.sort_order))
    levels = result.scalars().all()
    return [
        {
            "id": str(lv.id),
            "name": lv.name,
            "min_xp": lv.min_xp,
            "color": lv.color,
            "icon": lv.icon,
            "sort_order": lv.sort_order,
        }
        for lv in levels
    ]


@router.get("/leaderboard")
async def leaderboard(
    limit: int = Query(20, le=100),
    offset: int = Query(0, ge=0),
    department_id: str | None = None,
    db: AsyncSession = Depends(get_db),
    _=Depends(get_current_user),
):
    """Ranked leaderboard of users by total XP."""
    query = (
        select(User)
        .where(User.is_active == True)  # noqa: E712
        .options(selectinload(User.department))
        .order_by(User.total_xp.desc())
        .limit(limit)
        .offset(offset)
    )
    if department_id:
        query = query.where(User.department_id == UUID(department_id))

    result = await db.execute(query)
    users = result.scalars().all()

    # Get levels for mapping
    levels_result = await db.execute(select(Level).order_by(Level.min_xp.desc()))
    levels = levels_result.scalars().all()

    entries = []
    for rank, user in enumerate(users, start=offset + 1):
        # Determine level
        user_level = None
        for lv in levels:
            if user.total_xp >= lv.min_xp:
                user_level = lv
                break

        # Completion count
        comp_count = (
            await db.execute(
                select(func.count(ActivityCompletion.id)).where(
                    ActivityCompletion.user_id == user.id,
                    ActivityCompletion.status == "completed",
                )
            )
        ).scalar() or 0

        # Badge count
        badge_count = (
            await db.execute(
                select(func.count(UserBadge.id)).where(UserBadge.user_id == user.id)
            )
        ).scalar() or 0

        entries.append({
            "rank": rank,
            "user": {
                "id": str(user.id),
                "full_name": user.full_name,
                "email": user.email,
                "department": user.department.name if user.department else None,
                "total_xp": user.total_xp,
                "verified_xp": user.verified_xp,
                "current_level": user.current_level,
            },
            "total_xp": user.total_xp,
            "level": {"name": user_level.name, "color": user_level.color} if user_level else None,
            "completed_count": comp_count,
            "badge_count": badge_count,
        })

    return entries


@router.get("/department-leaderboard")
async def department_leaderboard(db: AsyncSession = Depends(get_db), _=Depends(get_current_user)):
    """Departments ranked by average XP per member."""
    result = await db.execute(select(Department))
    departments = result.scalars().all()

    summaries = []
    for dept in departments:
        members_result = await db.execute(
            select(User)
            .where(User.department_id == dept.id, User.is_active == True)  # noqa: E712
            .order_by(User.total_xp.desc())
        )
        members = members_result.scalars().all()
        if not members:
            continue

        total_xp = sum(m.total_xp for m in members)
        total_verified = sum(m.verified_xp for m in members)
        avg_xp = round(total_xp / len(members))

        comp_result = await db.execute(
            select(func.count(ActivityCompletion.id))
            .join(User, ActivityCompletion.user_id == User.id)
            .where(
                User.department_id == dept.id,
                ActivityCompletion.status == "completed",
            )
        )
        total_completions = comp_result.scalar() or 0

        summaries.append({
            "department": {"id": str(dept.id), "name": dept.name},
            "member_count": len(members),
            "total_xp": total_xp,
            "total_verified_xp": total_verified,
            "avg_xp": avg_xp,
            "total_completions": total_completions,
            "top_performer": {
                "id": str(members[0].id),
                "full_name": members[0].full_name,
                "total_xp": members[0].total_xp,
            },
        })

    summaries.sort(key=lambda s: s["avg_xp"], reverse=True)
    return summaries
