"""Service protocols for Trax platform.

This module defines all service protocols using Python's Protocol class to ensure
clean interfaces and testability. All services should implement these protocols.
"""

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

# from ..database.models import MediaFile, TranscriptionJob, TranscriptionResult
# Note: For research agent, we use the dataclass definitions below

# Temporary stubs for missing database models (when running without database)
try:
    from ..database.models import MediaFile, TranscriptionJob, TranscriptionResult as DBTranscriptionResult
except ImportError:
    # Create stub classes when database models aren't available
    from typing import Any
    
    class MediaFile:
        pass
    
    class TranscriptionJob:
        pass
    
    class DBTranscriptionResult:
        pass

logger = logging.getLogger(__name__)


# Re-export existing types from media_types for backward compatibility
from .media_types import (
    MediaStatus,
    MediaError,
    DownloadError,
    PreprocessingError,
    ValidationError,
    DownloadProgress,
    ProcessingProgress,
    MediaFileInfo,
    TelemetryData,
    ProgressCallback,
)


class TranscriptionStatus(Enum):
    """Transcription processing status."""
    PENDING = "pending"
    PROCESSING = "processing"
    COMPLETED = "completed"
    FAILED = "failed"


class ExportFormat(Enum):
    """Supported export formats."""
    JSON = "json"
    TXT = "txt"
    SRT = "srt"
    MARKDOWN = "md"


@dataclass
class TranscriptionConfig:
    """Configuration for transcription processing."""
    model: str = "whisper-1"
    language: Optional[str] = None
    prompt: Optional[str] = None
    response_format: str = "verbose_json"
    temperature: float = 0.0


@dataclass
class TranscriptionResult:
    """Result of transcription processing."""
    raw_content: str
    segments: List[Dict[str, Any]]
    confidence_scores: List[float]
    accuracy_estimate: float
    word_count: int
    processing_time_ms: float
    model_used: str


@dataclass
class EnhancementResult:
    """Result of transcript enhancement."""
    original_text: str
    enhanced_text: str
    improvements: List[str]
    confidence_score: float
    processing_time: float


@dataclass
class ExportResult:
    """Result of export operation."""
    format: ExportFormat
    file_path: Path
    file_size: int
    success: bool
    error_message: Optional[str] = None


@dataclass
class BatchTask:
    """Batch processing task."""
    task_id: UUID
    task_type: str
    input_data: Dict[str, Any]
    status: str
    created_at: float
    started_at: Optional[float] = None
    completed_at: Optional[float] = None
    result: Optional[Dict[str, Any]] = None
    error: Optional[str] = None


@dataclass
class BatchProgress:
    """Batch processing progress."""
    total_tasks: int
    completed_tasks: int
    failed_tasks: int
    in_progress_tasks: int
    pending_tasks: int
    overall_progress: float


@dataclass
class ResearchQuery:
    """Research query request."""
    query: str
    context: Optional[str] = None
    max_tokens: int = 4000
    temperature: float = 0.1
    model: str = "perplexity/sonar-reasoning-pro"


@dataclass
class ResearchResult:
    """Result of research query."""
    query: str
    answer: str
    sources: List[str]
    confidence_score: float
    processing_time: float
    model_used: str
    token_usage: Dict[str, int]


@runtime_checkable
class ResearchServiceProtocol(Protocol):
    """Protocol for AI research services."""

    async def research(self, query: ResearchQuery) -> ResearchResult:
        """Perform a research query."""
        ...

    async def batch_research(self, queries: List[ResearchQuery]) -> List[ResearchResult]:
        """Perform multiple research queries."""
        ...

    def get_available_models(self) -> List[str]:
        """Get list of available research models."""
        ...


@runtime_checkable
class YouTubeServiceProtocol(Protocol):
    """Protocol for YouTube metadata extraction services."""

    async def extract_metadata(self, url: str) -> Dict[str, Any]:
        """Extract metadata from a YouTube URL."""
        ...

    async def batch_extract(self, urls: List[str]) -> List[Dict[str, Any]]:
        """Extract metadata from multiple YouTube URLs."""
        ...


