"""
File serving router for VFX Project Management System.
Handles authenticated file serving, thumbnails, and access control.
"""

from fastapi import APIRouter, Depends, HTTPException, Response
from fastapi.responses import FileResponse, StreamingResponse
from sqlalchemy.orm import Session
from pathlib import Path
import os
import mimetypes
from typing import Optional

from database import get_db
from models.task import Task, TaskAttachment, Submission
from models.user import User, UserRole
from utils.auth import get_current_user_from_token, _get_user_from_db
from utils.file_handler import file_handler

router = APIRouter()


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


def check_file_access_permission(user: User, task: Task, db: Session) -> bool:
    """Check if user has permission to access files for a task."""
    from models.project import ProjectMember
    
    # Admins and coordinators can access all files
    if user.role == UserRole.COORDINATOR or user.is_admin:
        return True
    
    # Directors can access all files for review
    if user.role == UserRole.DIRECTOR:
        return True
    
    # Artists can access files for their assigned tasks
    if task.assigned_user_id == user.id:
        return True
    
    # Artists can also access files for tasks in projects they're members of
    if user.role == UserRole.ARTIST:
        # Get the project_id from the task's asset or shot
        project_id = None
        if task.asset_id:
            from models.asset import Asset
            asset = db.query(Asset).filter(Asset.id == task.asset_id).first()
            if asset:
                project_id = asset.project_id
        elif task.shot_id:
            from models.shot import Shot
            shot = db.query(Shot).filter(Shot.id == task.shot_id).first()
            if shot:
                from models.episode import Episode
                episode = db.query(Episode).filter(Episode.id == shot.episode_id).first()
                if episode:
                    project_id = episode.project_id
        
        # Check if user is a project member
        if project_id:
            member = db.query(ProjectMember).filter(
                ProjectMember.project_id == project_id,
                ProjectMember.user_id == user.id
            ).first()
            if member:
                return True
    
    return False


@router.get("/attachments/{attachment_id}")
async def serve_attachment(
    attachment_id: int,
    thumbnail: bool = False,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Serve a task attachment file with access control."""
    
    # Get attachment
    attachment = db.query(TaskAttachment).filter(
        TaskAttachment.id == attachment_id,
        TaskAttachment.deleted_at.is_(None)
    ).first()
    if not attachment:
        raise HTTPException(status_code=404, detail="Attachment not found")
    
    # Get associated task
    task = db.query(Task).filter(Task.id == attachment.task_id).first()
    if not task:
        raise HTTPException(status_code=404, detail="Associated task not found")
    
    # Check permissions
    if not check_file_access_permission(current_user, task, db):
        raise HTTPException(status_code=403, detail="Not authorized to access this file")
    
    # Determine file path
    if thumbnail and file_handler.is_image_file(attachment.file_path):
        # Try to serve thumbnail
        thumbnail_path = file_handler.get_thumbnail_path(attachment.file_path)
        absolute_thumbnail_path = file_handler.resolve_absolute_path(thumbnail_path)
        if os.path.exists(absolute_thumbnail_path):
            file_path = absolute_thumbnail_path
            filename = f"thumb_{attachment.file_name}"
        else:
            # Create thumbnail on-demand
            created_thumbnail = file_handler.create_thumbnail(attachment.file_path)
            if created_thumbnail:
                absolute_created_thumbnail = file_handler.resolve_absolute_path(created_thumbnail)
                if os.path.exists(absolute_created_thumbnail):
                    file_path = absolute_created_thumbnail
                    filename = f"thumb_{attachment.file_name}"
                else:
                    # Fall back to original file
                    file_path = file_handler.resolve_absolute_path(attachment.file_path)
                    filename = attachment.file_name
            else:
                # Fall back to original file
                file_path = file_handler.resolve_absolute_path(attachment.file_path)
                filename = attachment.file_name
    else:
        file_path = file_handler.resolve_absolute_path(attachment.file_path)
        filename = attachment.file_name
    
    # Check if file exists
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="File not found on disk")
    
    # Get MIME type
    mime_type, _ = mimetypes.guess_type(file_path)
    if not mime_type:
        mime_type = 'application/octet-stream'
    
    # Return file
    return FileResponse(
        path=file_path,
        filename=filename,
        media_type=mime_type
    )


@router.get("/submissions/{submission_id}")
async def serve_submission(
    submission_id: int,
    thumbnail: bool = False,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Serve a submission file with access control."""
    
    # Get submission
    submission = db.query(Submission).filter(
        Submission.id == submission_id,
        Submission.deleted_at.is_(None)
    ).first()
    if not submission:
        raise HTTPException(status_code=404, detail="Submission not found")
    
    # Get associated task
    task = db.query(Task).filter(Task.id == submission.task_id).first()
    if not task:
        raise HTTPException(status_code=404, detail="Associated task not found")
    
    # Check permissions
    if not check_file_access_permission(current_user, task, db):
        raise HTTPException(status_code=403, detail="Not authorized to access this file")
    
    # Determine file path
    if thumbnail and file_handler.is_image_file(submission.file_path):
        # Try to serve thumbnail
        thumbnail_path = file_handler.get_thumbnail_path(submission.file_path)
        absolute_thumbnail_path = file_handler.resolve_absolute_path(thumbnail_path)
        if os.path.exists(absolute_thumbnail_path):
            file_path = absolute_thumbnail_path
            filename = f"thumb_{submission.file_name}"
        else:
            # Create thumbnail on-demand
            created_thumbnail = file_handler.create_thumbnail(submission.file_path)
            if created_thumbnail:
                absolute_created_thumbnail = file_handler.resolve_absolute_path(created_thumbnail)
                if os.path.exists(absolute_created_thumbnail):
                    file_path = absolute_created_thumbnail
                    filename = f"thumb_{submission.file_name}"
                else:
                    # Fall back to original file
                    file_path = file_handler.resolve_absolute_path(submission.file_path)
                    filename = submission.file_name
            else:
                # Fall back to original file
                file_path = file_handler.resolve_absolute_path(submission.file_path)
                filename = submission.file_name
    else:
        file_path = file_handler.resolve_absolute_path(submission.file_path)
        filename = submission.file_name
    
    # Check if file exists
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="File not found on disk")
    
    # Get MIME type
    mime_type, _ = mimetypes.guess_type(file_path)
    if not mime_type:
        mime_type = 'application/octet-stream'
    
    # Return file
    return FileResponse(
        path=file_path,
        filename=filename,
        media_type=mime_type
    )


