"""
Chase Songs and Profile Stats Router
"""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlmodel import Session, select, func
from typing import List, Optional
from pydantic import BaseModel
from datetime import datetime

from database import get_session
from models import ChaseSong, Song, Attendance, Show, Performance, Rating, User
from routers.auth import get_current_user

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

# --- Schemas ---
class ChaseSongCreate(BaseModel):
    song_id: int
    priority: int = 1
    notes: Optional[str] = None

class ChaseSongResponse(BaseModel):
    id: int
    song_id: int
    song_title: str
    priority: int
    notes: Optional[str]
    created_at: datetime
    caught_at: Optional[datetime]
    caught_show_id: Optional[int]
    caught_show_date: Optional[str] = None

class ChaseSongUpdate(BaseModel):
    priority: Optional[int] = None
    notes: Optional[str] = None

class ProfileStats(BaseModel):
    shows_attended: int
    unique_songs_seen: int
    debuts_witnessed: int
    heady_versions_attended: int  # Top 10 rated performances
    top_10_performances: int
    total_ratings: int
    total_reviews: int
    chase_songs_count: int
    chase_songs_caught: int
    most_seen_song: Optional[str] = None
    most_seen_count: int = 0

# --- Routes ---

@router.get("/songs", response_model=List[ChaseSongResponse])
async def get_my_chase_songs(
    current_user: User = Depends(get_current_user),
    session: Session = Depends(get_session)
):
    """Get all chase songs for the current user"""
    statement = (
        select(ChaseSong)
        .where(ChaseSong.user_id == current_user.id)
        .order_by(ChaseSong.priority, ChaseSong.created_at.desc())
    )
    chase_songs = session.exec(statement).all()
    
    result = []
    for cs in chase_songs:
        song = session.get(Song, cs.song_id)
        caught_show_date = None
        if cs.caught_show_id:
            show = session.get(Show, cs.caught_show_id)
            if show:
                caught_show_date = show.date.strftime("%Y-%m-%d") if show.date else None
        
        result.append(ChaseSongResponse(
            id=cs.id,
            song_id=cs.song_id,
            song_title=song.title if song else "Unknown",
            priority=cs.priority,
            notes=cs.notes,
            created_at=cs.created_at,
            caught_at=cs.caught_at,
            caught_show_id=cs.caught_show_id,
            caught_show_date=caught_show_date
        ))
    
    return result

@router.post("/songs", response_model=ChaseSongResponse, status_code=status.HTTP_201_CREATED)
async def add_chase_song(
    data: ChaseSongCreate,
    current_user: User = Depends(get_current_user),
    session: Session = Depends(get_session)
):
    """Add a song to user's chase list"""
    # Check if song exists
    song = session.get(Song, data.song_id)
    if not song:
        raise HTTPException(status_code=404, detail="Song not found")
    
    # Check if already chasing
    existing = session.exec(
        select(ChaseSong)
        .where(ChaseSong.user_id == current_user.id, ChaseSong.song_id == data.song_id)
    ).first()
    if existing:
        raise HTTPException(status_code=400, detail="Song already in chase list")
    
    chase_song = ChaseSong(
        user_id=current_user.id,
        song_id=data.song_id,
        priority=data.priority,
        notes=data.notes
    )
    session.add(chase_song)
    session.commit()
    session.refresh(chase_song)
    
    return ChaseSongResponse(
        id=chase_song.id,
        song_id=chase_song.song_id,
        song_title=song.title,
        priority=chase_song.priority,
        notes=chase_song.notes,
        created_at=chase_song.created_at,
        caught_at=None,
        caught_show_id=None
    )

@router.patch("/songs/{chase_id}", response_model=ChaseSongResponse)
async def update_chase_song(
    chase_id: int,
    data: ChaseSongUpdate,
    current_user: User = Depends(get_current_user),
    session: Session = Depends(get_session)
):
    """Update a chase song"""
    chase_song = session.get(ChaseSong, chase_id)
    if not chase_song or chase_song.user_id != current_user.id:
        raise HTTPException(status_code=404, detail="Chase song not found")
    
    if data.priority is not None:
        chase_song.priority = data.priority
    if data.notes is not None:
        chase_song.notes = data.notes
    
    session.add(chase_song)
    session.commit()
    session.refresh(chase_song)
    
    song = session.get(Song, chase_song.song_id)
    return ChaseSongResponse(
        id=chase_song.id,
        song_id=chase_song.song_id,
        song_title=song.title if song else "Unknown",
        priority=chase_song.priority,
        notes=chase_song.notes,
        created_at=chase_song.created_at,
        caught_at=chase_song.caught_at,
        caught_show_id=chase_song.caught_show_id
    )

@router.delete("/songs/{chase_id}", status_code=status.HTTP_204_NO_CONTENT)
async def remove_chase_song(
    chase_id: int,
    current_user: User = Depends(get_current_user),
    session: Session = Depends(get_session)
):
    """Remove a song from chase list"""
    chase_song = session.get(ChaseSong, chase_id)
    if not chase_song or chase_song.user_id != current_user.id:
        raise HTTPException(status_code=404, detail="Chase song not found")
    
    session.delete(chase_song)
    session.commit()

