"""语音播报工具。"""

from __future__ import annotations

import json
from dataclasses import dataclass
from typing import Any
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen

from django.conf import settings


@dataclass(frozen=True)
class SpeakResponse:
    status_code: int
    raw: Any


def play_speech(
    *,
    text: str,
    endpoint: str | None = None,
    timeout_seconds: float = 10.0,
) -> SpeakResponse:
    """调用语音播报服务。

    默认 endpoint 读取 settings.SPEAK_ENDPOINT。
    请求格式：POST JSON {'text': '<text>'}
    """
    content = (text or '').strip()
    if not content:
        raise ValueError('text 不能为空')
    if not getattr(settings, 'SPEECH_ENABLED', True):
        return SpeakResponse(status_code=0, raw={'status': 'disabled'})

    url = (endpoint or getattr(settings, 'SPEAK_ENDPOINT', '') or '').strip()
    if not url:
        raise ValueError('SPEAK_ENDPOINT 未配置')

    payload = {'text': content}
    data = json.dumps(payload, ensure_ascii=False).encode('utf-8')
    headers = {'Content-Type': 'application/json'}
    api_key = (getattr(settings, 'SPEAK_API_KEY', '') or '').strip()
    if api_key:
        headers['X-Api-Key'] = api_key
    req = Request(
        url=url,
        data=data,
        headers=headers,
        method='POST',
    )

    try:
        with urlopen(req, timeout=float(timeout_seconds)) as resp:
            body = resp.read().decode('utf-8', errors='replace')
            status_code = int(getattr(resp, 'status', 200) or 200)
    except HTTPError as exc:
        body = ''
        try:
            body = exc.read().decode('utf-8', errors='replace')
        except Exception:
            pass
        raise RuntimeError(f'Speak service HTTPError: status={exc.code}, body={body}') from exc
    except URLError as exc:
        raise RuntimeError(f'Speak service URLError: {exc}') from exc

    try:
        raw = json.loads(body) if body else {}
    except Exception:
        raw = {'raw_text': body}

    return SpeakResponse(status_code=status_code, raw=raw)
