"""The transcription provider contract.

Deliberately one method wide. The prototype needs exactly one capability -
turn recorded audio into text - and `react.md` requires a thin provider
adapter so swapping the model or the vendor is a one-file change.

Adding a provider means writing one module here and registering it in
`registry.py`. Nothing else in the app knows which vendor is in use.
"""

from __future__ import annotations

from typing import Protocol


class TranscriptionError(Exception):
    """Structured failure the router can turn into an error_code response."""

    def __init__(self, error_code: str, summary: str, details: str | None = None):
        super().__init__(summary)
        self.error_code = error_code
        self.summary = summary
        self.details = details


# Error codes, shared across providers so the frontend can act on them
# without knowing which vendor produced them.
AI_NOT_CONFIGURED = "AI_NOT_CONFIGURED"
AI_UPSTREAM_ERROR = "AI_UPSTREAM_ERROR"
AI_BAD_RESPONSE = "AI_BAD_RESPONSE"
AI_AUDIO_UNSUPPORTED = "AI_AUDIO_UNSUPPORTED"


class TranscriptionProvider(Protocol):
    """One capability: audio bytes in, transcript out."""

    name: str

    def is_configured(self) -> bool:
        """False when the provider has no credentials - the router turns this
        into a clear 503 rather than a confusing upstream failure."""
        ...

    async def transcribe(self, audio: bytes, mime: str) -> str:
        """Transcribe one recording. Raises TranscriptionError on failure."""
        ...
