import re
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlmodel import Session, select, func
from database import get_session
from models import Comment, Rating, User, Profile, Reaction
from schemas import CommentCreate, CommentRead, RatingCreate, RatingRead, ReactionCreate, ReactionRead
from auth import get_current_user
from helpers import create_notification
from services.gamification import award_xp, check_and_award_badges, update_streak, XP_REWARDS

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

# --- Comments ---

@router.post("/comments", response_model=CommentRead)
def create_comment(
    comment: CommentCreate, 
    session: Session = Depends(get_session), 
    current_user: User = Depends(get_current_user)
):
    from services.email_service import send_reply_notification_email, send_mention_notification_email
    
    db_comment = Comment.model_validate(comment)
    db_comment.user_id = current_user.id
    session.add(db_comment)
    session.commit()
    session.refresh(db_comment)
    
    # Get commenter's display name
    commenter_profile = session.exec(select(Profile).where(Profile.user_id == current_user.id)).first()
    commenter_name = commenter_profile.display_name if commenter_profile else current_user.email.split('@')[0]
    
    # Notify parent author if reply
    if db_comment.parent_id:
        parent_comment = session.get(Comment, db_comment.parent_id)
        if parent_comment and parent_comment.user_id != current_user.id:
            # Create in-app notification
            create_notification(
                session,
                user_id=parent_comment.user_id,
                title="New Reply",
                message=f"{commenter_name} replied to your comment.",
                type="reply",
                link=f"/activity"
            )
            
            # Send email if user has email_on_reply enabled
            parent_user = session.get(User, parent_comment.user_id)
            if parent_user and parent_user.preferences and parent_user.preferences.email_on_reply:
                send_reply_notification_email(
                    to_email=parent_user.email,
                    replier_name=commenter_name,
                    original_content=parent_comment.content or "",
                    link="/activity"
                )
    
    # Handle Mentions
    mention_pattern = r"@(\w+)"
    mentions = re.findall(mention_pattern, db_comment.content)
    if mentions:
        # Find users with these profile usernames
        mentioned_profiles = session.exec(select(Profile).where(Profile.username.in_(mentions))).all()
        for profile in mentioned_profiles:
            if profile.user_id != current_user.id:
                create_notification(
                    session, 
                    user_id=profile.user_id, 
                    title="You were mentioned!", 
                    message=f"{commenter_name} mentioned you in a comment.", 
                    type="mention", 
                    link=f"/activity"
                )
                
                # Send email for mention (using reply preference for now)
                mentioned_user = session.get(User, profile.user_id)
                if mentioned_user and mentioned_user.preferences and mentioned_user.preferences.email_on_reply:
                    send_mention_notification_email(
                        to_email=mentioned_user.email,
                        mentioner_name=commenter_name,
                        context=db_comment.content or "",
                        link="/activity"
                    )

    return db_comment

@router.get("/comments", response_model=List[CommentRead])
def read_comments(
    show_id: Optional[int] = None,
    venue_id: Optional[int] = None,
    song_id: Optional[int] = None,
    offset: int = 0, 
    limit: int = Query(default=50, le=100), 
    session: Session = Depends(get_session)
):
    query = select(Comment)
    if show_id:
        query = query.where(Comment.show_id == show_id)
    if venue_id:
        query = query.where(Comment.venue_id == venue_id)
    if song_id:
        query = query.where(Comment.song_id == song_id)
        
    query = query.order_by(Comment.created_at.desc()).offset(offset).limit(limit)
    comments = session.exec(query).all()
    return comments

# --- Ratings ---

@router.post("/ratings", response_model=RatingRead)
def create_rating(
    rating: RatingCreate, 
    session: Session = Depends(get_session), 
    current_user: User = Depends(get_current_user)
):
    # Check if user already rated this entity
    query = select(Rating).where(Rating.user_id == current_user.id)
    if rating.show_id:
        query = query.where(Rating.show_id == rating.show_id)
    elif rating.song_id:
        query = query.where(Rating.song_id == rating.song_id)
    elif rating.performance_id:
        query = query.where(Rating.performance_id == rating.performance_id)
    elif rating.venue_id:
        query = query.where(Rating.venue_id == rating.venue_id)
    elif rating.tour_id:
        query = query.where(Rating.tour_id == rating.tour_id)
    else:
        raise HTTPException(status_code=400, detail="Must rate a show, song, performance, venue, or tour")
        
    existing_rating = session.exec(query).first()
    if existing_rating:
        # Update existing (no XP for updating)
        existing_rating.score = rating.score
        session.add(existing_rating)
        session.commit()
        session.refresh(existing_rating)
        return existing_rating
    
    # Create new rating with user_id injected
    rating_data = rating.model_dump()
    rating_data["user_id"] = current_user.id
    db_rating = Rating.model_validate(rating_data)
    session.add(db_rating)
    
    # Award XP for new rating
    # Check if first rating for bonus
    rating_count = session.exec(
        select(func.count(Rating.id)).where(Rating.user_id == current_user.id)
    ).one() or 0
    
    xp_amount = XP_REWARDS["rating_submit"]
    if rating_count == 0:
        xp_amount += XP_REWARDS["first_rating"]  # Bonus for first rating
    
    award_xp(session, current_user, xp_amount, "rating")
    update_streak(session, current_user)
    check_and_award_badges(session, current_user)
    
    session.commit()
    session.refresh(db_rating)
    return db_rating

