"""Media preprocessing service for audio conversion and validation."""

import asyncio
import json
import logging
from pathlib import Path
from typing import Any, Dict, Optional

from .media_types import (
    MediaFileInfo,
    PreprocessingError,
    ProgressCallback,
    ValidationError,
)
from .media_telemetry import MediaTelemetry, ProgressTracker

logger = logging.getLogger(__name__)


class MediaPreprocessingService:
    """Service for preprocessing media files for transcription."""

    def __init__(self, config: Optional[Dict[str, Any]] = None):
        self.telemetry = MediaTelemetry()

    async def _initialize_impl(self) -> None:
        """Initialize the preprocessing service."""
        # Check if FFmpeg is available
        try:
            result = await asyncio.create_subprocess_exec(
                "ffmpeg", "-version",
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE
            )
            await result.communicate()
            if result.returncode != 0:
                raise RuntimeError("FFmpeg not found or not working")
            logger.info("FFmpeg is available")
        except FileNotFoundError:
            raise RuntimeError("FFmpeg not found. Please install FFmpeg 6.0+")

    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."""
        telemetry = self.telemetry.create_telemetry("preprocess")

        try:
            output_path.parent.mkdir(parents=True, exist_ok=True)

            # Step 1: Initialize
            if progress_callback:
                progress = ProgressTracker.create_processing_progress(
                    stage="preprocessing",
                    current_step=1,
                    total_steps=3,
                    status="starting",
                    message="Initializing audio preprocessing",
                    start_time=telemetry.start_time,
                )
                ProgressTracker.notify_progress(progress, progress_callback)

            # Step 2: Convert audio
            cmd = [
                "ffmpeg",
                "-i", str(input_path),
                "-ar", "16000",  # 16kHz sample rate
                "-ac", "1",      # mono
                "-c:a", "pcm_s16le",  # 16-bit PCM
                "-y",            # overwrite output
                str(output_path)
            ]

            logger.info(f"Converting audio: {input_path.name} -> {output_path.name}")

            if progress_callback:
                progress = ProgressTracker.create_processing_progress(
                    stage="preprocessing",
                    current_step=2,
                    total_steps=3,
                    status="converting",
                    message="Converting audio to 16kHz mono WAV",
                    start_time=telemetry.start_time,
                )
                ProgressTracker.notify_progress(progress, progress_callback)

            process = await asyncio.create_subprocess_exec(
                *cmd,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE
            )
            stdout, stderr = await process.communicate()

            if process.returncode != 0:
                raise PreprocessingError(f"FFmpeg error: {stderr.decode()}")

            # Step 3: Validate quality
            if progress_callback:
                progress = ProgressTracker.create_processing_progress(
                    stage="preprocessing",
                    current_step=3,
                    total_steps=3,
                    status="validating",
                    message="Validating audio quality",
                    start_time=telemetry.start_time,
                )
                ProgressTracker.notify_progress(progress, progress_callback)

            # Verify file is not silent
            if not await self.check_audio_quality(output_path):
                raise ValidationError(f"Audio file appears to be silent or too short: {output_path}")

            logger.info(f"Audio preprocessing completed: {output_path}")

            # Update telemetry
            self.telemetry.update_telemetry_success(telemetry)

            if progress_callback:
                progress = ProgressTracker.create_processing_progress(
                    stage="preprocessing",
                    current_step=3,
                    total_steps=3,
                    status="completed",
                    message="Audio preprocessing completed successfully",
                    start_time=telemetry.start_time,
                    elapsed_time=telemetry.duration,
                )
                ProgressTracker.notify_progress(progress, progress_callback)

            return True

        except Exception as e:
            # Update telemetry with error information
            self.telemetry.update_telemetry_error(telemetry, e)

            logger.error(f"Error preprocessing audio: {str(e)}")
            if isinstance(e, (PreprocessingError, ValidationError)):
                raise
            else:
                raise PreprocessingError(f"Preprocessing failed: {str(e)}") from e

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

        file_size_mb = file_path.stat().st_size / (1024 * 1024)
        return file_size_mb <= max_size_mb

    async def check_audio_quality(self, audio_path: Path) -> bool:
        """Check if audio file has valid content (not silent, duration >0.1s)."""
        try:
            # Use FFmpeg to get audio duration
            cmd = [
                "ffprobe",
                "-v", "quiet",
                "-show_entries", "format=duration",
                "-of", "csv=p=0",
                str(audio_path)
            ]

            process = await asyncio.create_subprocess_exec(
                *cmd,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE
            )
            stdout, stderr = await process.communicate()

            if process.returncode != 0:
                logger.error(f"FFprobe error: {stderr.decode()}")
                return False

            duration_str = stdout.decode().strip()
            if not duration_str:
                return False

            duration = float(duration_str)
            return duration > 0.1  # Must be longer than 0.1 seconds

        except Exception as e:
            logger.error(f"Error checking audio quality: {str(e)}")
            return False

    async def get_media_info(self, file_path: Path) -> Dict[str, Any]:
        """Get media file information using FFmpeg."""
        try:
            cmd = [
                "ffprobe",
                "-v", "quiet",
                "-print_format", "json",
                "-show_format",
                "-show_streams",
                str(file_path)
            ]

            process = await asyncio.create_subprocess_exec(
                *cmd,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE
            )
            stdout, stderr = await process.communicate()

            if process.returncode != 0:
                logger.error(f"FFprobe error: {stderr.decode()}")
                return {}

            info = json.loads(stdout.decode())

            # Extract relevant information
            format_info = info.get("format", {})
            streams = info.get("streams", [])

            # Find audio stream
            audio_stream = next((s for s in streams if s.get("codec_type") == "audio"), None)

            return {
                "duration": float(format_info.get("duration", 0)),
                "mime_type": format_info.get("format_name"),
                "bit_rate": format_info.get("bit_rate"),
                "size": format_info.get("size"),
                "audio_codec": audio_stream.get("codec_name") if audio_stream else None,
                "sample_rate": audio_stream.get("sample_rate") if audio_stream else None,
                "channels": audio_stream.get("channels") if audio_stream else None,
            }

        except Exception as e:
            logger.error(f"Error getting media info: {str(e)}")
            return {}

    async def update_media_info(self, media_info: MediaFileInfo, file_path: Path) -> MediaFileInfo:
        """Update media info with file metadata."""
        file_info = await self.get_media_info(file_path)
        
        return MediaFileInfo(
            filename=media_info.filename,
            file_size=media_info.file_size,
            duration=file_info.get("duration"),
            mime_type=file_info.get("mime_type"),
            source_path=media_info.source_path,
            local_path=media_info.local_path,
            file_hash=media_info.file_hash,
            metadata=file_info,
        )

    def get_telemetry_data(self):
        """Get telemetry data for monitoring."""
        return self.telemetry.get_telemetry_data()

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