"""Deepgram, in about forty lines of stdlib.

The foreman is standing in the wind holding a phone. Typing WEATHER and ISSUES into a form at ten
past four is exactly the chore this whole app exists to delete, so those boxes get a mic instead.

One call, one transcript, one row in Diary-Notes.csv. No streaming, no websocket, no SDK, no new
dependency in requirements.txt - urllib posts the bytes the browser recorded and reads the JSON
back. If the key is missing the page says so in words and the typed box still works; if the call
fails the foreman is told to try again and nothing is written.

Never log the key. transcribe() takes it as an argument so it never has to reach for os.environ in
a code path that also builds an error message.
"""
from __future__ import annotations

import json
import os
import urllib.error
import urllib.request

API = "https://api.deepgram.com/v1/listen?model=nova-2&smart_format=true&punctuate=true"
TIMEOUT = 30

# The words a bloke in the rain gets to see. Never a traceback, never an exception class name -
# those go to the log, where they are useful, not onto a screen where they are noise.
CANT_HEAR = "couldn't hear that — try again"
NO_KEY = "voice unavailable — no transcription key set"


def key() -> str:
    return (os.getenv("DEEPGRAM_API_KEY") or "").strip()


def available() -> bool:
    return bool(key())


class VoiceError(Exception):
    """Carries the words for the screen; the caller logs the detail separately."""

    def __init__(self, say: str, detail: str = ""):
        super().__init__(detail or say)
        self.say = say
        self.detail = detail


def transcribe(audio: bytes, content_type: str, api_key: str = "") -> str:
    """Bytes in, words out. Raises VoiceError with something sayable on any failure."""
    api_key = (api_key or key()).strip()
    if not api_key:
        raise VoiceError(NO_KEY, "DEEPGRAM_API_KEY not set")
    if not audio:
        raise VoiceError(CANT_HEAR, "empty recording")

    req = urllib.request.Request(API, data=audio, method="POST", headers={
        "Authorization": "Token " + api_key,
        "Content-Type": content_type or "audio/webm",
    })
    try:
        with urllib.request.urlopen(req, timeout=TIMEOUT) as resp:
            body = json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        # Read the body: Deepgram says WHY in it, and "401" on its own has cost people days.
        detail = ""
        try:
            detail = e.read().decode("utf-8", "replace")[:300]
        except Exception:
            pass
        if e.code in (401, 403):
            raise VoiceError("voice unavailable — the transcription key was refused",
                             "HTTP %s %s" % (e.code, detail))
        raise VoiceError(CANT_HEAR, "HTTP %s %s" % (e.code, detail))
    except Exception as e:
        raise VoiceError(CANT_HEAR, "%s: %s" % (type(e).__name__, e))

    try:
        alt = body["results"]["channels"][0]["alternatives"][0]
    except (KeyError, IndexError, TypeError):
        raise VoiceError(CANT_HEAR, "unexpected response shape: " + json.dumps(body)[:300])
    said = (alt.get("transcript") or "").strip()
    if not said:
        raise VoiceError(CANT_HEAR, "transcript came back empty")
    return said
