"""Piper TTS implementation — lightweight local neural TTS."""

from __future__ import annotations

import logging
from pathlib import Path

import numpy as np

from roohai.base import TTSModel

logger = logging.getLogger(__name__)

# Directory to store downloaded Piper voice models
PIPER_MODELS_DIR = Path(__file__).resolve().parent.parent.parent / "models" / "piper"


class PiperTTS(TTSModel):
    META = {
        "display_name": "Piper",
        "description": "Fast, lightweight local TTS. Downloads voice models automatically on first use.",
        "kind": "local",
        "pip_dependencies": ["piper-tts>=1.4"],
        "hf_models": [],
        "estimated_download_mb": 60,
        "config_fields": [
            {
                "name": "voice",
                "label": "Voice",
                "type": "select",
                "required": False,
                "default": "en_US-lessac-medium",
                "options": [
                    {"value": "en_US-lessac-medium", "label": "Lessac (US, Medium)"},
                    {"value": "en_US-amy-medium", "label": "Amy (US, Medium)"},
                    {"value": "en_US-ryan-medium", "label": "Ryan (US, Medium)"},
                    {"value": "en_US-libritts_r-medium", "label": "LibriTTS-R (US, Medium)"},
                    {"value": "en_GB-alan-medium", "label": "Alan (GB, Medium)"},
                    {"value": "en_GB-cori-medium", "label": "Cori (GB, Medium)"},
                ],
            },
        ],
    }

    def __init__(
        self,
        voice: str = "en_US-lessac-medium",
        **kwargs,
    ) -> None:
        self.voice_name = voice
        self._voice = None  # PiperVoice instance
        self._sample_rate = 22050

    def load(self) -> None:
        from piper import PiperVoice
        from piper.download_voices import download_voice

        PIPER_MODELS_DIR.mkdir(parents=True, exist_ok=True)

        # Download voice if not present
        model_path = PIPER_MODELS_DIR / f"{self.voice_name}.onnx"
        if not model_path.exists():
            logger.info("Downloading Piper voice '%s'...", self.voice_name)
            download_voice(self.voice_name, PIPER_MODELS_DIR)
            logger.info("Piper voice downloaded to %s", PIPER_MODELS_DIR)

        self._voice = PiperVoice.load(
            str(model_path),
            download_dir=str(PIPER_MODELS_DIR),
        )
        self._sample_rate = self._voice.config.sample_rate
        logger.info(
            "Piper TTS loaded: voice=%s, sample_rate=%d",
            self.voice_name,
            self._sample_rate,
        )

    def synthesize(self, text: str) -> tuple[np.ndarray, int]:
        if not self.is_loaded:
            raise RuntimeError("Model not loaded. Call load() first.")

        # Synthesize and collect all audio chunks
        audio_chunks = []
        for chunk in self._voice.synthesize(text):
            audio_chunks.append(chunk.audio_int16_array)

        if not audio_chunks:
            # Return silence if no audio produced
            return np.zeros(self._sample_rate, dtype=np.float32), self._sample_rate

        # Concatenate int16 arrays and convert to float32
        raw = np.concatenate(audio_chunks)
        audio = raw.astype(np.float32) / 32768.0
        return audio, self._sample_rate

    def unload(self) -> None:
        self._voice = None

    @property
    def is_loaded(self) -> bool:
        return self._voice is not None
