"""Media file repository for database operations."""

import logging
from typing import Any, Dict, List, Optional, Protocol, runtime_checkable
from uuid import UUID

from ..database.models import MediaFile
from ..database.connection import get_db_session

logger = logging.getLogger(__name__)


@runtime_checkable
class MediaRepositoryProtocol(Protocol):
    """Protocol for Media file repository operations."""

    async def create(self, media_data: Dict[str, Any]) -> MediaFile:
        """Create a new Media file record."""
        ...

    async def get_by_id(self, media_id: UUID) -> Optional[MediaFile]:
        """Get media file by ID."""
        ...

    async def get_by_filename(self, filename: str) -> Optional[MediaFile]:
        """Get media file by filename."""
        ...

    async def get_by_file_hash(self, file_hash: str) -> Optional[MediaFile]:
        """Get media file by file hash."""
        ...

    async def update(self, media_id: UUID, media_data: Dict[str, Any]) -> Optional[MediaFile]:
        """Update media file record."""
        ...

    async def delete(self, media_id: UUID) -> bool:
        """Delete media file record."""
        ...

    async def list_all(self, limit: int = 100, offset: int = 0) -> List[MediaFile]:
        """List all media files with pagination."""
        ...

    async def get_by_status(self, status: str, limit: int = 50) -> List[MediaFile]:
        """Get media files by status."""
        ...

    async def get_by_youtube_video_id(self, youtube_video_id: UUID, limit: int = 50) -> List[MediaFile]:
        """Get media files by YouTube video ID."""
        ...

    async def update_status(self, media_id: UUID, status: str) -> Optional[MediaFile]:
        """Update media file status."""
        ...

    async def get_pending_files(self, limit: int = 50) -> List[MediaFile]:
        """Get media files with pending status."""
        ...

    async def get_ready_files(self, limit: int = 50) -> List[MediaFile]:
        """Get media files with ready status."""
        ...


class MediaRepository:
    """Media file repository implementation."""

    def __init__(self):
        pass

    async def create(self, media_data: Dict[str, Any]) -> MediaFile:
        """Create a new Media file record."""
        try:
            with get_db_session() as session:
                media = MediaFile(**media_data)
                session.add(media)
                session.commit()
                session.refresh(media)
                logger.info(f"Created Media file: {media.filename}")
                return media
        except Exception as e:
            logger.error(f"Error creating Media file: {e}")
            raise

    async def get_by_id(self, media_id: UUID) -> Optional[MediaFile]:
        """Get media file by ID."""
        try:
            with get_db_session() as session:
                media = session.query(MediaFile).filter(MediaFile.id == media_id).first()
                return media
        except Exception as e:
            logger.error(f"Error getting media file by ID: {e}")
            return None

    async def get_by_filename(self, filename: str) -> Optional[MediaFile]:
        """Get media file by filename."""
        try:
            with get_db_session() as session:
                media = session.query(MediaFile).filter(MediaFile.filename == filename).first()
                return media
        except Exception as e:
            logger.error(f"Error getting media file by filename: {e}")
            return None

    async def get_by_file_hash(self, file_hash: str) -> Optional[MediaFile]:
        """Get media file by file hash."""
        try:
            with get_db_session() as session:
                media = session.query(MediaFile).filter(MediaFile.file_hash == file_hash).first()
                return media
        except Exception as e:
            logger.error(f"Error getting media file by hash: {e}")
            return None

    async def update(self, media_id: UUID, media_data: Dict[str, Any]) -> Optional[MediaFile]:
        """Update media file record."""
        try:
            with get_db_session() as session:
                media = session.query(MediaFile).filter(MediaFile.id == media_id).first()
                if not media:
                    return None
                
                for key, value in media_data.items():
                    if hasattr(media, key):
                        setattr(media, key, value)
                
                session.commit()
                session.refresh(media)
                logger.info(f"Updated Media file: {media.filename}")
                return media
        except Exception as e:
            logger.error(f"Error updating Media file: {e}")
            raise

    async def delete(self, media_id: UUID) -> bool:
        """Delete media file record."""
        try:
            with get_db_session() as session:
                media = session.query(MediaFile).filter(MediaFile.id == media_id).first()
                if not media:
                    return False
                
                session.delete(media)
                session.commit()
                logger.info(f"Deleted Media file: {media.filename}")
                return True
        except Exception as e:
            logger.error(f"Error deleting Media file: {e}")
            return False

    async def list_all(self, limit: int = 100, offset: int = 0) -> List[MediaFile]:
        """List all media files with pagination."""
        try:
            with get_db_session() as session:
                media_files = session.query(MediaFile).offset(offset).limit(limit).all()
                return media_files
        except Exception as e:
            logger.error(f"Error listing media files: {e}")
            return []

    async def get_by_status(self, status: str, limit: int = 50) -> List[MediaFile]:
        """Get media files by status."""
        try:
            with get_db_session() as session:
                media_files = session.query(MediaFile).filter(
                    MediaFile.status == status
                ).limit(limit).all()
                return media_files
        except Exception as e:
            logger.error(f"Error getting media files by status: {e}")
            return []

    async def get_by_youtube_video_id(self, youtube_video_id: UUID, limit: int = 50) -> List[MediaFile]:
        """Get media files by YouTube video ID."""
        try:
            with get_db_session() as session:
                media_files = session.query(MediaFile).filter(
                    MediaFile.youtube_video_id == youtube_video_id
                ).limit(limit).all()
                return media_files
        except Exception as e:
            logger.error(f"Error getting media files by YouTube video ID: {e}")
            return []

    async def update_status(self, media_id: UUID, status: str) -> Optional[MediaFile]:
        """Update media file status."""
        try:
            with get_db_session() as session:
                media = session.query(MediaFile).filter(MediaFile.id == media_id).first()
                if not media:
                    return None
                
                media.status = status
                session.commit()
                session.refresh(media)
                logger.info(f"Updated Media file status: {media.filename} -> {status}")
                return media
        except Exception as e:
            logger.error(f"Error updating Media file status: {e}")
            raise

    async def get_pending_files(self, limit: int = 50) -> List[MediaFile]:
        """Get media files with pending status."""
        try:
            with get_db_session() as session:
                media_files = session.query(MediaFile).filter(
                    MediaFile.status == "pending"
                ).limit(limit).all()
                return media_files
        except Exception as e:
            logger.error(f"Error getting pending media files: {e}")
            return []

    async def get_ready_files(self, limit: int = 50) -> List[MediaFile]:
        """Get media files with ready status."""
        try:
            with get_db_session() as session:
                media_files = session.query(MediaFile).filter(
                    MediaFile.status == "ready"
                ).limit(limit).all()
                return media_files
        except Exception as e:
            logger.error(f"Error getting ready media files: {e}")
            return []


# Factory function for creating media repository instances
def create_media_repository() -> MediaRepository:
    """Create a new MediaRepository instance."""
    return MediaRepository()
