"""
Audio class for FMUS-VID.

This module provides the Audio class for handling audio operations.
"""

from typing import Union, Optional, Dict, Any, Callable
from pathlib import Path
import logging

logger = logging.getLogger(__name__)

class Audio:
    """
    Class for handling audio operations.

    This class provides methods for manipulating audio.
    """

    def __init__(self, audio_data: Any, backend: Any):
        """
        Initialize an Audio object.

        Args:
            audio_data: Backend-specific audio data
            backend: Backend instance
        """
        self._audio_data = audio_data
        self._backend = backend

    def save(self, path: Union[str, Path], **kwargs) -> None:
        """
        Save audio to file.

        Args:
            path: Output file path
            **kwargs: Save options
                - codec: Audio codec (e.g., "mp3", "aac")
                - bitrate: Audio bitrate (e.g., "192k")

        Example:
            >>> audio.save("output.mp3", codec="mp3", bitrate="192k")
        """
        self._backend.save_audio(self._audio_data, path, **kwargs)

    def trim(self, start: float, end: Optional[float] = None) -> 'Audio':
        """
        Trim audio to specified time range.

        Args:
            start: Start time in seconds
            end: End time in seconds (None means until the end)

        Returns:
            New Audio object

        Example:
            >>> intro = audio.trim(0, 10)  # First 10 seconds
        """
        new_audio_data = self._backend.trim_audio(self._audio_data, start, end)
        return Audio(new_audio_data, self._backend)

    def volume(self, level: float) -> 'Audio':
        """
        Set audio volume.

        Args:
            level: Volume level (1.0 = original, 0.5 = 50%, 2.0 = 200%)

        Returns:
            New Audio object

        Example:
            >>> quieter = audio.volume(0.8)  # Reduce volume to 80%
        """
        new_audio_data = self._backend.volume_audio(self._audio_data, level)
        return Audio(new_audio_data, self._backend)

    def fade_in(self, duration: float) -> 'Audio':
        """
        Add fade-in effect.

        Args:
            duration: Fade duration in seconds

        Returns:
            New Audio object

        Example:
            >>> with_fade = audio.fade_in(2)  # 2-second fade in
        """
        new_audio_data = self._backend.fade_in_audio(self._audio_data, duration)
        return Audio(new_audio_data, self._backend)

    def fade_out(self, duration: float) -> 'Audio':
        """
        Add fade-out effect.

        Args:
            duration: Fade duration in seconds

        Returns:
            New Audio object

        Example:
            >>> with_fade = audio.fade_out(2)  # 2-second fade out
        """
        new_audio_data = self._backend.fade_out_audio(self._audio_data, duration)
        return Audio(new_audio_data, self._backend)

    def normalize(self, target_db: float = -3) -> 'Audio':
        """
        Normalize audio levels.

        Args:
            target_db: Target peak level in dB

        Returns:
            New Audio object

        Example:
            >>> normalized = audio.normalize(-3)  # Normalize to -3 dB
        """
        new_audio_data = self._backend.normalize_audio(self._audio_data, target_db)
        return Audio(new_audio_data, self._backend)

    def mix(self, other: 'Audio', weight: float = 0.5) -> 'Audio':
        """
        Mix with another audio track.

        Args:
            other: Audio to mix with
            weight: Weight of the other audio (0.5 = equal mix)

        Returns:
            New Audio object

        Example:
            >>> mixed = voice.mix(music, weight=0.3)  # Mix voice with background music
        """
        new_audio_data = self._backend.mix_audio(
            self._audio_data,
            other._audio_data,
            weight
        )
        return Audio(new_audio_data, self._backend)

    def info(self) -> Dict[str, Any]:
        """
        Get audio information.

        Returns:
            Dictionary with audio information
                - duration: Duration in seconds
                - channels: Number of channels
                - sample_rate: Sample rate in Hz
                - codec: Audio codec
                - bitrate: Audio bitrate

        Example:
            >>> info = audio.info()
            >>> print(f"Duration: {info['duration']} seconds")
        """
        return self._backend.get_audio_info(self._audio_data)

    def __repr__(self) -> str:
        """String representation of the Audio object."""
        try:
            info = self.info()
            return (f"Audio(duration={info['duration']:.2f}s, "
                   f"channels={info['channels']}, "
                   f"sample_rate={info['sample_rate']}Hz)")
        except Exception:
            return "Audio(unknown info)"