@router.get("/ratings/average", response_model=float)
def get_average_rating(
    show_id: Optional[int] = None,
    song_id: Optional[int] = None,
    performance_id: Optional[int] = None,
    venue_id: Optional[int] = None,
    tour_id: Optional[int] = None,
    session: Session = Depends(get_session)
):
    query = select(func.avg(Rating.score))
    if show_id:
        query = query.where(Rating.show_id == show_id)
    elif song_id:
        query = query.where(Rating.song_id == song_id)
    elif performance_id:
        query = query.where(Rating.performance_id == performance_id)
    elif venue_id:
        query = query.where(Rating.venue_id == venue_id)
    elif tour_id:
        query = query.where(Rating.tour_id == tour_id)
    else:
        # Return 0 if no entity specified instead of error (graceful degradation)
        return 0.0
        
    avg = session.exec(query).first()
    return float(avg) if avg else 0.0

@router.get("/ratings/me")
def get_my_rating(
    show_id: Optional[int] = None,
    song_id: Optional[int] = None,
    performance_id: Optional[int] = None,
    venue_id: Optional[int] = None,
    tour_id: Optional[int] = None,
    current_user: User = Depends(get_current_user),
    session: Session = Depends(get_session)
):
    """Get current user's rating for an entity"""
    query = select(Rating).where(Rating.user_id == current_user.id)
    if show_id:
        query = query.where(Rating.show_id == show_id)
    elif song_id:
        query = query.where(Rating.song_id == song_id)
    elif performance_id:
        query = query.where(Rating.performance_id == performance_id)
    elif venue_id:
        query = query.where(Rating.venue_id == venue_id)
    elif tour_id:
        query = query.where(Rating.tour_id == tour_id)
    else:
        return None
    
    rating = session.exec(query).first()
    return {"score": rating.score if rating else None, "id": rating.id if rating else None}

# --- Reactions ---

@router.post("/reactions", response_model=ReactionRead)
def toggle_reaction(
    reaction: ReactionCreate,
    session: Session = Depends(get_session),
    current_user: User = Depends(get_current_user)
):
    query = select(Reaction).where(
        Reaction.user_id == current_user.id,
        Reaction.entity_type == reaction.entity_type,
        Reaction.entity_id == reaction.entity_id
    )
    existing = session.exec(query).first()
    
    if existing:
        if existing.emoji == reaction.emoji:
            # Toggle off
            session.delete(existing)
            session.commit()
            return existing 
        else:
            # Change emoji
            existing.emoji = reaction.emoji
            session.add(existing)
            session.commit()
            session.refresh(existing)
            return existing
    
    # Create new
    db_reaction = Reaction.model_validate(reaction)
    db_reaction.user_id = current_user.id
    session.add(db_reaction)
    session.commit()
    session.refresh(db_reaction)
    
    return db_reaction

@router.get("/reactions/counts")
def get_reaction_counts(
    entity_type: str,
    entity_id: int,
    session: Session = Depends(get_session)
):
    # Group by emoji and count
    query = select(Reaction.emoji, func.count(Reaction.id)).where(
        Reaction.entity_type == entity_type,
        Reaction.entity_id == entity_id
    ).group_by(Reaction.emoji)
    
    results = session.exec(query).all()
    # returns list of (emoji, count)
    return {emoji: count for emoji, count in results}

@router.get("/reactions/me")
def get_my_reaction(
    entity_type: str, 
    entity_id: int, 
    current_user: User = Depends(get_current_user),
    session: Session = Depends(get_session)
):
    query = select(Reaction).where(
        Reaction.user_id == current_user.id,
        Reaction.entity_type == entity_type,
        Reaction.entity_id == entity_id
    )
    return session.exec(query).first()
