"""
ElevenLabs TTS Provider – generates speech audio from text.
"""

from __future__ import annotations

import asyncio
import logging
import os
from pathlib import Path

from providers.ports import TTSProvider
from models import VoiceSettings

logger = logging.getLogger(__name__)


class ElevenLabsTTSProvider(TTSProvider):
    """Wraps the ElevenLabs Python SDK for text-to-speech generation."""

    name = "elevenlabs"

    def __init__(self, voice_settings: VoiceSettings | None = None):
        api_key = os.getenv("ELEVENLABS_API_KEY")
        if not api_key:
            raise EnvironmentError(
                "ELEVENLABS_API_KEY is required for Generate mode. "
                "Set it in your .env file."
            )
        from elevenlabs.client import ElevenLabs
        from elevenlabs import VoiceSettings as ELVoiceSettings

        self._el_voice_settings_cls = ELVoiceSettings
        self.client = ElevenLabs(api_key=api_key)
        self.settings = voice_settings or VoiceSettings()

    def _generate_sync(self, text: str, output_path: str | Path) -> Path:
        """Generate speech audio and save to *output_path*. Returns the path."""
        output_path = Path(output_path)
        output_path.parent.mkdir(parents=True, exist_ok=True)

        logger.info("Generating TTS for %d chars → %s", len(text), output_path)

        audio = self.client.text_to_speech.convert(
            text=text,
            voice_id=self.settings.voice_id,
            model_id=self.settings.model_id,
            voice_settings=self._el_voice_settings_cls(
                stability=self.settings.stability,
                similarity_boost=self.settings.similarity_boost,
                style=self.settings.style,
                speed=self.settings.speed,
            ),
        )

        with open(output_path, "wb") as f:
            for chunk in audio:
                if isinstance(chunk, bytes):
                    f.write(chunk)

        logger.info("TTS audio saved: %s", output_path)
        return output_path

    async def generate(self, text: str, output_path: Path) -> Path:
        """Generate speech audio asynchronously."""
        return await asyncio.to_thread(self._generate_sync, text, output_path)

    @staticmethod
    def get_audio_duration(audio_path: str | Path) -> float:
        """Return the duration of an audio file in seconds using pydub."""
        from pydub import AudioSegment

        seg = AudioSegment.from_file(str(audio_path))
        return seg.duration_seconds
