"""Google Gemini Text-to-Speech (TTS) helpers.

Provides a bytes-oriented API similar to the existing iFlytek implementation,
but backed by Google Gemini TTS models via `google-genai`.

Public API:
- `synthesize_speech_google_bytes`: returns WAV or PCM bytes (no disk I/O)

Auth:
- Prefer `GEMINI_API_KEY` from environment or package `.env` (auto-loaded by api_sdk).
- If not set, relies on google-genai default credentials (ADC) when available.

Notes:
- Default model: `gemini-2.5-pro-preview-tts`. You may pass another TTS model if needed.
- When `audio_format='pcm'`, we request WAV and then decode the returned WAV in-memory to raw PCM.
- When `audio_format='mp3'`, we request MP3 bytes.
"""

from __future__ import annotations

from typing import Optional
from pathlib import Path
import logging
import os
import io
import wave

from google import genai
from google.genai import types


logger = logging.getLogger(__name__)


DEFAULT_GOOGLE_TTS_MODEL = "gemini-2.5-pro-preview-tts"


def _get_client() -> genai.Client:
    """Create a google-genai client using the GEMINI_API_KEY env var."""
    env_key = os.environ.get("GEMINI_API_KEY")
    if not env_key:
        raise RuntimeError("GEMINI_API_KEY is required for Google TTS")
    return genai.Client(api_key=env_key)


def synthesize_speech_google_bytes(
    text: str,
    *,
    voice: Optional[str] = None,
    sample_rate: Optional[int] = None,
    model: Optional[str] = None,
    audio_format: str = "wav",
    timeout: float = 60.0,  # reserved for parity; not used here
) -> bytes:
    """Synthesize speech with Google Gemini TTS and return audio bytes.

    Args:
        text: Text to synthesize (UTF-8)
        voice: Optional voice name (provider-specific)
        sample_rate: Optional sample rate hint (Hz). If unsupported by the model,
                     the provider default is used. Returned audio is not resampled.
        model: Gemini TTS model name. Default: gemini-2.5-pro-tts
        audio_format: 'wav' (default) or 'pcm'. When 'pcm', the returned WAV is
                      decoded in-memory to raw PCM bytes.
        timeout: Reserved for API parity; google-genai handles timeouts internally.

    Returns:
        bytes: WAV or PCM bytes.
    """
    if not text or not isinstance(text, str):
        raise ValueError("text must be a non-empty string")

    client = _get_client()

    # Choose output format; for PCM we request WAV and decode later.
    fmt = (audio_format or "wav").lower()

    cfg_kwargs: dict = {}
    # Request AUDIO modality explicitly for TTS models.
    cfg_kwargs["response_modalities"] = ["AUDIO"]

    # Optional speech configuration for voice selection (if provided by caller)
    if voice:
        try:
            cfg_kwargs["speech_config"] = types.SpeechConfig(
                voice_config=types.VoiceConfig(
                    prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name=voice)
                )
            )
        except Exception:
            logger.debug("SpeechConfig not available; proceeding without explicit voice")

    config = types.GenerateContentConfig(**cfg_kwargs)

    use_model = model or DEFAULT_GOOGLE_TTS_MODEL

    response = client.models.generate_content(
        model=use_model,
        contents=text,
        config=config,
    )

    # Extract first audio part from response
    audio_bytes: Optional[bytes] = None
    audio_mime: Optional[str] = None
    try:
        candidates = getattr(response, "candidates", None) or []
        for cand in candidates:
            content = getattr(cand, "content", None)
            parts = getattr(content, "parts", None) or []
            for part in parts:
                inline = getattr(part, "inline_data", None)
                if inline and isinstance(getattr(inline, "data", None), (bytes, bytearray)):
                    mime = getattr(inline, "mime_type", "") or ""
                    if mime.startswith("audio/"):
                        audio_bytes = bytes(inline.data)
                        audio_mime = mime
                        break
            if audio_bytes is not None:
                break
    except Exception as e:
        logger.debug(f"Failed to parse audio from response: {e}")

    if not audio_bytes:
        raise RuntimeError("No audio bytes in Gemini TTS response")

    # If the model returned raw PCM (audio/L16), handle according to desired format.
    if (audio_mime or "").startswith("audio/L16"):
        # Parse sample rate from mime, default to provided or 24000
        rate = 24000
        try:
            for part in (audio_mime or "").split(";"):
                part = part.strip()
                if part.startswith("rate="):
                    rate = int(part.split("=", 1)[1])
                    break
        except Exception:
            pass

        if fmt == "pcm":
            return audio_bytes
        # Wrap as WAV for wav/mp3 requests (mp3 fallback as wav for compatibility)
        buf = io.BytesIO()
        with wave.open(buf, "wb") as wf:
            wf.setnchannels(1)
            wf.setsampwidth(2)
            # Always use the provider's actual sample rate to avoid speed/pitch issues
            wf.setframerate(rate)
            wf.writeframes(audio_bytes)
        return buf.getvalue()

    # Otherwise, return bytes as-is (e.g., if provider returns audio/mpeg)
    return audio_bytes


__all__ = [
    "synthesize_speech_google_bytes",
    "DEFAULT_GOOGLE_TTS_MODEL",
]
