#!/usr/bin/env python3
"""JBNX Studio Model m/002 — ElevenLabs voice pipeline health check.

Key handling (standing rule): the ElevenLabs API key is NEVER hardcoded,
printed, or logged. At runtime it is injected as the environment variable
ELEVENLABS_KEY by the hosting platform:

  * Supabase Edge Function Secrets — ELEVENLABS_KEY is set in BOTH the
    jbnx project (ref ngjmqdzpnhwpybtssykz) and the fedm8 project
    (names verified 2026-10-28 via the Management API; values are
    write-only there and were not read).
  * Railway — ELEVENLABS_KEY variable on the service (owner-set
    2026-10-28), which injects it into this app's environment.

Run this inside a runtime where the secret is injected (Railway service,
Supabase Edge Function, or a local shell that exported it). A runtime
without the secret reports {"ok": false, "status": "key_missing"} —
that is an environment fact, not a verdict on the key.

Output is status only: HTTP status from the ElevenLabs user/voices
endpoints, whether the key was accepted, voice count, and whether a
voice matching the m/002 clone names exists. No key, header, or voice
ID is ever printed.

Usage:  python3 voice-healthcheck.py [--json]
Exit:   0 = key accepted · 1 = API error/rejection · 2 = key missing
"""

import json
import os
import sys
import urllib.error
import urllib.request
from urllib.parse import urlsplit

API_BASE = "https://api.elevenlabs.io/v1"
API_HOST = "api.elevenlabs.io"
CLONE_NAME_HINTS = ("joey", "jbnx-m-002", "m/002")


def _get(path, api_key):
    url = API_BASE + path
    parts = urlsplit(url)
    if parts.scheme != "https" or parts.hostname != API_HOST:
        return None, {}
    request = urllib.request.Request(
        url,
        headers={"xi-api-key": api_key, "Accept": "application/json"},
        method="GET",
    )
    try:
        # Scheme and host are pinned by the check above (API_BASE + the two
        # constant call-site paths), which is the control the rule asks for —
        # same pattern as safe_http.py in this repo.
        with urllib.request.urlopen(request, timeout=20) as response:  # nosemgrep: python.lang.security.audit.dynamic-urllib-use-detected.dynamic-urllib-use-detected
            return response.status, json.loads(response.read().decode("utf-8"))
    except urllib.error.HTTPError as error:
        return error.code, {}
    except Exception:
        return None, {}


def check(api_key):
    """Return a status-only report dict. Never includes the key."""
    if not api_key:
        return {"ok": False, "status": "key_missing",
                "detail": "ELEVENLABS_KEY is not present in this runtime's environment. "
                          "Run inside the Railway service or a Supabase Edge Function, "
                          "where the secret is injected."}
    user_status, _user = _get("/user", api_key)
    if user_status != 200:
        return {"ok": False, "status": "key_not_accepted", "http_status": user_status,
                "detail": "ElevenLabs /user did not return 200 for the injected key."}
    voices_status, voices_payload = _get("/voices", api_key)
    voices = voices_payload.get("voices", []) if voices_status == 200 else []
    clone_found = any(
        any(hint in (voice.get("name") or "").lower() for hint in CLONE_NAME_HINTS)
        for voice in voices
    )
    return {
        "ok": True,
        "status": "key_accepted",
        "http_status": user_status,
        "voices_endpoint_http_status": voices_status,
        "voice_count": len(voices),
        "m002_clone_enrolled": clone_found,
        "detail": "Key accepted by ElevenLabs. Clone enrollment is reported as a "
                  "boolean only; enroll the m/002 custom clone before narration work.",
    }


def main(argv):
    report = check(os.environ.get("ELEVENLABS_KEY", ""))
    if "--json" in argv:
        print(json.dumps(report, indent=2))
    else:
        for key, value in report.items():
            print(f"{key}: {value}")
    if report["status"] == "key_missing":
        return 2
    return 0 if report["ok"] else 1


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1:]))
