"""智能体侧：解密胶囊并按契约请求平台（前端不持有明文契约）。"""

from __future__ import annotations

import base64
import json
from typing import Any

import httpx
from cryptography.hazmat.primitives.ciphers.aead import AESGCM


PREFIX = "AJZ1"


def decrypt_capsule(agent_key_b64: str, capsule: str) -> dict[str, Any]:
    parts = capsule.split(".")
    if len(parts) != 3 or parts[0] != PREFIX:
        raise ValueError("invalid capsule")
    key = base64.urlsafe_b64decode(pad(agent_key_b64))
    nonce = base64.urlsafe_b64decode(pad(parts[1]))
    data = base64.urlsafe_b64decode(pad(parts[2]))
    # Go RawURLEncoding has no padding; Python needs pad
    aes = AESGCM(key)
    plain = aes.decrypt(nonce, data, None)
    return json.loads(plain)


def pad(s: str) -> str:
    return s + "=" * (-len(s) % 4)


class AgentClient:
    def __init__(self, access_token: str, agent_key: str, capsule: str):
        self.access_token = access_token
        self.desc = decrypt_capsule(agent_key, capsule)
        self.http = httpx.Client(
            base_url=self.desc["base_url"],
            headers={"Authorization": f"Bearer {access_token}"},
            timeout=30.0,
        )

    def resources(self) -> list[dict[str, Any]]:
        return self.desc.get("resources", [])

    def list(self, resource_name: str, **filters: str) -> dict[str, Any]:
        res = self._find(resource_name)
        params = {f"filter.{k}": v for k, v in filters.items()}
        r = self.http.get(res["path"], params=params)
        r.raise_for_status()
        return r.json()

    def create(self, resource_name: str, body: dict[str, Any]) -> dict[str, Any]:
        res = self._find(resource_name)
        r = self.http.post(res["path"], json=body)
        r.raise_for_status()
        return r.json()

    def get(self, resource_name: str, row_id: str) -> dict[str, Any]:
        res = self._find(resource_name)
        r = self.http.get(f"{res['path'].rstrip('/')}/{row_id}")
        r.raise_for_status()
        return r.json()

    def update(self, resource_name: str, row_id: str, body: dict[str, Any]) -> dict[str, Any]:
        res = self._find(resource_name)
        r = self.http.put(f"{res['path'].rstrip('/')}/{row_id}", json=body)
        r.raise_for_status()
        return r.json()

    def delete(self, resource_name: str, row_id: str) -> None:
        res = self._find(resource_name)
        r = self.http.delete(f"{res['path'].rstrip('/')}/{row_id}")
        if r.status_code not in (200, 204):
            r.raise_for_status()

    def _find(self, name: str) -> dict[str, Any]:
        for r in self.resources():
            if r["name"] == name:
                return r
        raise KeyError(f"resource not in capsule: {name}")


if __name__ == "__main__":
    import os
    import sys

    token = os.environ.get("AJZ_TOKEN", "")
    key = os.environ.get("AJZ_AGENT_KEY", "")
    capsule = os.environ.get("AJZ_CAPSULE", "")
    if not (token and key and capsule):
        print("Set AJZ_TOKEN / AJZ_AGENT_KEY / AJZ_CAPSULE", file=sys.stderr)
        sys.exit(1)
    client = AgentClient(token, key, capsule)
    print(json.dumps({"app": client.desc["app_slug"], "resources": [r["name"] for r in client.resources()]}, ensure_ascii=False))
    if client.resources():
        name = client.resources()[0]["name"]
        print(json.dumps(client.list(name), ensure_ascii=False, indent=2))