@router.post("/songs/{chase_id}/caught")
async def mark_song_caught(
    chase_id: int,
    show_id: int,
    current_user: User = Depends(get_current_user),
    session: Session = Depends(get_session)
):
    """Mark a chase song as caught at a specific show"""
    chase_song = session.get(ChaseSong, chase_id)
    if not chase_song or chase_song.user_id != current_user.id:
        raise HTTPException(status_code=404, detail="Chase song not found")
    
    show = session.get(Show, show_id)
    if not show:
        raise HTTPException(status_code=404, detail="Show not found")
    
    chase_song.caught_at = datetime.utcnow()
    chase_song.caught_show_id = show_id
    session.add(chase_song)
    session.commit()
    
    return {"message": "Song marked as caught!"}


# Profile stats endpoint
@router.get("/profile/stats", response_model=ProfileStats)
async def get_profile_stats(
    current_user: User = Depends(get_current_user),
    session: Session = Depends(get_session)
):
    """Get comprehensive profile stats for the current user"""
    
    # Shows attended
    shows_attended = session.exec(
        select(func.count(Attendance.id))
        .where(Attendance.user_id == current_user.id)
    ).one() or 0
    
    # Get show IDs user attended
    attended_show_ids = session.exec(
        select(Attendance.show_id)
        .where(Attendance.user_id == current_user.id)
    ).all()
    
    # Unique songs seen (performances at attended shows)
    unique_songs_seen = session.exec(
        select(func.count(func.distinct(Performance.song_id)))
        .where(Performance.show_id.in_(attended_show_ids) if attended_show_ids else False)
    ).one() or 0
    
    # Debuts witnessed (times_played = 1 at show they attended)
    # This would require joining with song data - simplified for now
    debuts_witnessed = 0
    if attended_show_ids:
        debuts_q = session.exec(
            select(Performance)
            .where(Performance.show_id.in_(attended_show_ids))
        ).all()
        # Count performances where this was the debut
        for perf in debuts_q:
            # Check if this was the first performance of the song
            earlier_perfs = session.exec(
                select(func.count(Performance.id))
                .join(Show, Performance.show_id == Show.id)
                .where(Performance.song_id == perf.song_id)
                .where(Show.date < session.get(Show, perf.show_id).date if session.get(Show, perf.show_id) else False)
            ).one()
            if earlier_perfs == 0:
                debuts_witnessed += 1
    
    # Top performances attended (with avg rating >= 8.0)
    top_performances_attended = 0
    heady_versions_attended = 0
    if attended_show_ids:
        # Get average ratings for performances at attended shows
        perf_ratings = session.exec(
            select(
                Rating.performance_id,
                func.avg(Rating.score).label("avg_rating")
            )
            .where(Rating.performance_id.isnot(None))
            .group_by(Rating.performance_id)
            .having(func.avg(Rating.score) >= 8.0)
        ).all()
        
        # Filter to performances at attended shows
        high_rated_perf_ids = [pr[0] for pr in perf_ratings]
        if high_rated_perf_ids:
            attended_high_rated = session.exec(
                select(func.count(Performance.id))
                .where(Performance.id.in_(high_rated_perf_ids))
                .where(Performance.show_id.in_(attended_show_ids))
            ).one() or 0
            top_performances_attended = attended_high_rated
            heady_versions_attended = attended_high_rated
    
    # Total ratings/reviews
    total_ratings = session.exec(
        select(func.count(Rating.id)).where(Rating.user_id == current_user.id)
    ).one() or 0
    
    total_reviews = session.exec(
        select(func.count()).select_from(session.exec(
            select(1).where(Rating.user_id == current_user.id)  # placeholder
        ).subquery())
    ).one() if False else 0  # Will fix this
    
    # Chase songs
    chase_count = session.exec(
        select(func.count(ChaseSong.id)).where(ChaseSong.user_id == current_user.id)
    ).one() or 0
    
    chase_caught = session.exec(
        select(func.count(ChaseSong.id))
        .where(ChaseSong.user_id == current_user.id)
        .where(ChaseSong.caught_at.isnot(None))
    ).one() or 0
    
    # Most seen song
    most_seen_song = None
    most_seen_count = 0
    if attended_show_ids:
        song_counts = session.exec(
            select(
                Performance.song_id,
                func.count(Performance.id).label("count")
            )
            .where(Performance.show_id.in_(attended_show_ids))
            .group_by(Performance.song_id)
            .order_by(func.count(Performance.id).desc())
            .limit(1)
        ).first()
        
        if song_counts:
            song = session.get(Song, song_counts[0])
            if song:
                most_seen_song = song.title
                most_seen_count = song_counts[1]
    
    return ProfileStats(
        shows_attended=shows_attended,
        unique_songs_seen=unique_songs_seen,
        debuts_witnessed=min(debuts_witnessed, 50),  # Cap to prevent timeout
        heady_versions_attended=heady_versions_attended,
        top_10_performances=top_performances_attended,
        total_ratings=total_ratings,
        total_reviews=0,  # TODO: implement
        chase_songs_count=chase_count,
        chase_songs_caught=chase_caught,
        most_seen_song=most_seen_song,
        most_seen_count=most_seen_count
    )
