from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy import func
from typing import List

from database import get_db
from models.episode import Episode
from models.project import Project, ProjectMember
from models.user import User, UserRole
from models.shot import Shot
from schemas.episode import EpisodeCreate, EpisodeUpdate, EpisodeResponse, EpisodeListResponse
from utils.auth import get_current_user, require_role, get_current_user_from_token

router = APIRouter()


def get_current_user_with_db(
    token_data: dict = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """Get current user with proper database dependency."""
    from utils.auth import _get_user_from_db
    return _get_user_from_db(db, token_data["user_id"])


def require_coordinator_or_admin(
    token_data: dict = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """Require coordinator or admin role."""
    from utils.auth import _get_user_from_db
    current_user = _get_user_from_db(db, token_data["user_id"])
    
    if current_user.role != UserRole.COORDINATOR and not current_user.is_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Insufficient permissions"
        )
    return current_user


@router.get("/", response_model=List[EpisodeListResponse])
async def list_episodes(
    project_id: int = None,
    skip: int = 0,
    limit: int = 100,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user_with_db)
):
    """List episodes, optionally filtered by project"""
    query = db.query(Episode)
    
    if project_id:
        # Check if project exists and user has access
        project = db.query(Project).filter(Project.id == project_id).first()
        if not project:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Project not found"
            )
        
        # Check access for artists
        if current_user.role == UserRole.ARTIST:
            member = db.query(ProjectMember).filter(
                ProjectMember.project_id == project_id,
                ProjectMember.user_id == current_user.id
            ).first()
            if not member:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="Access denied to this project"
                )
        
        query = query.filter(Episode.project_id == project_id)
    else:
        # For artists, only show episodes from projects they're members of
        if current_user.role == UserRole.ARTIST:
            user_project_ids = db.query(ProjectMember.project_id).filter(
                ProjectMember.user_id == current_user.id
            ).subquery()
            query = query.filter(Episode.project_id.in_(user_project_ids))
    
    episodes = query.order_by(Episode.episode_number).offset(skip).limit(limit).all()
    
    # Add shot count for each episode
    result = []
    for episode in episodes:
        shot_count = db.query(Shot).filter(Shot.episode_id == episode.id).count()
        episode_data = EpisodeListResponse.model_validate(episode)
        episode_data.shot_count = shot_count
        result.append(episode_data)
    
    return result


@router.post("/", response_model=EpisodeResponse, status_code=status.HTTP_201_CREATED)
async def create_episode(
    episode: EpisodeCreate,
    project_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_coordinator_or_admin)
):
    """Create a new episode within a project"""
    # Check if project exists
    project = db.query(Project).filter(Project.id == project_id).first()
    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Project not found"
        )
    
    # Check if episode number is already used in this project
    existing_episode = db.query(Episode).filter(
        Episode.project_id == project_id,
        Episode.episode_number == episode.episode_number
    ).first()
    
    if existing_episode:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Episode number {episode.episode_number} already exists in this project"
        )
    
    # Create new episode
    db_episode = Episode(
        project_id=project_id,
        **episode.model_dump()
    )
    
    db.add(db_episode)
    db.commit()
    db.refresh(db_episode)
    
    episode_data = EpisodeResponse.model_validate(db_episode)
    episode_data.shot_count = 0  # New episode has no shots yet
    
    return episode_data


@router.get("/{episode_id}", response_model=EpisodeResponse)
async def get_episode(
    episode_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user_with_db)
):
    """Get a specific episode by ID"""
    episode = db.query(Episode).filter(Episode.id == episode_id).first()
    
    if not episode:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Episode not found"
        )
    
    # Check access for artists
    if current_user.role == UserRole.ARTIST:
        member = db.query(ProjectMember).filter(
            ProjectMember.project_id == episode.project_id,
            ProjectMember.user_id == current_user.id
        ).first()
        if not member:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Access denied to this episode"
            )
    
    # Add shot count
    shot_count = db.query(Shot).filter(Shot.episode_id == episode.id).count()
    episode_data = EpisodeResponse.model_validate(episode)
    episode_data.shot_count = shot_count
    
    return episode_data


@router.put("/{episode_id}", response_model=EpisodeResponse)
async def update_episode(
    episode_id: int,
    episode_update: EpisodeUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_coordinator_or_admin)
):
    """Update an episode"""
    db_episode = db.query(Episode).filter(Episode.id == episode_id).first()
    
    if not db_episode:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Episode not found"
        )
    
    # If updating episode number, check for conflicts
    update_data = episode_update.model_dump(exclude_unset=True)
    if 'episode_number' in update_data:
        existing_episode = db.query(Episode).filter(
            Episode.project_id == db_episode.project_id,
            Episode.episode_number == update_data['episode_number'],
            Episode.id != episode_id
        ).first()
        
        if existing_episode:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Episode number {update_data['episode_number']} already exists in this project"
            )
    
    # Update only provided fields
    for field, value in update_data.items():
        setattr(db_episode, field, value)
    
    db.commit()
    db.refresh(db_episode)
    
    # Add shot count
    shot_count = db.query(Shot).filter(Shot.episode_id == db_episode.id).count()
    episode_data = EpisodeResponse.model_validate(db_episode)
    episode_data.shot_count = shot_count
    
    return episode_data


@router.delete("/{episode_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_episode(
    episode_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_coordinator_or_admin)
):
    """Delete an episode"""
    db_episode = db.query(Episode).filter(Episode.id == episode_id).first()
    
    if not db_episode:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Episode not found"
        )
    
    db.delete(db_episode)
    db.commit()


# Project-specific episode endpoints

@router.get("/projects/{project_id}/episodes", response_model=List[EpisodeListResponse])
async def list_project_episodes(
    project_id: int,
    skip: int = 0,
    limit: int = 100,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user_with_db)
):
    """List all episodes for a specific project"""
    # Check if project exists
    project = db.query(Project).filter(Project.id == project_id).first()
    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Project not found"
        )
    
    # Check access for artists
    if current_user.role == UserRole.ARTIST:
        member = db.query(ProjectMember).filter(
            ProjectMember.project_id == project_id,
            ProjectMember.user_id == current_user.id
        ).first()
        if not member:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Access denied to this project"
            )
    
    episodes = db.query(Episode).filter(
        Episode.project_id == project_id
    ).order_by(Episode.episode_number).offset(skip).limit(limit).all()
    
    # Add shot count for each episode
    result = []
    for episode in episodes:
        shot_count = db.query(Shot).filter(Shot.episode_id == episode.id).count()
        episode_data = EpisodeListResponse.model_validate(episode)
        episode_data.shot_count = shot_count
        result.append(episode_data)
    
    return result


@router.post("/projects/{project_id}/episodes", response_model=EpisodeResponse, status_code=status.HTTP_201_CREATED)
async def create_project_episode(
    project_id: int,
    episode: EpisodeCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_coordinator_or_admin)
):
    """Create a new episode within a specific project"""
    return await create_episode(episode, project_id, db, current_user)