#!/usr/bin/env python3
"""provision_litellm_keys — kb#147 (A2A-15): turn agent-registry.yaml grants
into real LiteLLM virtual keys.

This is the ONE place a capability grant (model allow-list + budget) crosses
from data (agent-registry.yaml, version-controlled) into a live LiteLLM
key (via the proxy's /key/generate or /key/update admin API, master-key
authenticated). It deliberately does nothing destructive: --dry-run (the
default) only computes and prints the payload each agent WOULD get, making
zero network calls. --apply is required to actually create/update a key,
and needs LITELLM_MASTER_KEY in the environment (never hardcoded here, never
committed) — this is a privileged write against a live production service,
so it is not something this task runs unattended; --apply is the kb#147
handover step for a human/approved run.

Usage:
    # Safe, run-anytime: print what each agent's key WOULD look like.
    ./provision_litellm_keys.py --dry-run
    ./provision_litellm_keys.py --dry-run --id torgash

    # Privileged, requires explicit opt-in + master key (kb#147 handover):
    LITELLM_MASTER_KEY=sk-... ./provision_litellm_keys.py --apply --id adolf
"""

import argparse
import json
import os
import sys
import urllib.error
import urllib.request

import agent_registry as ar
import model_registry as mr

LITELLM_BASE_URL = os.environ.get("LITELLM_BASE_URL", "http://localhost:4000")


def agent_ids_with_grants(registry):
    return [a["id"] for a in registry["agents"] if a.get("capability_grant")]


def _http_post(path, payload, master_key):
    req = urllib.request.Request(
        f"{LITELLM_BASE_URL}{path}",
        data=json.dumps(payload).encode(),
        headers={
            "Authorization": f"Bearer {master_key}",
            "Content-Type": "application/json",
        },
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=10) as resp:
        return json.loads(resp.read())


def apply_key(spec, master_key):
    """Create (or update, if key_alias already exists) a LiteLLM virtual key
    matching `spec` (the dict returned by agent_registry.litellm_key_spec).
    Raises on any HTTP error rather than swallowing it — a failed grant
    should never look like a successful one."""
    payload = {
        "key_alias": spec["key_alias"],
        "models": spec["models"],
        "max_budget": spec["max_budget"],
        "budget_duration": spec["budget_duration"],
        "metadata": {"agent_id": spec["agent_id"], "trust_class": spec["trust_class"], "source": "kb#147 agent-registry.yaml"},
    }
    try:
        return _http_post("/key/generate", payload, master_key)
    except urllib.error.HTTPError as e:
        body = e.read().decode(errors="replace")
        raise SystemExit(f"LiteLLM /key/generate failed for {spec['key_alias']}: {e.code} {body}")


def main():
    ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    ap.add_argument("--registry", default=None)
    ap.add_argument("--model-registry", default=None)
    ap.add_argument("--id", default=None, help="only this agent id (default: every agent with a capability_grant)")
    mode = ap.add_mutually_exclusive_group()
    mode.add_argument("--dry-run", action="store_true", default=True, help="default: compute + print only, no network call")
    mode.add_argument("--apply", action="store_true", help="actually call LiteLLM /key/generate (needs LITELLM_MASTER_KEY) -- privileged, kb#147 handover step")
    args = ap.parse_args()

    reg = ar.load_registry(args.registry)
    model_reg = mr.load_registry(args.model_registry)

    ids = [args.id] if args.id else agent_ids_with_grants(reg)
    if not ids:
        print("no agents with a capability_grant in the registry", file=sys.stderr)
        sys.exit(1)

    master_key = os.environ.get("LITELLM_MASTER_KEY")
    if args.apply and not master_key:
        print("error: --apply requires LITELLM_MASTER_KEY in the environment", file=sys.stderr)
        sys.exit(2)

    for agent_id in ids:
        spec = ar.litellm_key_spec(reg, agent_id, model_reg)
        if args.apply:
            result = apply_key(spec, master_key)
            print(json.dumps({"agent_id": agent_id, "key_alias": spec["key_alias"], "applied": True, "litellm_response_keys": list(result.keys())}))
        else:
            print(json.dumps({"mode": "dry-run", **spec}, indent=2))


if __name__ == "__main__":
    main()
