"""Audio transcription via Gemini generateContent (multimodal).

Port of v1 main.py:8253-8325 (``_transcribe_audio_via_gemini``), keeping the
stdlib ``urllib`` approach — no httpx/requests dependency for this one call —
and the exact v1 prompt. Inline base64 audio (fine up to ~20 MB; capture
audio is bounded at 50 MB by services/media.py — larger files would need the
Files API, same caveat as v1).

Config: ``GEMINI_API_KEY`` from app settings (.env, shape-verified only);
``GEMINI_TRANSCRIBE_MODEL`` from the environment (default gemini-2.5-flash),
matching the v1 env-override contract.

Async per standards (AI route): the blocking urllib call runs in a worker
thread via ``asyncio.to_thread`` so the event loop is never blocked. Callers
must not hold a DB session across the await.
"""
from __future__ import annotations

import asyncio
import base64
import json
import os

from ...config import get_settings
from ...errors import AppError

# --- error codes (AI domain) ---
AI_NOT_CONFIGURED = "ai_not_configured"
AI_UPSTREAM_ERROR = "ai_upstream_error"
AI_BAD_RESPONSE = "ai_bad_response"

DEFAULT_TRANSCRIBE_MODEL = "gemini-2.5-flash"

# v1 mime map, verbatim.
_MIME_MAP = {
    ".webm": "audio/webm",
    ".ogg": "audio/ogg",
    ".oga": "audio/ogg",
    ".m4a": "audio/mp4",
    ".mp4": "audio/mp4",
    ".mp3": "audio/mpeg",
    ".wav": "audio/wav",
}

# v1 prompt, verbatim (no vocabulary-hint support — that is deliberately not
# ported; it was never in v1).
_PROMPT = (
    "Transcribe this audio recording verbatim. It is a casual "
    "voice memo about gardening (varieties, areas, observations). "
    "Return ONLY the transcript text. No preamble, no explanation, "
    "no quotation marks. Preserve the speaker's exact words including "
    "any 'um's or 'uh's removed. Resolve obvious mis-hearings of "
    "garden terms when context makes them clear."
)


def transcribe_model() -> str:
    return os.environ.get("GEMINI_TRANSCRIBE_MODEL", DEFAULT_TRANSCRIBE_MODEL)


def _transcribe_sync(abs_audio_path: str, *, api_key: str, model: str) -> str:
    """Blocking urllib call — v1 logic verbatim, AppError instead of
    HTTPException. Never log or echo the key; it travels only in the URL."""
    import urllib.error
    import urllib.request

    ext = os.path.splitext(abs_audio_path)[1].lower()
    mime = _MIME_MAP.get(ext, "audio/webm")

    with open(abs_audio_path, "rb") as f:
        audio_b64 = base64.b64encode(f.read()).decode("ascii")

    payload = {
        "contents": [{
            "parts": [
                {"text": _PROMPT},
                {"inline_data": {"mime_type": mime, "data": audio_b64}},
            ]
        }],
        "generationConfig": {
            "temperature": 0.0,
            "responseMimeType": "text/plain",
        },
    }
    url = (
        f"https://generativelanguage.googleapis.com/v1beta/models/"
        f"{model}:generateContent?key={api_key}"
    )
    req = urllib.request.Request(
        url,
        data=json.dumps(payload).encode("utf-8"),
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=120) as resp:
            body = resp.read().decode("utf-8")
    except urllib.error.HTTPError as e:
        detail = e.read().decode("utf-8", errors="replace")[:500]
        raise AppError(AI_UPSTREAM_ERROR, f"Gemini API error {e.code}: {detail}", 502)
    except urllib.error.URLError as e:
        raise AppError(AI_UPSTREAM_ERROR, f"Gemini API unreachable: {e.reason}", 502)

    data = json.loads(body)
    try:
        text = data["candidates"][0]["content"]["parts"][0]["text"]
    except (KeyError, IndexError, TypeError):
        raise AppError(
            AI_BAD_RESPONSE, f"Unexpected Gemini response shape: {body[:300]}", 502
        )
    return text.strip()


async def transcribe_audio(abs_audio_path: str) -> str:
    """Transcribe one audio file. Raises AppError on any failure."""
    settings = get_settings()
    if not settings.gemini_api_key:
        raise AppError(AI_NOT_CONFIGURED, "GEMINI_API_KEY is not configured", 503)
    return await asyncio.to_thread(
        _transcribe_sync,
        abs_audio_path,
        api_key=settings.gemini_api_key,
        model=transcribe_model(),
    )
