"""
FFprobe utilities for precise duration detection.

Uses stream duration (not container duration) for accuracy,
accounting for codec delays in formats like AAC.
"""

from __future__ import annotations

import json
import logging
import subprocess
from typing import Optional

logger = logging.getLogger(__name__)


async def get_exact_duration_sync(
    file_path: str,
    stream_type: str = "a"
) -> Optional[float]:
    """
    Get exact stream duration via ffprobe.
    
    Args:
        file_path: Path to media file
        stream_type: 'a' for audio, 'v' for video
    
    Returns: Duration in seconds, or None if stream not found
    
    Uses stream duration (not container), which is more accurate
    for AAC and other formats with codec delay.
    """
    try:
        result = subprocess.run([
            "ffprobe",
            "-v", "error",
            "-select_streams", f"{stream_type}:0",
            "-show_entries", "stream=duration",
            "-of", "json",
            str(file_path)
        ], capture_output=True, text=True, timeout=30, check=False)
        
        if result.returncode != 0:
            logger.warning(f"ffprobe failed for {file_path}: {result.stderr}")
            return None
        
        data = json.loads(result.stdout)
        streams = data.get("streams", [])
        
        if not streams:
            logger.warning(f"No {stream_type} stream found in {file_path}")
            return None
        
        duration = float(streams[0].get("duration"))
        logger.debug(f"ffprobe {file_path}: {stream_type} duration = {duration:.3f}s")
        return duration
    
    except (json.JSONDecodeError, ValueError, subprocess.TimeoutExpired) as e:
        logger.error(f"Error getting duration for {file_path}: {e}")
        return None


def get_exact_duration(
    file_path: str,
    stream_type: str = "a"
) -> Optional[float]:
    """Synchronous wrapper for get_exact_duration_sync."""
    import asyncio
    
    try:
        loop = asyncio.get_event_loop()
        if loop.is_running():
            # We're already in an async context, use synchronous version
            return get_exact_duration_sync_blocking(file_path, stream_type)
        return asyncio.run(get_exact_duration_sync(file_path, stream_type))
    except RuntimeError:
        return get_exact_duration_sync_blocking(file_path, stream_type)


def get_exact_duration_sync_blocking(
    file_path: str,
    stream_type: str = "a"
) -> Optional[float]:
    """Synchronous, blocking ffprobe call."""
    try:
        result = subprocess.run([
            "ffprobe",
            "-v", "error",
            "-select_streams", f"{stream_type}:0",
            "-show_entries", "stream=duration",
            "-of", "json",
            str(file_path)
        ], capture_output=True, text=True, timeout=30, check=False)
        
        if result.returncode != 0:
            logger.warning(f"ffprobe failed: {result.stderr}")
            return None
        
        data = json.loads(result.stdout)
        streams = data.get("streams", [])
        if not streams:
            return None
        
        return float(streams[0].get("duration"))
    except Exception as e:
        logger.error(f"ffprobe error: {e}")
        return None
