import os
import httpx
import asyncio
import base64
import logging
from typing import AsyncGenerator
from app.core.providers.base import TTSProvider
from fastapi import HTTPException

# Configure logging
logger = logging.getLogger(__name__)

import re

class GCloudTTSProvider(TTSProvider):
    # English voices
      # English voices
    # English voices (Studio and Neural2 are the highest quality available in standard Cloud TTS)
    AVAILABLE_VOICES_EN = [
        "en-US-Studio-A", "en-US-Studio-O", "en-US-Neural2-A", 
        "en-US-Neural2-C", "en-US-Neural2-D", "en-US-Neural2-E", 
        "en-US-Neural2-F", "en-US-Neural2-G", "en-US-Neural2-H", 
        "en-US-Neural2-I", "en-US-Neural2-J", "en-US-Wavenet-A", 
        "en-US-Wavenet-B", "en-US-Wavenet-C", "en-US-Wavenet-D", 
        "en-US-Wavenet-E", "en-US-Wavenet-F", "en-US-Wavenet-G", 
        "en-US-Wavenet-H", "en-US-Wavenet-I", "en-US-Wavenet-J"
    ]
    DEFAULT_VOICE_EN = "en-US-Studio-O"

    # Chinese voices
    AVAILABLE_VOICES_CMN = [
        "cmn-CN-Wavenet-A", "cmn-CN-Wavenet-B", "cmn-CN-Wavenet-C", 
        "cmn-CN-Wavenet-D", "cmn-CN-Standard-A", "cmn-CN-Standard-B", 
        "cmn-CN-Standard-C", "cmn-CN-Standard-D"
    ]
    DEFAULT_VOICE_CMN = "cmn-CN-Wavenet-A"

    def __init__(self, api_key: str, model_name: str = "", voice_name: str = DEFAULT_VOICE_EN, **kwargs):
        self.api_key = api_key
        # For typical TTS, it's just text:synthesize. Some new models might use different endpoints, but let's stick to standard.
        self.api_url = f"https://texttospeech.googleapis.com/v1/text:synthesize?key={self.api_key}"
        self.voice_name = voice_name or self.DEFAULT_VOICE_EN
        self.model_name = model_name
        logger.debug(f"Initialized GCloudTTSProvider with voice: {self.voice_name}, model: {self.model_name}")


    def _detect_language(self, text: str) -> str:
        # Simple heuristic: count Chinese characters vs. total chars
        chinese_chars = re.findall(r'[\u4e00-\u9fff]', text)
        if len(chinese_chars) / max(len(text), 1) > 0.5:
            return "cmn-CN"
        return "en-US"

    async def generate_speech(self, text: str) -> bytes:
        voice_to_use = self.voice_name

        # Extract languageCode directly from voice name (e.g., 'en-US-Journey-F' -> 'en-US')
        # Google API requires languageCode to exactly match the voice's language prefix
        parts = voice_to_use.split("-")
        if len(parts) >= 2:
            language = f"{parts[0]}-{parts[1]}"
        else:
            language = self._detect_language(text)

        logger.debug(f"Using language '{language}' for voice: '{voice_to_use}'")

        # This allows testing newer models that might not be in the hardcoded list.
        # Ensure the voice_name provided in the config exactly matches a valid Google TTS model name.
        voice_to_use = self.voice_name

        headers = {
            "Content-Type": "application/json"
        }
        json_data = {
            "input": {"text": text},
            "voice": {
                "languageCode": language,
                "name": voice_to_use
            },
            "audioConfig": {
                "audioEncoding": "LINEAR16",
                "sampleRateHertz": 24000
            }
        }
        
        # Some Google Cloud STT/TTS models require the model parameter in the request body for specific endpoints,
        # but for standard text:synthesize just using the name is usually enough.
        # If model_name is provided, let's include it in the voice config if it acts as a model override,
        # or at the top level (as seen in some v1beta documentation).
        # We'll just attach it to voice config if present.
        if self.model_name and self.model_name not in voice_to_use:
             json_data["voice"]["name"] = self.model_name # Often the voice name IS the model name for newer ones


        logger.debug(f"API Request URL: {self.api_url}")
        logger.debug(f"Request Payload: {json_data}")

        try:
            async with httpx.AsyncClient(timeout=30.0) as client:
                response = await client.post(self.api_url, headers=headers, json=json_data)
                
                if response.status_code != 200:
                    logger.error(f"GCloud TTS API error ({response.status_code}): {response.text}")
                    if response.status_code == 429:
                        raise HTTPException(status_code=429, detail="Rate limit exceeded. Please try again later.")
                    raise HTTPException(status_code=500, detail=f"API request failed ({response.status_code}): {response.text}")

                response_json = response.json()
                logger.debug("Successfully parsed API response JSON.")

                audio_base64 = response_json.get('audioContent')
                if not audio_base64:
                    raise KeyError("audioContent key not found in the response.")

                audio_bytes = base64.b64decode(audio_base64)
                logger.debug(f"Decoded audio data, size: {len(audio_bytes)} bytes.")

                return audio_bytes
                
        except HTTPException:
            raise
        except httpx.RequestError as e:
            logger.error(f"Network error communicating with Google Cloud TTS: {e}")
            raise HTTPException(status_code=500, detail=f"Network error: {e}")
        except Exception as e:
            logger.error(f"An unexpected error occurred during speech generation: {e}")
            raise HTTPException(status_code=500, detail=f"Failed to generate speech: {e}")
