"""
TTS 语音合成服务 + OSS 上传
"""
import io
import json
import uuid
import logging
from datetime import datetime
from django.conf import settings

logger = logging.getLogger(__name__)

# TTS 提供商可在此切换，当前预留 edge-tts（免费）
TTS_VOICE = 'zh-CN-XiaoxiaoNeural'


def generate_tts_stream(story):
    """
    为故事生成 TTS 音频并上传 OSS，通过 SSE 推送进度。

    Args:
        story: Story model instance

    Yields:
        str: SSE 格式的事件数据行
    """
    yield _sse_event('stage', {
        'stage': 'connecting',
        'progress': 0,
        'message': '正在准备语音合成...',
    })

    try:
        import edge_tts
    except ImportError:
        yield _sse_event('error', {'message': 'edge-tts 库未安装，请运行 pip install edge-tts'})
        return

    # 如果已有音频，直接返回
    if story.audio_url:
        yield _sse_event('done', {
            'stage': 'done',
            'progress': 100,
            'message': '音频已存在',
            'audio_url': story.audio_url,
        })
        return

    yield _sse_event('stage', {
        'stage': 'generating',
        'progress': 10,
        'message': '正在合成语音...',
    })

    try:
        # edge-tts 是异步的，需要在同步上下文中运行
        import asyncio
        audio_data = asyncio.run(_synthesize(story.content))
    except Exception as e:
        logger.error(f'TTS synthesis failed: {e}')
        yield _sse_event('error', {'message': f'语音合成失败: {str(e)}'})
        return

    yield _sse_event('stage', {
        'stage': 'saving',
        'progress': 70,
        'message': '正在保存音频文件...',
    })

    # 上传到 OSS
    try:
        from utils.oss import get_oss_client
        oss_client = get_oss_client()

        filename = f"{datetime.now().strftime('%Y%m%d')}/{uuid.uuid4().hex}.mp3"
        key = f"stories/audio/{filename}"

        oss_client.bucket.put_object(key, audio_data)

        oss_config = settings.ALIYUN_OSS
        if oss_config.get('CUSTOM_DOMAIN'):
            audio_url = f"https://{oss_config['CUSTOM_DOMAIN']}/{key}"
        else:
            audio_url = f"https://{oss_config['BUCKET_NAME']}.{oss_config['ENDPOINT']}/{key}"

        # 更新故事记录
        story.audio_url = audio_url

    except Exception as e:
        logger.error(f'OSS upload failed: {e}')
        yield _sse_event('error', {'message': f'音频上传失败: {str(e)}'})
        return

    # Opus 预转码：MP3 → Opus 帧 JSON，上传 OSS
    yield _sse_event('stage', {
        'stage': 'opus_converting',
        'progress': 80,
        'message': '正在预转码 Opus 音频...',
    })

    try:
        from apps.stories.services.opus_converter import convert_mp3_to_opus_json

        opus_json = convert_mp3_to_opus_json(audio_data)

        opus_filename = f"{datetime.now().strftime('%Y%m%d')}/{uuid.uuid4().hex}.json"
        opus_key = f"stories/audio-opus/{opus_filename}"

        oss_client.bucket.put_object(opus_key, opus_json.encode('utf-8'))

        if oss_config.get('CUSTOM_DOMAIN'):
            opus_url = f"https://{oss_config['CUSTOM_DOMAIN']}/{opus_key}"
        else:
            opus_url = f"https://{oss_config['BUCKET_NAME']}.{oss_config['ENDPOINT']}/{opus_key}"

        story.opus_url = opus_url
        logger.info(f'Opus 预转码上传成功: {opus_url}')

    except Exception as e:
        logger.warning(f'Opus 预转码失败（不影响 MP3 播放）: {e}')
        # 预转码失败不阻断流程，MP3 仍可正常使用

    story.save(update_fields=['audio_url', 'opus_url'])

    yield _sse_event('done', {
        'stage': 'done',
        'progress': 100,
        'message': '语音合成完成！',
        'audio_url': audio_url,
    })


async def _synthesize(text):
    """使用 edge-tts 合成语音，返回音频 bytes"""
    import edge_tts

    communicate = edge_tts.Communicate(text, TTS_VOICE)
    audio_chunks = []
    async for chunk in communicate.stream():
        if chunk['type'] == 'audio':
            audio_chunks.append(chunk['data'])
    return b''.join(audio_chunks)


def _sse_event(event, data):
    """格式化 SSE 事件"""
    return f"event: {event}\ndata: {json.dumps(data, ensure_ascii=False)}\n\n"
