import httpx
import json
import asyncio
import os
from http import HTTPStatus
from typing import Optional, Dict, Any, List
from src.services.provider.base import BaseAudioService, ServiceResponse, TaskStatus, GenerationResult
from src.services.storage_service import storage_manager
import logging
import uuid
import dashscope
from dashscope.audio.tts_v2 import SpeechSynthesizer, AudioFormat

logger = logging.getLogger(__name__)


class DashScopeAudioService(BaseAudioService):
    def __init__(self, model_name: str = "cosyvoice-v3-plus", api_key: Optional[str] = None, **kwargs):
        """
        Audio Generation Service for DashScope.
        Supports: CosyVoice (cosyvoice-v3-plus/flash), Qwen-TTS (qwen3-tts-flash)
        """
        super().__init__(model_name, api_key=api_key, **kwargs)
        if not self.api_key:
            logger.warning("API Key is not set. Audio generation will fail.")

    async def generate(self, 
                       text: str, 
                       voice: str = "Cherry",
                       format: str = "mp3",
                       **kwargs) -> ServiceResponse:
        """ 生成 audio from text (TTS).
        Voice is passed through directly to the provider API.
        """
        try:
            logger.info(f"Starting TTS ({self.model_name}) voice={voice}, text: {text[:50]}...")
            
            if "qwen" in self.model_name.lower():
                return await self._generate_qwen(text, voice, **kwargs)
            else:
                return await self._generate_cosyvoice(text, voice, format, **kwargs)

        except Exception as e:
            logger.error(f"Audio Gen Call Failed: {str(e)}")
            raise RuntimeError(f"Audio Gen Service Error: {str(e)}")

    async def _generate_cosyvoice(self, text: str, voice: str, format: str, **kwargs) -> ServiceResponse:
        """ 生成 audio using CosyVoice v3 via DashScope SDK (WebSocket)."""
        
        # 映射 string format to AudioFormat enum
        FORMAT_MAP = {
            "mp3": AudioFormat.MP3_22050HZ_MONO_256KBPS,
            "wav": AudioFormat.WAV_22050HZ_MONO_16BIT,
            "pcm": AudioFormat.PCM_22050HZ_MONO_16BIT,
        }
        audio_format = FORMAT_MAP.get(format, AudioFormat.MP3_22050HZ_MONO_256KBPS)
        
        def _synthesize():
            # 集合 API key for SDK
            dashscope.api_key = self.api_key
            
            synthesizer = SpeechSynthesizer(
                model=self.model_name,
                voice=voice or "longanyang",
                format=audio_format,
            )
            audio_data = synthesizer.call(text)
            request_id = synthesizer.get_last_request_id() or str(uuid.uuid4())
            return audio_data, request_id
        
        logger.info(f"CosyVoice TTS request: model={self.model_name}, voice={voice}, format={format}, text_len={len(text)}")
        
        audio_data, request_id = await asyncio.to_thread(_synthesize)
        
        if not audio_data or len(audio_data) == 0:
            raise RuntimeError(f"CosyVoice TTS returned empty audio data, request_id={request_id}")
        
        logger.info(f"CosyVoice TTS completed: request_id={request_id}, audio_size={len(audio_data)} bytes")
        
        # Determine file extension from format
        ext = format if format in ("mp3", "wav", "pcm") else "mp3"
        
        return await asyncio.to_thread(
            self._save_audio, audio_data, ext, request_id
        )

    async def _generate_qwen(self, text: str, voice: str, **kwargs) -> ServiceResponse:
        """ 生成 audio using Qwen3-TTS-Flash via HTTP API.
        
        API: POST /api/v1/services/aigc/multimodal-generation/generation
        Response: JSON with output.audio.url
        """
        url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }
        
        input_data = {
            "text": text,
            "voice": voice or "Cherry",
        }
        
        language_type = kwargs.get("language_type", "Auto")
        if language_type:
            input_data["language_type"] = language_type
        
        payload = {
            "model": self.model_name,
            "input": input_data
        }
        
        logger.info(f"Qwen TTS request: model={self.model_name}, voice={voice}, text_len={len(text)}")

        async with httpx.AsyncClient(timeout=(30, 120)) as client:
            response = await client.post(url, headers=headers, json=payload)
        
        if response.status_code != HTTPStatus.OK:
            error_msg = f"Qwen TTS Request Failed: {response.status_code} - {response.text}"
            logger.error(error_msg)
            raise RuntimeError(error_msg)
        
        try:
            result = response.json()
            logger.debug(f"Qwen TTS raw response: {json.dumps(result, ensure_ascii=False)[:500]}")
            
            output = result.get("output", {})
            audio_url = None
            
            # 格式化 1: output.audio.url (primary for qwen3-tts-flash)
            audio_obj = output.get("audio")
            if isinstance(audio_obj, dict):
                audio_url = audio_obj.get("url")
            elif isinstance(audio_obj, str):
                audio_url = audio_obj
            
            # 格式化 2: output.choices[].message.content[].audio (fallback for qwen-tts)
            if not audio_url:
                choices = output.get("choices", [])
                if choices:
                    content_list = choices[0].get("message", {}).get("content", [])
                    for item in content_list:
                        if "audio" in item:
                            audio_item = item["audio"]
                            if isinstance(audio_item, dict):
                                audio_url = audio_item.get("url")
                            elif isinstance(audio_item, str):
                                audio_url = audio_item
                            if audio_url:
                                break
            
            if not audio_url:
                raise RuntimeError(f"No audio URL in Qwen TTS response: {json.dumps(result, ensure_ascii=False)[:500]}")
            
            logger.info(f"Qwen TTS audio URL obtained: {audio_url[:80]}...")
            
            async with httpx.AsyncClient(timeout=(30, 120)) as client:
                audio_response = await client.get(audio_url)
                audio_response.raise_for_status()
                audio_data = audio_response.content
            ext = "wav" if ".wav" in audio_url.lower() else "mp3"
            
            return await asyncio.to_thread(
                self._save_audio, audio_data, ext, 
                result.get("request_id", str(uuid.uuid4()))
            )

        except RuntimeError:
            raise
        except Exception as e:
            raise RuntimeError(f"Failed to parse Qwen TTS response: {e}")

    def _save_audio(self, audio_data: bytes, format: str, task_id: str) -> ServiceResponse:
        file_name = f"{uuid.uuid4()}.{format}"
        storage_path = f"generations/audio/{task_id}/{file_name}"
        
        try:
            saved_url = storage_manager.save(storage_path, audio_data)
            return ServiceResponse(
                status=TaskStatus.SUCCEEDED,
                task_id=task_id,
                results=[GenerationResult(url=saved_url)]
            )
        except Exception as e:
            logger.error(f"Failed to save audio to storage: {e}")
            raise RuntimeError(f"Storage Error: {e}")