@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."""
        ...


@runtime_checkable
class TranscriptionServiceProtocol(Protocol):
    """Protocol for transcription services."""

    async def transcribe_file(
        self, 
        media_file: MediaFile, 
        config: Optional[TranscriptionConfig] = None
    ) -> TranscriptionResult:
        """Transcribe a media file."""
        ...

    async def transcribe_audio(
        self, 
        audio_path: Path, 
        config: Optional[TranscriptionConfig] = None
    ) -> TranscriptionResult:
        """Transcribe audio from file path."""
        ...

    async def create_transcription_job(
        self, 
        media_file: MediaFile, 
        config: Optional[TranscriptionConfig] = None
    ) -> TranscriptionJob:
        """Create a transcription job."""
        ...

    async def get_job_status(self, job_id: UUID) -> TranscriptionStatus:
        """Get transcription job status."""
        ...

    async def cancel_job(self, job_id: UUID) -> bool:
        """Cancel a transcription job."""
        ...


@runtime_checkable
class EnhancementServiceProtocol(Protocol):
    """Protocol for enhancement services."""

    async def initialize(self) -> None:
        """Initialize the enhancement service."""
        ...

    async def enhance_transcript(self, transcript: str, **kwargs) -> EnhancementResult:
        """Enhance a transcript."""
        ...

    async def enhance_transcript_batch(
        self, 
        transcripts: List[str], 
        **kwargs
    ) -> List[EnhancementResult]:
        """Enhance multiple transcripts."""
        ...

    async def enhance_transcription_result(
        self, 
        transcription_result: TranscriptionResult, 
        **kwargs
    ) -> EnhancementResult:
        """Enhance a transcription result from the database."""
        ...


@runtime_checkable
class ExportServiceProtocol(Protocol):
    """Protocol for export services."""

    async def export_transcript(
        self, 
        transcription_result: TranscriptionResult, 
        output_path: Path, 
        format: ExportFormat
    ) -> ExportResult:
        """Export a transcript to the specified format."""
        ...

    async def export_batch(
        self, 
        transcription_results: List[TranscriptionResult], 
        output_dir: Path, 
        format: ExportFormat
    ) -> List[ExportResult]:
        """Export multiple transcripts to the specified format."""
        ...

    def get_supported_formats(self) -> List[ExportFormat]:
        """Get list of supported export formats."""
        ...


@runtime_checkable
class BatchProcessorProtocol(Protocol):
    """Protocol for batch processing services."""

    async def add_task(self, task_type: str, input_data: Dict[str, Any]) -> UUID:
        """Add a new task to the batch processor."""
        ...

    async def process_tasks(self, max_workers: int = 4) -> None:
        """Process all pending tasks."""
        ...

    async def get_progress(self) -> BatchProgress:
        """Get current batch processing progress."""
        ...

    async def cancel_task(self, task_id: UUID) -> bool:
        """Cancel a specific task."""
        ...

    async def get_task_status(self, task_id: UUID) -> Optional[BatchTask]:
        """Get status of a specific task."""
        ...

    async def get_completed_tasks(self, limit: int = 100) -> List[BatchTask]:
        """Get list of completed tasks."""
        ...


# Additional specialized protocols for specific operations

@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."""
        ...


# Protocol validation utilities

def validate_protocol_implementation(instance: Any, protocol: type) -> bool:
    """Validate that an instance implements a protocol correctly."""
    if not isinstance(protocol, type):
        return False
    
    if not hasattr(protocol, '__subclasshook__'):
        return False
    
    return isinstance(instance, protocol)


def get_missing_methods(instance: Any, protocol: type) -> List[str]:
    """Get list of missing methods for protocol implementation."""
    if not hasattr(protocol, '__subclasshook__'):
        return []
    
    missing_methods = []
    for attr_name in dir(protocol):
        if attr_name.startswith('_'):
            continue
        
        attr = getattr(protocol, attr_name)
        if callable(attr) and not hasattr(instance, attr_name):
            missing_methods.append(attr_name)
    
    return missing_methods
