"""BoBClient — main entry point for the Bank of Bots Python SDK."""

from __future__ import annotations

from typing import Any

import httpx

from .exceptions import AuthenticationError, BoBError, ForbiddenError, NotFoundError
from .types import (
    APIKeyRecord,
    Agent,
    AgentCreditResponse,
    AgentNodeBinding,
    CreditEvent,
    HistoricalPaymentProofImport,
    InboxEvent,
    PaymentIntent,
    PaymentIntentProof,
    PaymentProofOwnershipChallenge,
    ProofCreditOutcome,
    WebhookSubscriber,
)

_DEFAULT_BASE_URL = "http://localhost:8080/api/v1"


class BoBClient:
    """Client for the Bank of Bots API.

    Usage::

        client = BoBClient(api_key="bok_...", agent_id="<uuid>")
        me = client.get_me()

    Operator-scoped calls can omit ``agent_id``::

        op = BoBClient(api_key="bok_...")
        keys = op.list_api_keys()
    """

    def __init__(
        self,
        api_key: str,
        agent_id: str | None = None,
        base_url: str = _DEFAULT_BASE_URL,
        timeout: float = 30.0,
    ):
        self.api_key = api_key
        self.agent_id = agent_id
        self.base_url = base_url.rstrip("/")
        self._client = httpx.Client(
            base_url=self.base_url,
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=timeout,
        )

    # -- Context manager --

    def __enter__(self) -> "BoBClient":
        return self

    def __exit__(self, *args: Any) -> None:
        self.close()

    def close(self) -> None:
        self._client.close()

    # -- Private helpers --

    def _request(self, method: str, path: str, **kwargs: Any) -> Any:
        resp = self._client.request(method, path, **kwargs)
        if resp.status_code == 401:
            raise AuthenticationError()
        if resp.status_code == 403:
            body = resp.json()
            raise ForbiddenError(body.get("error", "access denied"))
        if resp.status_code == 404:
            body = resp.json()
            raise NotFoundError(body.get("error", "not found"))
        if resp.status_code >= 400:
            body = resp.json()
            raise BoBError(body.get("error", "request failed"), status_code=resp.status_code)
        return resp.json()

    def _agent_path(self, suffix: str = "") -> str:
        if not self.agent_id:
            raise ValueError("agent_id is required for agent-scoped endpoints")
        return f"/agents/{self.agent_id}{suffix}"

    # -- Private parse helpers --

    def _parse_intent(self, data: dict[str, Any]) -> PaymentIntent:
        return PaymentIntent(**{k: data[k] for k in PaymentIntent.__dataclass_fields__ if k in data})

    def _parse_intent_proof(self, data: dict[str, Any]) -> PaymentIntentProof:
        return PaymentIntentProof(**{k: data[k] for k in PaymentIntentProof.__dataclass_fields__ if k in data})

    def _parse_node_binding(self, data: dict[str, Any]) -> AgentNodeBinding:
        return AgentNodeBinding(**{k: data[k] for k in AgentNodeBinding.__dataclass_fields__ if k in data})

    def _parse_proof_ownership_challenge(self, data: dict[str, Any]) -> PaymentProofOwnershipChallenge:
        return PaymentProofOwnershipChallenge(
            **{k: data[k] for k in PaymentProofOwnershipChallenge.__dataclass_fields__ if k in data}
        )

    def _parse_proof_credit(self, data: dict[str, Any] | None) -> ProofCreditOutcome | None:
        if not isinstance(data, dict):
            return None
        known_fields = [k for k in ProofCreditOutcome.__dataclass_fields__ if k != "extra"]
        parsed = {k: data[k] for k in known_fields if k in data}
        extra = {k: v for k, v in data.items() if k not in ProofCreditOutcome.__dataclass_fields__}
        if extra:
            parsed["extra"] = extra
        return ProofCreditOutcome(**parsed)

    def _parse_historical_import(self, data: dict[str, Any]) -> HistoricalPaymentProofImport:
        return HistoricalPaymentProofImport(
            **{k: data[k] for k in HistoricalPaymentProofImport.__dataclass_fields__ if k in data}
        )

    # -- Auth --

    def get_me(self) -> Agent:
        """Get the authenticated agent's details."""
        data = self._request("GET", self._agent_path())
        return Agent(**{k: data[k] for k in Agent.__dataclass_fields__ if k in data})

    # -- Agent CRUD --

    def create_agent(self, name: str, **kwargs: Any) -> Agent:
        """Create a new agent."""
        payload: dict[str, Any] = {"name": name, **kwargs}
        data = self._request("POST", "/agents", json=payload)
        return Agent(**{k: data[k] for k in Agent.__dataclass_fields__ if k in data})

    def get_agent(self, agent_id: str) -> Agent:
        """Get an agent by ID."""
        data = self._request("GET", f"/agents/{agent_id}")
        return Agent(**{k: data[k] for k in Agent.__dataclass_fields__ if k in data})

    def list_agents(self, limit: int = 50, offset: int = 0) -> list[Agent]:
        """List agents for the authenticated operator."""
        params: dict[str, int] = {"limit": limit, "offset": offset}
        data = self._request("GET", "/agents", params=params)
        items = data.get("data", data) if isinstance(data, dict) else data
        return [
            Agent(**{k: item[k] for k in Agent.__dataclass_fields__ if k in item})
            for item in items
            if isinstance(item, dict)
        ]

    def approve_agent(
        self,
        agent_id: str,
        seed_amount: int = 0,
        seed_currency: str | None = None,
        seed_wallet_id: str | None = None,
    ) -> dict[str, Any]:
        """Approve an agent and optionally seed starter balance."""
        payload: dict[str, Any] = {}
        if seed_amount > 0:
            payload["seed_amount"] = seed_amount
        if seed_currency:
            payload["seed_currency"] = seed_currency
        if seed_wallet_id:
            payload["seed_wallet_id"] = seed_wallet_id
        return self._request("POST", f"/agents/{agent_id}/approve", json=payload)

    def batch_agents(self, items: list[dict[str, Any]]) -> dict[str, Any]:
        """Create multiple agents in a single request."""
        payload: dict[str, Any] = {"items": items}
        data = self._request("POST", "/agents/batch", json=payload)
        return data if isinstance(data, dict) else {}

    def suggest_agent_name(self) -> str:
        """Get a suggested agent name."""
        data = self._request("GET", "/agents/suggest-name")
        data_map = data if isinstance(data, dict) else {}
        return str(data_map.get("name", ""))

    # -- Payment intents --

    def create_payment_intent(
        self,
        amount: int,
        destination_type: str,
        destination_ref: str,
        currency: str = "BTC",
        auto_execute: bool = True,
        priority: str = "balanced",
        execution_mode: str = "auto",
        pinned_rail: str | None = None,
        pinned_wallet_id: str | None = None,
        max_fee: int = 0,
        latest_settlement_by: str | None = None,
    ) -> dict[str, Any]:
        """Create a payment intent, optionally auto-executing the best route.

        Returns the raw response dict containing ``intent``, ``quotes``, and
        optionally ``payment`` keys.
        """
        payload: dict[str, Any] = {
            "destination_type": destination_type,
            "destination_ref": destination_ref,
            "amount": amount,
            "currency": currency,
            "auto_execute": auto_execute,
            "priority": priority,
            "execution_mode": execution_mode,
        }
        if pinned_rail:
            payload["pinned_rail"] = pinned_rail
        if pinned_wallet_id:
            payload["pinned_wallet_id"] = pinned_wallet_id
        if max_fee > 0:
            payload["max_fee"] = max_fee
        if latest_settlement_by:
            payload["latest_settlement_by"] = latest_settlement_by
        data = self._request("POST", self._agent_path("/payment-intents"), json=payload)
        return data if isinstance(data, dict) else {}

    def quote_payment_intent(
        self,
        amount: int,
        destination_type: str,
        destination_ref: str,
        currency: str = "BTC",
        priority: str = "balanced",
        execution_mode: str = "auto",
        pinned_rail: str | None = None,
        pinned_wallet_id: str | None = None,
        max_fee: int = 0,
        latest_settlement_by: str | None = None,
    ) -> dict[str, Any]:
        """Quote a payment intent without executing it.

        Returns the raw response dict containing ``intent`` and ``quotes`` keys.
        """
        payload: dict[str, Any] = {
            "destination_type": destination_type,
            "destination_ref": destination_ref,
            "amount": amount,
            "currency": currency,
            "auto_execute": False,
            "priority": priority,
            "execution_mode": execution_mode,
        }
        if pinned_rail:
            payload["pinned_rail"] = pinned_rail
        if pinned_wallet_id:
            payload["pinned_wallet_id"] = pinned_wallet_id
        if max_fee > 0:
            payload["max_fee"] = max_fee
        if latest_settlement_by:
            payload["latest_settlement_by"] = latest_settlement_by
        data = self._request("POST", self._agent_path("/payment-intents/quote"), json=payload)
        return data if isinstance(data, dict) else {}

    def execute_payment_intent(
        self,
        intent_id: str,
        quote_id: str | None = None,
        description: str | None = None,
    ) -> dict[str, Any]:
        """Execute a previously quoted payment intent.

        Returns the raw response dict containing ``intent``, ``quote``, and
        ``payment`` keys.
        """
        payload: dict[str, Any] = {}
        if quote_id:
            payload["quote_id"] = quote_id
        if description:
            payload["description"] = description
        data = self._request(
            "POST",
            self._agent_path(f"/payment-intents/{intent_id}/execute"),
            json=payload,
        )
        return data if isinstance(data, dict) else {}

    def list_payment_intents(self, limit: int = 50, offset: int = 0) -> list[PaymentIntent]:
        """List payment intents for this agent."""
        params: dict[str, int] = {"limit": limit, "offset": offset}
        data = self._request("GET", self._agent_path("/payment-intents"), params=params)
        items = data.get("data", data) if isinstance(data, dict) else data
        return [
            self._parse_intent(item)
            for item in items
            if isinstance(item, dict)
        ]

    def get_payment_intent(self, intent_id: str) -> dict[str, Any]:
        """Get a payment intent with its route quotes.

        Returns the raw response dict containing ``intent`` and ``quotes`` keys.
        """
        data = self._request("GET", self._agent_path(f"/payment-intents/{intent_id}"))
        return data if isinstance(data, dict) else {}

    # -- Proof submission --

    def create_proof_ownership_challenge(
        self,
        intent_id: str,
        proof_type: str,
        proof_ref: str,
    ) -> PaymentProofOwnershipChallenge:
        """Create a one-time ownership challenge bound to intent + proof context."""
        payload: dict[str, Any] = {
            "proof_type": (proof_type or "").strip().lower(),
            "proof_ref": (proof_ref or "").strip(),
        }
        data = self._request(
            "POST",
            self._agent_path(f"/payment-intents/{intent_id}/proof-ownership/challenge"),
            json=payload,
        )
        return self._parse_proof_ownership_challenge(data.get("challenge", {}))

    def submit_payment_intent_proof(
        self,
        intent_id: str,
        proof_type: str,
        proof_ref: str,
        ownership_challenge_id: str,
        ownership_signature: str,
        metadata: dict[str, Any] | None = None,
    ) -> tuple[PaymentIntent, PaymentIntentProof]:
        """Submit non-custodial proof for a BTC payment intent.

        Supported proof_type values:
        - btc_onchain_tx: on-chain transaction ID
        - btc_lightning_payment_hash: lightning payment hash
        - btc_lightning_preimage: lightning preimage (pass preimage in
          metadata["preimage"], optionally include BOLT11 invoice in
          metadata["invoice"] for stronger verification)
        """
        payload: dict[str, Any] = {
            "proof_type": (proof_type or "").strip().lower(),
            "proof_ref": (proof_ref or "").strip(),
            "ownership_challenge_id": (ownership_challenge_id or "").strip(),
            "ownership_signature": (ownership_signature or "").strip(),
        }
        if payload["ownership_challenge_id"] == "" or payload["ownership_signature"] == "":
            raise ValueError("ownership_challenge_id and ownership_signature are required")
        if metadata is not None:
            payload["metadata"] = metadata
        data = self._request("POST", self._agent_path(f"/payment-intents/{intent_id}/proofs"), json=payload)
        intent = self._parse_intent(data.get("intent", {}))
        proof = self._parse_intent_proof(data.get("proof", {}))
        proof.credit = self._parse_proof_credit(data.get("credit"))
        return intent, proof

    def list_payment_intent_proofs(self, intent_id: str) -> tuple[PaymentIntent, list[PaymentIntentProof]]:
        """List submitted proofs for a payment intent."""
        data = self._request("GET", self._agent_path(f"/payment-intents/{intent_id}/proofs"))
        intent = self._parse_intent(data.get("intent", {}))
        proofs = [
            self._parse_intent_proof(item)
            for item in data.get("proofs", [])
            if isinstance(item, dict)
        ]
        return intent, proofs

    def reverify_payment_intent_proof(self, intent_id: str, proof_id: str) -> PaymentIntentProof:
        """Re-run verification on an existing payment intent proof."""
        data = self._request(
            "POST",
            self._agent_path(f"/payment-intents/{intent_id}/proofs/{proof_id}/reverify"),
            json={},
        )
        proof = self._parse_intent_proof(data.get("proof", {}))
        proof.credit = self._parse_proof_credit(data.get("credit"))
        return proof

    # -- Historical proof imports --

    def import_payment_proof(
        self,
        proof_type: str,
        proof_ref: str,
        rail: str,
        amount: int,
        currency: str = "BTC",
        direction: str = "outbound",
        occurred_at: str | None = None,
        counterparty_ref: str | None = None,
        metadata: dict[str, Any] | None = None,
    ) -> HistoricalPaymentProofImport:
        """Import a historical BTC payment proof for credit building.

        Supported proof_type values:
        - btc_onchain_tx: on-chain transaction ID
        - btc_lightning_payment_hash: lightning payment hash
        - btc_lightning_preimage: lightning preimage (pass preimage in
          metadata["preimage"], optionally include BOLT11 invoice in
          metadata["invoice"] for stronger verification)
        """
        payload: dict[str, Any] = {
            "proof_type": (proof_type or "").strip().lower(),
            "proof_ref": (proof_ref or "").strip(),
            "rail": (rail or "").strip().lower(),
            "currency": (currency or "BTC").strip().upper(),
            "amount": amount,
            "direction": (direction or "outbound").strip().lower(),
        }
        if occurred_at:
            payload["occurred_at"] = occurred_at
        if counterparty_ref:
            payload["counterparty_ref"] = counterparty_ref
        if metadata is not None:
            payload["metadata"] = metadata
        data = self._request("POST", self._agent_path("/credit/imports/payment-proofs"), json=payload)
        imported = self._parse_historical_import(data.get("import", {}))
        imported.credit = self._parse_proof_credit(data.get("credit"))
        return imported

    def list_payment_proof_imports(
        self,
        limit: int = 50,
        offset: int = 0,
    ) -> list[HistoricalPaymentProofImport]:
        """List historical BTC payment proof imports for this agent."""
        params: dict[str, int] = {"limit": limit, "offset": offset}
        data = self._request("GET", self._agent_path("/credit/imports/payment-proofs"), params=params)
        items = data.get("data", data) if isinstance(data, dict) else data
        return [
            self._parse_historical_import(item)
            for item in items
            if isinstance(item, dict)
        ]

    def reverify_payment_proof_import(self, import_id: str) -> HistoricalPaymentProofImport:
        """Re-run verification on a historical payment proof import."""
        data = self._request(
            "POST",
            self._agent_path(f"/credit/imports/payment-proofs/{import_id}/reverify"),
            json={},
        )
        imported = self._parse_historical_import(data.get("import", {}))
        imported.credit = self._parse_proof_credit(data.get("credit"))
        return imported

    # -- Agent credit --

    def get_agent_credit(self) -> AgentCreditResponse:
        """Fetch the agent's credit score, tier, and effective policy limits."""
        data = self._request("GET", self._agent_path("/credit"))
        data_map = data if isinstance(data, dict) else {}
        return AgentCreditResponse(
            **{k: data_map[k] for k in AgentCreditResponse.__dataclass_fields__ if k in data_map}
        )

    def list_agent_credit_events(self, limit: int = 50, offset: int = 0) -> list[CreditEvent]:
        """Fetch paginated credit event history for the agent."""
        data = self._request(
            "GET",
            self._agent_path("/credit/events"),
            params={"limit": limit, "offset": offset},
        )
        items = data.get("data", []) if isinstance(data, dict) else []
        return [
            CreditEvent(**{k: item[k] for k in CreditEvent.__dataclass_fields__ if k in item})
            for item in items
        ]

    # -- BOB Score --

    def get_score(self, agent_id: str | None = None) -> dict[str, Any]:
        """Get the BOB Score for an agent."""
        target = agent_id or self.agent_id
        if not target:
            raise ValueError("agent_id is required")
        data = self._request("GET", f"/agents/{target}/score")
        return data if isinstance(data, dict) else {}

    def get_score_composition(self, agent_id: str | None = None) -> dict[str, Any]:
        """Get the detailed BOB Score composition breakdown for an agent."""
        target = agent_id or self.agent_id
        if not target:
            raise ValueError("agent_id is required")
        data = self._request("GET", f"/agents/{target}/score/composition")
        return data if isinstance(data, dict) else {}

    def update_signal_visibility(
        self,
        signals: dict[str, bool],
        agent_id: str | None = None,
    ) -> dict[str, Any]:
        """Update which BOB Score signals are publicly visible for an agent."""
        target = agent_id or self.agent_id
        if not target:
            raise ValueError("agent_id is required")
        data = self._request("PATCH", f"/agents/{target}/score/signals", json={"signals": signals})
        return data if isinstance(data, dict) else {}

    def get_leaderboard(
        self,
        limit: int = 50,
        offset: int = 0,
    ) -> dict[str, Any]:
        """Get the global BOB Score leaderboard."""
        params: dict[str, int] = {"limit": limit, "offset": offset}
        data = self._request("GET", "/leaderboard", params=params)
        return data if isinstance(data, dict) else {}

    # -- Wallet binding --

    def create_wallet_binding_challenge(
        self,
        chain: str,
        address: str,
        agent_id: str | None = None,
    ) -> dict[str, Any]:
        """Create a challenge for binding an EVM wallet address to an agent."""
        target = agent_id or self.agent_id
        if not target:
            raise ValueError("agent_id is required")
        payload: dict[str, Any] = {
            "chain": (chain or "").strip().lower(),
            "address": (address or "").strip(),
        }
        data = self._request("POST", f"/agents/{target}/wallet-bindings/challenge", json=payload)
        return data if isinstance(data, dict) else {}

    def verify_wallet_binding(
        self,
        challenge_id: str,
        signature: str,
        agent_id: str | None = None,
    ) -> dict[str, Any]:
        """Verify an EVM wallet binding by submitting a signed challenge."""
        target = agent_id or self.agent_id
        if not target:
            raise ValueError("agent_id is required")
        payload: dict[str, Any] = {
            "challenge_id": (challenge_id or "").strip(),
            "signature": (signature or "").strip(),
        }
        data = self._request("POST", f"/agents/{target}/wallet-bindings/verify", json=payload)
        return data if isinstance(data, dict) else {}

    def create_node_binding_challenge(self, wallet_id: str | None = None) -> PaymentProofOwnershipChallenge:
        """Create a challenge for binding a Lightning node to this agent."""
        payload: dict[str, Any] = {}
        if wallet_id:
            payload["wallet_id"] = wallet_id
        data = self._request(
            "POST",
            self._agent_path("/node-bindings/lightning/challenge"),
            json=payload,
        )
        return self._parse_proof_ownership_challenge(data.get("challenge", {}))

    def verify_node_binding(self, challenge_id: str, signature: str) -> AgentNodeBinding:
        """Verify a Lightning node binding by submitting a signed challenge."""
        payload: dict[str, Any] = {
            "challenge_id": (challenge_id or "").strip(),
            "signature": (signature or "").strip(),
        }
        data = self._request(
            "POST",
            self._agent_path("/node-bindings/lightning/verify"),
            json=payload,
        )
        return self._parse_node_binding(data.get("binding", {}))

    # -- Social --

    def connect_social(
        self,
        platform: str,
        access_token: str,
        agent_id: str | None = None,
    ) -> dict[str, Any]:
        """Connect a social account to an agent for BOB Score signals."""
        target = agent_id or self.agent_id
        if not target:
            raise ValueError("agent_id is required")
        payload: dict[str, Any] = {
            "platform": (platform or "").strip().lower(),
            "access_token": (access_token or "").strip(),
        }
        data = self._request("POST", f"/agents/{target}/social/connect", json=payload)
        return data if isinstance(data, dict) else {}

    # -- Webhooks --

    def create_agent_webhook(self, url: str, events: list[str] | None = None) -> WebhookSubscriber:
        """Create an agent-scoped webhook subscriber."""
        payload: dict[str, Any] = {"url": (url or "").strip()}
        if events is not None:
            payload["events"] = [str(event).strip() for event in events if str(event).strip()]
        data = self._request("POST", self._agent_path("/webhooks"), json=payload)
        data_map = data if isinstance(data, dict) else {}
        return WebhookSubscriber(
            **{k: data_map[k] for k in WebhookSubscriber.__dataclass_fields__ if k in data_map}
        )

    def list_agent_webhooks(self) -> list[WebhookSubscriber]:
        """List webhook subscribers scoped to this agent."""
        data = self._request("GET", self._agent_path("/webhooks"))
        items = data if isinstance(data, list) else []
        return [
            WebhookSubscriber(
                **{k: item[k] for k in WebhookSubscriber.__dataclass_fields__ if k in item}
            )
            for item in items
            if isinstance(item, dict)
        ]

    def get_agent_webhook(self, webhook_id: str) -> WebhookSubscriber:
        """Fetch one agent webhook subscriber by ID."""
        data = self._request("GET", self._agent_path(f"/webhooks/{webhook_id}"))
        data_map = data if isinstance(data, dict) else {}
        return WebhookSubscriber(
            **{k: data_map[k] for k in WebhookSubscriber.__dataclass_fields__ if k in data_map}
        )

    def update_agent_webhook(
        self,
        webhook_id: str,
        *,
        url: str | None = None,
        events: list[str] | None = None,
        active: bool | None = None,
    ) -> WebhookSubscriber:
        """Update an agent-scoped webhook subscriber."""
        payload: dict[str, Any] = {}
        if url is not None:
            payload["url"] = url.strip()
        if events is not None:
            payload["events"] = [str(event).strip() for event in events if str(event).strip()]
        if active is not None:
            payload["active"] = bool(active)
        data = self._request("PATCH", self._agent_path(f"/webhooks/{webhook_id}"), json=payload)
        data_map = data if isinstance(data, dict) else {}
        return WebhookSubscriber(
            **{k: data_map[k] for k in WebhookSubscriber.__dataclass_fields__ if k in data_map}
        )

    def delete_agent_webhook(self, webhook_id: str) -> dict[str, Any]:
        """Delete an agent-scoped webhook subscriber."""
        data = self._request("DELETE", self._agent_path(f"/webhooks/{webhook_id}"))
        return data if isinstance(data, dict) else {}

    # -- Inbox --

    def get_agent_inbox(
        self,
        status: str | None = None,
        limit: int = 50,
        offset: int = 0,
    ) -> list[InboxEvent]:
        """List inbox events for this agent."""
        params: dict[str, str | int] = {"limit": limit, "offset": offset}
        if status:
            params["status"] = status
        data = self._request("GET", self._agent_path("/inbox"), params=params)
        items = data.get("data", data) if isinstance(data, dict) else data
        return [
            InboxEvent(**{k: item[k] for k in InboxEvent.__dataclass_fields__ if k in item})
            for item in items
            if isinstance(item, dict)
        ]

    def ack_inbox_event(self, event_id: str) -> InboxEvent:
        """Acknowledge an inbox event."""
        data = self._request("POST", self._agent_path(f"/inbox/{event_id}/ack"))
        return InboxEvent(**{k: data[k] for k in InboxEvent.__dataclass_fields__ if k in data})

    def list_agent_events(self, limit: int = 30, offset: int = 0) -> list[dict[str, Any]]:
        """List agent system events (paginated)."""
        data = self._request(
            "GET",
            self._agent_path("/events"),
            params={"limit": limit, "offset": offset},
        )
        items = data.get("data", []) if isinstance(data, dict) else []
        return [item for item in items if isinstance(item, dict)]

    # -- API keys --

    def list_api_keys(
        self,
        include_revoked: bool = False,
        limit: int = 50,
    ) -> list[APIKeyRecord]:
        """List API keys for the authenticated operator."""
        if limit <= 0:
            raise ValueError("limit must be > 0")
        params: dict[str, Any] = {"limit": limit}
        if include_revoked:
            params["include_revoked"] = "true"
        data = self._request("GET", "/operators/me/api-keys", params=params)
        items = data if isinstance(data, list) else []
        return [
            APIKeyRecord(**{k: item[k] for k in APIKeyRecord.__dataclass_fields__ if k in item})
            for item in items
            if isinstance(item, dict)
        ]

    def create_api_key(
        self,
        name: str = "",
        scopes: list[str] | None = None,
    ) -> dict[str, Any]:
        """Create a new API key with optional scopes.

        Returns a dict with ``api_key`` (the raw secret, shown once) and
        ``key`` (an ``APIKeyRecord``-shaped dict).
        """
        payload: dict[str, Any] = {}
        if (name or "").strip():
            payload["name"] = name.strip()
        if scopes:
            payload["scopes"] = [str(scope).strip().lower() for scope in scopes if str(scope).strip()]
        data = self._request("POST", "/operators/me/api-keys", json=payload)
        return data if isinstance(data, dict) else {}

    def revoke_api_key(self, key_id: str) -> dict[str, Any]:
        """Revoke an API key by ID."""
        normalized = (key_id or "").strip()
        if not normalized:
            raise ValueError("key_id is required")
        data = self._request("POST", f"/operators/me/api-keys/{normalized}/revoke", json={})
        return data if isinstance(data, dict) else {}
