"""Media service types, protocols, and data classes."""

import logging
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
from typing import Any, Dict, List, Optional, Protocol, runtime_checkable
from uuid import UUID

# Handle database imports gracefully for research agent
try:
    from ..database.models import MediaFile
except ImportError:
    # Create stub class when database models aren't available
    class MediaFile:
        pass

logger = logging.getLogger(__name__)


class MediaStatus(Enum):
    """Media file processing status."""

    PENDING = "pending"
    DOWNLOADING = "downloading"
    PROCESSING = "processing"
    READY = "ready"
    FAILED = "failed"


class MediaError(Exception):
    """Base exception for media processing errors."""
    pass


class DownloadError(MediaError):
    """Exception raised when download fails."""
    pass


class PreprocessingError(MediaError):
    """Exception raised when preprocessing fails."""
    pass


class ValidationError(MediaError):
    """Exception raised when validation fails."""
    pass


@dataclass
class DownloadProgress:
    """Download progress information."""

    downloaded_bytes: int
    total_bytes: Optional[int]
    speed: Optional[float]
    eta: Optional[int]
    status: str
    percentage: float = 0.0


@dataclass
class ProcessingProgress:
    """Processing progress information."""

    stage: str
    current_step: int
    total_steps: int
    status: str
    message: str
    start_time: float
    elapsed_time: float = 0.0


@dataclass
class MediaFileInfo:
    """Information about a media file."""

    filename: str
    file_size: int
    duration: Optional[float]
    mime_type: Optional[str]
    source_path: str
    local_path: Optional[str]
    file_hash: Optional[str]
    metadata: Dict[str, Any]


@dataclass
class TelemetryData:
    """Telemetry data for monitoring service performance."""

    operation: str
    start_time: float
    end_time: float = 0.0
    duration: float = 0.0
    success: bool = False
    error_type: Optional[str] = None
    error_message: Optional[str] = None
    file_size: Optional[int] = None
    download_speed: Optional[float] = None


@runtime_checkable
class ProgressCallback(Protocol):
    """Protocol for progress callback functions."""

    def __call__(self, progress: DownloadProgress | ProcessingProgress) -> None:
        """Handle progress updates."""
        ...


@runtime_checkable
class MediaDownloadProtocol(Protocol):
    """Protocol for media download operations."""

    async def download_media(self, url: str, output_dir: Path, progress_callback: Optional[ProgressCallback] = None) -> MediaFileInfo:
        """Download media from URL to local directory."""
        ...


@runtime_checkable
class MediaPreprocessingProtocol(Protocol):
    """Protocol for media preprocessing operations."""

    async def preprocess_audio(
        self, input_path: Path, output_path: Path, progress_callback: Optional[ProgressCallback] = None
    ) -> bool:
        """Convert audio to 16kHz mono WAV format for Whisper processing."""
        ...

    async def validate_file_size(self, file_path: Path, max_size_mb: int = 500) -> bool:
        """Validate that file size is within limits."""
        ...

    async def check_audio_quality(self, audio_path: Path) -> bool:
        """Check if audio file has valid content (not silent, duration >0.1s)."""
        ...

    async def get_media_info(self, file_path: Path) -> Dict[str, Any]:
        """Get media file information using FFmpeg."""
        ...


@runtime_checkable
class MediaDatabaseProtocol(Protocol):
    """Protocol for media database operations."""

    async def create_media_file_record(self, media_info: MediaFileInfo, youtube_video_id: Optional[UUID] = None) -> MediaFile:
        """Create a media file record in the database."""
        ...

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

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

    async def get_pending_media_files(self, limit: int = 50) -> List[MediaFile]:
        """Get pending media files from the database."""
        ...

    async def get_ready_media_files(self, limit: int = 50) -> List[MediaFile]:
        """Get ready media files from the database."""
        ...


@runtime_checkable
class MediaServiceProtocol(Protocol):
    """Protocol for complete media service implementations."""

    async def download_media(self, url: str, output_dir: Path, progress_callback: Optional[ProgressCallback] = None) -> MediaFileInfo:
        """Download media from URL to local directory."""
        ...

    async def preprocess_audio(
        self, input_path: Path, output_path: Path, progress_callback: Optional[ProgressCallback] = None
    ) -> bool:
        """Convert audio to 16kHz mono WAV format for Whisper processing."""
        ...

    async def validate_file_size(self, file_path: Path, max_size_mb: int = 500) -> bool:
        """Validate that file size is within limits."""
        ...

    async def check_audio_quality(self, audio_path: Path) -> bool:
        """Check if audio file has valid content (not silent, duration >0.1s)."""
        ...

    async def get_media_info(self, file_path: Path) -> Dict[str, Any]:
        """Get media file information using FFmpeg."""
        ...

    async def create_media_file_record(self, media_info: MediaFileInfo, youtube_video_id: Optional[UUID] = None) -> MediaFile:
        """Create a media file record in the database."""
        ...

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

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

    async def get_pending_media_files(self, limit: int = 50) -> List[MediaFile]:
        """Get pending media files from the database."""
        ...

    async def get_ready_media_files(self, limit: int = 50) -> List[MediaFile]:
        """Get ready media files from the database."""
        ...

    async def process_media_pipeline(self, url: str, output_dir: Path, youtube_video_id: Optional[UUID] = None, progress_callback: Optional[ProgressCallback] = None) -> MediaFile:
        """Complete media processing pipeline from download to ready."""
        ...

    def get_telemetry_data(self) -> List[TelemetryData]:
        """Get telemetry data for monitoring."""
        ...

    def clear_telemetry_data(self) -> None:
        """Clear telemetry data."""
        ...
