from fastapi import APIRouter, Depends, Query
from sqlmodel import Session, select, func, desc
from typing import List, Optional
from database import get_session
from models import Review, Show, Venue, User, Profile, Performance, Song, Rating

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

@router.get("/shows/top")
def get_top_shows(limit: int = 10, session: Session = Depends(get_session)):
    """Get top rated shows based on average rating"""
    # Using Rating table allows for more data points than just text reviews
    query = (
        select(
            Show,
            Venue,
            func.avg(Rating.score).label("avg_score"),
            func.count(Rating.id).label("rating_count")
        )
        .join(Rating, Rating.show_id == Show.id)
        .join(Venue, Show.venue_id == Venue.id)
        # Rating FK already filters via join
        .group_by(Show.id, Venue.id)
        .having(func.count(Rating.id) >= 1) 
        .order_by(desc("avg_score"), desc("rating_count"))
        .limit(limit)
    )
    
    results = session.exec(query).all()
    
    return [
        {
            "show": show,
            "venue": venue,
            "avg_score": round(score, 2) if score else 0,
            "review_count": count
        }
        for show, venue, score, count in results
    ]

@router.get("/performances/top")
def get_top_performances(limit: int = 20, session: Session = Depends(get_session)):
    """Get top rated performances (Heady Jams)"""
    query = (
        select(
            Performance,
            Song,
            Show,
            Venue,
            func.avg(Rating.score).label("avg_score"),
            func.count(Rating.id).label("rating_count")
        )
        .join(Rating, Rating.performance_id == Performance.id)
        .join(Song, Performance.song_id == Song.id)
        .join(Show, Performance.show_id == Show.id)
        .join(Venue, Show.venue_id == Venue.id)
        # Rating FK already filters via join
        .group_by(Performance.id, Song.id, Show.id, Venue.id)
        .having(func.count(Rating.id) >= 1)
        .order_by(desc("avg_score"), desc("rating_count"))
        .limit(limit)
    )

    results = session.exec(query).all()

    return [
        {
            "performance": performance,
            "song": song,
            "show": show,
            "venue": venue,
            "avg_score": round(score, 2) if score else 0,
            "rating_count": count
        }
        for performance, song, show, venue, score, count in results
    ]

@router.get("/venues/top")
def get_top_venues(limit: int = 10, session: Session = Depends(get_session)):
    """Get top rated venues based on show ratings there"""
    # Aggregate ratings from shows played at each venue
    query = (
        select(
            Venue,
            func.avg(Rating.score).label("avg_score"),
            func.count(Rating.id).label("rating_count")
        )
        .join(Show, Show.venue_id == Venue.id)
        .join(Rating, Rating.show_id == Show.id)
        .group_by(Venue.id)
        .having(func.count(Rating.id) >= 1)
        .order_by(desc("avg_score"))
        .limit(limit)
    )
    
    results = session.exec(query).all()
    
    return [
        {
            "venue": venue,
            "avg_score": round(score, 2) if score else 0,
            "review_count": count
        }
        for venue, score, count in results
    ]

@router.get("/users/active")
def get_active_users(limit: int = 10, session: Session = Depends(get_session)):
    """Get users with most reviews/ratings"""
    # Combining reviews count
    query = (
        select(
            Profile,
            func.count(Review.id).label("review_count")
        )
        .join(User, User.id == Profile.user_id)
        .join(Review, Review.user_id == User.id)
        .where(User.xp > 0)
        .group_by(Profile.id)
        .order_by(desc("review_count"))
        .limit(limit)
    )
    
    results = session.exec(query).all()
    
    return [
        {
            "profile": profile,
            "review_count": count
        }
        for profile, count in results
    ]
