from io import BytesIO

from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import StreamingResponse

from app.errors import RoutingError
from app.auth import require_user
from app.store import User, SessionOwnershipError
from app.dependencies import (
    resolve_route,
    build_orchestrator,
    resolve_output_endpoint,
    get_store,
    piper_voice_for_language,
)
from app.quota import enforce_quota, record_usage, QuotaExceededError
from app.schemas import SpeakRequest

router = APIRouter()


@router.post("/speak")
async def speak(
    payload: SpeakRequest,
    session_id: str | None = Query(
        default=None,
        description="Optional session id to apply a stored route",
    ),
    user: User = Depends(require_user),
):
    overrides = {
        "output_endpoint": payload.output_endpoint,
        "language": payload.language,
        "tts_provider": payload.tts_provider,
    }
    try:
        route = resolve_route(user, session_id, overrides)
        # Explizit angefragte Stimme gewinnt; sonst folgt sie der Sprache (Piper-Parität zu /chat).
        voice = payload.voice or piper_voice_for_language(route.tts_provider, route.language)
        orchestrator = build_orchestrator(route)
        output = await resolve_output_endpoint(route)
    except SessionOwnershipError as exc:
        raise HTTPException(status_code=403, detail=str(exc))
    except RoutingError as exc:
        raise HTTPException(status_code=422, detail=str(exc))

    store = get_store()
    try:
        enforce_quota(user, store)
    except QuotaExceededError as exc:
        raise HTTPException(status_code=429, detail=str(exc))

    try:
        audio = await orchestrator.speak_only(
            payload.text,
            voice=voice,
            language=route.language,
            output=output,
        )
        record_usage(user, store, len(payload.text))

        headers = {
            "Content-Language": route.language,
            "X-Audio-Format": "pcm",
            "X-Audio-Sample-Rate": "24000",
            "X-Audio-Channels": "1",
            "X-Audio-Sample-Width": "16",
            "X-Output-Endpoint": route.output_endpoint,
            "X-TTS-Provider": route.tts_provider,
        }
        return StreamingResponse(BytesIO(audio), media_type="audio/pcm", headers=headers)

    except Exception as exc:
        raise HTTPException(status_code=502, detail=str(exc))
