"""TTS vía ElevenLabs (μ-law 8 kHz nativo para RTP telefónico)."""

from __future__ import annotations

import logging

import httpx

from voice.protocols import AudioFormat, TextToSpeech
from voice.tts.sanitize import sanitize_for_tts

logger = logging.getLogger(__name__)

_API_BASE = "https://api.elevenlabs.io/v1"


class ElevenLabsTextToSpeech(TextToSpeech):
    provider_name = "elevenlabs"

    def __init__(
        self,
        *,
        api_key: str,
        voice_id: str,
        model_id: str = "eleven_multilingual_v2",
        timeout: float = 60.0,
    ) -> None:
        key = (api_key or "").strip()
        vid = (voice_id or "").strip()
        if not key:
            raise ValueError("ELEVENLABS_API_KEY está vacío")
        if not vid:
            raise ValueError("ELEVENLABS_VOICE_ID está vacío")
        self.api_key = key
        self.voice_id = vid
        self.model_id = (model_id or "eleven_multilingual_v2").strip()
        self._timeout = timeout
        self._client: httpx.AsyncClient | None = None

    def _get_client(self) -> httpx.AsyncClient:
        if self._client is None:
            self._client = httpx.AsyncClient(
                base_url=_API_BASE,
                headers={
                    "xi-api-key": self.api_key,
                    "Accept": "application/octet-stream",
                    "Content-Type": "application/json",
                },
                timeout=self._timeout,
            )
        return self._client

    @staticmethod
    def _output_format(fmt: AudioFormat) -> str:
        if fmt.encoding == "mulaw":
            return "ulaw_8000"
        return "pcm_8000"

    async def synthesize(
        self,
        text: str,
        *,
        audio_format: AudioFormat | None = None,
        voice: str | None = None,
        language_code: str | None = None,
    ) -> bytes:
        del language_code  # ElevenLabs usa el modelo multilingüe + voice_id
        fmt = audio_format or AudioFormat(encoding="mulaw")
        voice_id = (voice or self.voice_id).strip()
        clean = sanitize_for_tts(text)
        if not clean:
            return b""

        output_format = self._output_format(fmt)
        client = self._get_client()
        try:
            response = await client.post(
                f"/text-to-speech/{voice_id}",
                params={"output_format": output_format},
                json={
                    "text": clean,
                    "model_id": self.model_id,
                },
            )
            response.raise_for_status()
            return response.content or b""
        except httpx.HTTPStatusError as exc:
            body = (exc.response.text or "")[:300]
            logger.exception(
                "ElevenLabs TTS HTTP %s: %s",
                exc.response.status_code,
                body,
            )
            raise
        except Exception:
            logger.exception("ElevenLabs TTS falló")
            raise

    async def close(self) -> None:
        if self._client is not None:
            await self._client.aclose()
            self._client = None