@router.get("/submissions/{submission_id}/stream")
async def stream_submission(
    submission_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Stream a submission file for video playback."""
    
    # Get submission
    submission = db.query(Submission).filter(
        Submission.id == submission_id,
        Submission.deleted_at.is_(None)
    ).first()
    if not submission:
        raise HTTPException(status_code=404, detail="Submission not found")
    
    # Get associated task
    task = db.query(Task).filter(Task.id == submission.task_id).first()
    if not task:
        raise HTTPException(status_code=404, detail="Associated task not found")
    
    # Check permissions
    if not check_file_access_permission(current_user, task, db):
        raise HTTPException(status_code=403, detail="Not authorized to access this file")
    
    file_path = file_handler.resolve_absolute_path(submission.file_path)
    
    # Check if file exists
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="File not found on disk")
    
    # Only stream video files
    if not file_handler.is_video_file(file_path):
        raise HTTPException(status_code=400, detail="File is not a video")
    
    # Get MIME type
    mime_type, _ = mimetypes.guess_type(file_path)
    if not mime_type:
        mime_type = 'video/mp4'  # Default for video
    
    def iterfile(file_path: str):
        """Generator to stream file in chunks."""
        with open(file_path, mode="rb") as file_like:
            while True:
                chunk = file_like.read(1024 * 1024)  # 1MB chunks
                if not chunk:
                    break
                yield chunk
    
    return StreamingResponse(
        iterfile(file_path),
        media_type=mime_type,
        headers={
            "Content-Disposition": f"inline; filename={submission.file_name}",
            "Accept-Ranges": "bytes"
        }
    )


@router.get("/info/attachment/{attachment_id}")
async def get_attachment_info(
    attachment_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Get file information for an attachment."""
    
    # Get attachment
    attachment = db.query(TaskAttachment).filter(
        TaskAttachment.id == attachment_id,
        TaskAttachment.deleted_at.is_(None)
    ).first()
    if not attachment:
        raise HTTPException(status_code=404, detail="Attachment not found")
    
    # Get associated task
    task = db.query(Task).filter(Task.id == attachment.task_id).first()
    if not task:
        raise HTTPException(status_code=404, detail="Associated task not found")
    
    # Check permissions
    if not check_file_access_permission(current_user, task, db):
        raise HTTPException(status_code=403, detail="Not authorized to access this file")
    
    # Get file info
    file_info = file_handler.get_file_info(attachment.file_path)
    
    return {
        "id": attachment.id,
        "file_name": attachment.file_name,
        "file_type": attachment.file_type,
        "file_size": attachment.file_size,
        "attachment_type": attachment.attachment_type,
        "description": attachment.description,
        "uploaded_at": attachment.uploaded_at,
        "is_image": file_handler.is_image_file(attachment.file_path),
        "is_video": file_handler.is_video_file(attachment.file_path),
        "has_thumbnail": file_handler.is_image_file(attachment.file_path),
        "file_exists": file_info.get('exists', False),
        **file_info
    }


@router.get("/info/submission/{submission_id}")
async def get_submission_info(
    submission_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Get file information for a submission."""
    
    # Get submission
    submission = db.query(Submission).filter(
        Submission.id == submission_id,
        Submission.deleted_at.is_(None)
    ).first()
    if not submission:
        raise HTTPException(status_code=404, detail="Submission not found")
    
    # Get associated task
    task = db.query(Task).filter(Task.id == submission.task_id).first()
    if not task:
        raise HTTPException(status_code=404, detail="Associated task not found")
    
    # Check permissions
    if not check_file_access_permission(current_user, task, db):
        raise HTTPException(status_code=403, detail="Not authorized to access this file")
    
    # Get file info
    file_info = file_handler.get_file_info(submission.file_path)
    
    return {
        "id": submission.id,
        "file_name": submission.file_name,
        "version_number": submission.version_number,
        "notes": submission.notes,
        "submitted_at": submission.submitted_at,
        "is_image": file_handler.is_image_file(submission.file_path),
        "is_video": file_handler.is_video_file(submission.file_path),
        "has_thumbnail": file_handler.is_image_file(submission.file_path),
        "file_exists": file_info.get('exists', False),
        **file_info
    }


@router.get("/projects/{project_id}/thumbnail")
async def serve_project_thumbnail(
    project_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Serve a project thumbnail image with access control."""
    from models.project import Project
    from models.project import ProjectMember
    
    # Get project
    project = db.query(Project).filter(Project.id == project_id).first()
    if not project:
        raise HTTPException(status_code=404, detail="Project not found")
    
    # Check if user has access to this project
    # Artists can only access projects they're members of
    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=403, detail="Access denied to this project")
    
    # Check if project has a thumbnail
    if not project.thumbnail_path:
        raise HTTPException(status_code=404, detail="Project has no thumbnail")
    
    # Resolve to absolute path for file serving
    absolute_thumbnail_path = file_handler.resolve_absolute_path(project.thumbnail_path)
    
    # Check if file exists
    if not os.path.exists(absolute_thumbnail_path):
        raise HTTPException(status_code=404, detail="Thumbnail file not found on disk")
    
    # Get MIME type
    mime_type, _ = mimetypes.guess_type(absolute_thumbnail_path)
    if not mime_type:
        mime_type = 'image/jpeg'  # Default for thumbnails
    
    # Return file
    return FileResponse(
        path=absolute_thumbnail_path,
        media_type=mime_type
    )


@router.get("/users/{user_id}/avatar")
async def serve_user_avatar(
    user_id: int,
    db: Session = Depends(get_db)
):
    """Serve user avatar (public access for simplicity)."""
    
    # Get user
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    
    # Check if user has avatar
    if not user.avatar_url:
        raise HTTPException(status_code=404, detail="User has no avatar")
    
    # Note: Avatar access is public for simplicity since img tags can't send auth headers
    # More restrictive access control can be added later if needed
    
    # Resolve to absolute path for file serving
    absolute_avatar_path = file_handler.resolve_absolute_path(user.avatar_url)
    
    # Check if file exists
    if not os.path.exists(absolute_avatar_path):
        raise HTTPException(status_code=404, detail="Avatar file not found on disk")
    
    # Get MIME type
    mime_type, _ = mimetypes.guess_type(absolute_avatar_path)
    if not mime_type:
        mime_type = 'image/jpeg'  # Default for avatars
    
    # Return file
    return FileResponse(
        path=absolute_avatar_path,
        media_type=mime_type
    )
