from __future__ import annotations

import inspect
import warnings
from dataclasses import dataclass
from typing import Any, Awaitable, Callable
from urllib.parse import quote

from .models import (
    APIResponse,
    ActorKeyChallengeRequest,
    ActorKeyRegisterRequest,
    ActorKeyRevokeRequest,
    AbuseClearRequest,
    AbuseRuleRequest,
    AgentEnrollApproveRequest,
    AgentEnrollChallengeRequest,
    AgentEnrollFinalizeRequest,
    AgentEnrollRejectRequest,
    AgentEnrollStartRequest,
    AuthMode,
    ClientOptions,
    CreateActorRequest,
    CreateInviteRequest,
    CreateOrgRequest,
    CreateProjectRequest,
    CredentialIssueRequest,
    CreateEnvelopeRequest,
    EnvelopeListQuery,
    HistoryListQuery,
    HistoryRecordRequest,
    HistoryShareTokenCreateRequest,
    InviteAcceptRequest,
    ListTemplatesQuery,
    MagicLinkStartRequest,
    MagicLinkVerifyRequest,
    MembershipRoleRequest,
    OIDCExchangeRequest,
    RequestOptions,
    SigningAcceptRequest,
    SigningRejectRequest,
    SetCounterpartyRequest,
    SetCounterpartiesRequest,
    ScopePolicyUpsertRequest,
    SecurityPolicyUpsertRequest,
    SignupCompleteRequest,
    SignupStartRequest,
    SignupVerifyRequest,
    SwitchOrgRequest,
    TemplateEnableRequest,
    TemplateShareRequest,
)
from .runtime import AsyncRuntime, RuntimeOptions, SyncRuntime

ResponseLike = APIResponse | Awaitable[APIResponse]
RequestCallable = Callable[..., ResponseLike]


def _model_dict(payload: Any) -> Any:
    if payload is None:
        return None
    if hasattr(payload, "model_dump"):
        return payload.model_dump(exclude_none=True, by_alias=True)
    return payload


def _path_escape(value: str) -> str:
    return quote(value, safe="")


@dataclass
class _BaseResource:
    request: RequestCallable

    def _call(
        self,
        *,
        method: str,
        path: str,
        auth: AuthMode,
        idempotent: bool,
        challenge: bool,
        options: RequestOptions | None = None,
        body: Any = None,
        params: dict[str, Any] | None = None,
        retryable: bool = True,
    ) -> ResponseLike:
        return self.request(
            method=method,
            path=path,
            auth=auth,
            idempotent=idempotent,
            challenge=challenge,
            options=options,
            body=_model_dict(body),
            params=params,
            retryable=retryable,
        )


class PublicSignupAPI(_BaseResource):
    def start(self, body: SignupStartRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/signup/start", auth="none", idempotent=True, challenge=True, body=body, options=options)

    def verify(self, body: SignupVerifyRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/signup/verify", auth="none", idempotent=True, challenge=True, body=body, options=options)

    def get(self, session_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/public/v1/signup/{_path_escape(session_id)}", auth="none", idempotent=False, challenge=False, options=options)

    def complete(self, body: SignupCompleteRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/signup/complete", auth="none", idempotent=True, challenge=True, body=body, options=options)


class PublicAuthAPI(_BaseResource):
    def magic_link_start(self, body: MagicLinkStartRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/auth/magic-link/start", auth="none", idempotent=True, challenge=True, body=body, options=options)

    def magic_link_verify(self, body: MagicLinkVerifyRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/auth/magic-link/verify", auth="none", idempotent=True, challenge=False, body=body, options=options)

    def oidc_exchange(self, body: OIDCExchangeRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/auth/oidc/exchange", auth="none", idempotent=True, challenge=False, body=body, options=options)

    def switch_org(self, body: SwitchOrgRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/auth/session:switch-org", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def session(self, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path="/public/v1/auth/session", auth="session", idempotent=False, challenge=False, options=options)

    def logout(self, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/auth/logout", auth="session", idempotent=True, challenge=False, options=options)

    def sessions(self, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path="/public/v1/auth/sessions", auth="session", idempotent=False, challenge=False, options=options)

    def revoke_session(self, session_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/public/v1/auth/sessions/{_path_escape(session_id)}:revoke", auth="session", idempotent=True, challenge=False, options=options)


class PublicAgentEnrollmentAPI(_BaseResource):
    def challenge(self, body: AgentEnrollChallengeRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/agent-enroll/challenge", auth="none", idempotent=True, challenge=True, body=body, options=options)

    def start(self, body: AgentEnrollStartRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/agent-enroll/start", auth="none", idempotent=True, challenge=True, body=body, options=options)

    def get(self, enrollment_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/public/v1/agent-enroll/{_path_escape(enrollment_id)}", auth="none", idempotent=False, challenge=False, options=options)

    def approve(self, enrollment_id: str, body: AgentEnrollApproveRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/public/v1/agent-enroll/{_path_escape(enrollment_id)}/approve", auth="none", idempotent=True, challenge=False, body=body, options=options)

    def reject(self, enrollment_id: str, body: AgentEnrollRejectRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/public/v1/agent-enroll/{_path_escape(enrollment_id)}/reject", auth="none", idempotent=True, challenge=False, body=body, options=options)

    def finalize(self, enrollment_id: str, body: AgentEnrollFinalizeRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/public/v1/agent-enroll/{_path_escape(enrollment_id)}/finalize", auth="none", idempotent=True, challenge=True, body=body, options=options)


class PublicInvitesAPI(_BaseResource):
    def accept(self, body: InviteAcceptRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/public/v1/invites/accept", auth="none", idempotent=True, challenge=False, body=body, options=options)


class PublicSharedHistoryAPI(_BaseResource):
    def get(self, token: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/public/v1/shared-history/{_path_escape(token)}", auth="none", idempotent=False, challenge=False, options=options)


class PublicSigningAPI(_BaseResource):
    def resolve(self, token: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/public/v1/signing/{_path_escape(token)}", auth="none", idempotent=False, challenge=False, options=options)

    def accept(self, token: str, body: SigningAcceptRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/public/v1/signing/{_path_escape(token)}/accept", auth="none", idempotent=True, challenge=True, body=body, options=options)

    def reject(self, token: str, body: SigningRejectRequest | None = None, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/public/v1/signing/{_path_escape(token)}/reject", auth="none", idempotent=True, challenge=True, body=body or SigningRejectRequest(), options=options)


class OperatorAdminAPI(_BaseResource):
    def create_org(self, body: CreateOrgRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/operator/v1/orgs", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def create_project(self, org_id: str, body: CreateProjectRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/orgs/{_path_escape(org_id)}/projects", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def create_actor(self, project_id: str, body: CreateActorRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/projects/{_path_escape(project_id)}/actors", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def list_actors(self, project_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/operator/v1/projects/{_path_escape(project_id)}/actors", auth="session", idempotent=False, challenge=False, options=options)

    def list_actors_compat(self, project_id: str | None = None, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path="/operator/v1/actors", auth="session", idempotent=False, challenge=False, params={"project_id": project_id} if project_id else None, options=options)

    def disable_actor(self, actor_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/actors/{_path_escape(actor_id)}:disable", auth="session", idempotent=True, challenge=False, options=options)

    def upsert_scope_policy(self, principal_id: str, body: ScopePolicyUpsertRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="PUT", path=f"/operator/v1/principals/{_path_escape(principal_id)}/scope-policy", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def get_scope_policy(self, principal_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/operator/v1/principals/{_path_escape(principal_id)}/scope-policy", auth="session", idempotent=False, challenge=False, options=options)

    def issue_credential(self, body: CredentialIssueRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/operator/v1/credentials:issue", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def rotate_credential(self, credential_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/credentials/{_path_escape(credential_id)}:rotate", auth="session", idempotent=True, challenge=False, options=options)

    def revoke_credential(self, credential_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/credentials/{_path_escape(credential_id)}:revoke", auth="session", idempotent=True, challenge=False, options=options)

    def list_credentials(self, actor_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path="/operator/v1/credentials", auth="session", idempotent=False, challenge=False, params={"actor_id": actor_id}, options=options)

    def create_invite(self, org_id: str, body: CreateInviteRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/orgs/{_path_escape(org_id)}/invites", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def list_invites(self, org_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/operator/v1/orgs/{_path_escape(org_id)}/invites", auth="session", idempotent=False, challenge=False, options=options)

    def cancel_invite(self, invite_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/invites/{_path_escape(invite_id)}:cancel", auth="session", idempotent=True, challenge=False, options=options)

    def change_membership_role(self, org_id: str, user_id: str, body: MembershipRoleRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/memberships/{_path_escape(org_id)}/{_path_escape(user_id)}:role", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def suspend_membership(self, org_id: str, user_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/memberships/{_path_escape(org_id)}/{_path_escape(user_id)}:suspend", auth="session", idempotent=True, challenge=False, options=options)

    def reactivate_membership(self, org_id: str, user_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/memberships/{_path_escape(org_id)}/{_path_escape(user_id)}:reactivate", auth="session", idempotent=True, challenge=False, options=options)


class OperatorHistoryAPI(_BaseResource):
    def list(self, query: HistoryListQuery | None = None, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path="/operator/v1/history", auth="session", idempotent=False, challenge=False, params=_model_dict(query) if query else None, options=options)

    def get(self, envelope_id: str, options: RequestOptions | None = None) -> ResponseLike:
        out = self._call(method="GET", path=f"/operator/v1/history/{_path_escape(envelope_id)}", auth="session", idempotent=False, challenge=False, options=options)
        if inspect.isawaitable(out):
            async def _normalize() -> APIResponse:
                res = await out
                if "history" not in res.data:
                    res.data["history"] = {"envelope_id": envelope_id, "status": "PENDING", "events": []}
                return res
            return _normalize()
        if "history" not in out.data:
            out.data["history"] = {"envelope_id": envelope_id, "status": "PENDING", "events": []}
        return out

    def create_share_token(self, envelope_id: str, body: HistoryShareTokenCreateRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/history/{_path_escape(envelope_id)}/share-tokens", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def list_share_tokens(self, envelope_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/operator/v1/history/{_path_escape(envelope_id)}/share-tokens", auth="session", idempotent=False, challenge=False, options=options)

    def revoke_share_token(self, token_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/history/share-tokens/{_path_escape(token_id)}:revoke", auth="session", idempotent=True, challenge=False, options=options)

    def record_internal(self, body: HistoryRecordRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/operator/v1/history:record", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def iter_all(self, query: HistoryListQuery | None = None, options: RequestOptions | None = None):
        page_token = (query.page_token if query else None) if hasattr(query, "page_token") else None
        while True:
            query_payload = _model_dict(query) if query else {}
            if page_token:
                query_payload["page_token"] = page_token
            result = self.list(query_payload, options)
            if inspect.isawaitable(result):
                raise TypeError("iter_all is sync-only. Use aiter_all on AsyncOperatorClient.")
            for item in result.data.get("history", []):
                yield item
            page_token = result.data.get("next_page_token")
            if not page_token:
                break

    async def aiter_all(self, query: HistoryListQuery | None = None, options: RequestOptions | None = None):
        query_payload = _model_dict(query) if query else {}
        page_token = query_payload.get("page_token")
        while True:
            if page_token:
                query_payload["page_token"] = page_token
            result = self.list(query_payload, options)
            if inspect.isawaitable(result):
                result = await result
            for item in result.data.get("history", []):
                yield item
            page_token = result.data.get("next_page_token")
            if not page_token:
                break


class OperatorEnvelopesAPI(_BaseResource):
    def list(self, query: EnvelopeListQuery | None = None, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path="/operator/v1/envelopes", auth="session", idempotent=False, challenge=False, params=_model_dict(query) if query else None, options=options)

    def get(self, contract_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/operator/v1/envelopes/{_path_escape(contract_id)}", auth="session", idempotent=False, challenge=False, options=options)

    def get_by_envelope_id(self, envelope_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/operator/v1/envelopes/by-envelope/{_path_escape(envelope_id)}", auth="session", idempotent=False, challenge=False, options=options)


class OperatorSecurityAPI(_BaseResource):
    def get_policy(self, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path="/operator/v1/security/policy", auth="session", idempotent=False, challenge=False, options=options)

    def upsert_policy(self, org_id: str, body: SecurityPolicyUpsertRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="PUT", path=f"/operator/v1/orgs/{_path_escape(org_id)}/security/policy", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def list_abuse_events(self, limit: int | None = None, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path="/operator/v1/security/abuse/events", auth="session", idempotent=False, challenge=False, params={"limit": limit} if limit is not None else None, options=options)

    def allow_abuse(self, body: AbuseRuleRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/operator/v1/security/abuse/allow", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def block_abuse(self, body: AbuseRuleRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/operator/v1/security/abuse/block", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def clear_abuse(self, subject: str, body: AbuseClearRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/security/abuse/{_path_escape(subject)}:clear", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def list_prune_runs(self, limit: int | None = None, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path="/operator/v1/history/prune/runs", auth="session", idempotent=False, challenge=False, params={"limit": limit} if limit is not None else None, options=options)

    def dry_run_prune(self, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/operator/v1/history/prune:dry-run", auth="session", idempotent=True, challenge=False, options=options)


class OperatorTemplatesAPI(_BaseResource):
    def create_for_project(self, project_id: str, body: dict[str, Any], options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/projects/{_path_escape(project_id)}/templates", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def update(self, template_id: str, body: dict[str, Any], options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="PUT", path=f"/operator/v1/templates/{_path_escape(template_id)}", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def publish(self, template_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/templates/{_path_escape(template_id)}:publish", auth="session", idempotent=True, challenge=False, options=options)

    def archive(self, template_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/templates/{_path_escape(template_id)}:archive", auth="session", idempotent=True, challenge=False, options=options)

    def clone(self, template_id: str, body: dict[str, Any], options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/templates/{_path_escape(template_id)}:clone", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def list(self, query: ListTemplatesQuery | None = None, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path="/operator/v1/templates", auth="session", idempotent=False, challenge=False, params=_model_dict(query) if query else None, options=options)

    def get(self, template_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/operator/v1/templates/{_path_escape(template_id)}", auth="session", idempotent=False, challenge=False, options=options)

    def list_shares(self, template_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/operator/v1/templates/{_path_escape(template_id)}/shares", auth="session", idempotent=False, challenge=False, options=options)

    def add_share(self, template_id: str, body: TemplateShareRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/templates/{_path_escape(template_id)}/shares", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def remove_share(self, template_id: str, principal_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="DELETE", path=f"/operator/v1/templates/{_path_escape(template_id)}/shares/{_path_escape(principal_id)}", auth="session", idempotent=True, challenge=False, options=options)

    def enable_for_project(self, project_id: str, template_id: str, body: TemplateEnableRequest | None = None, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/projects/{_path_escape(project_id)}/templates/{_path_escape(template_id)}:enable", auth="session", idempotent=True, challenge=False, body=body or TemplateEnableRequest(), options=options)


class GatewayCELAPI(_BaseResource):
    def create_contract(self, body: dict[str, Any], options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path="/gateway/v1/cel/contracts", auth="operator", idempotent=False, challenge=False, body=body, retryable=False, options=options)

    def create_envelope(self, body: CreateEnvelopeRequest | dict[str, Any], options: RequestOptions | None = None) -> ResponseLike:
        payload = _model_dict(body) if hasattr(body, "model_dump") else dict(body)
        safe: dict[str, Any] = {"template_id": payload.get("template_id")}
        if isinstance(payload.get("variables"), dict):
            safe["variables"] = payload["variables"]
        if isinstance(payload.get("counterparty"), dict):
            safe["counterparty"] = payload["counterparty"]
        return self.create_contract(safe, options)

    def contract_action(self, contract_id: str, action: str, body: dict[str, Any], options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/gateway/v1/cel/contracts/{_path_escape(contract_id)}/actions/{_path_escape(action)}", auth="operator", idempotent=False, challenge=False, body=body, retryable=False, options=options)

    def advanced_action(self, contract_id: str, action: str, body: dict[str, Any], options: RequestOptions | None = None) -> ResponseLike:
        return self.contract_action(contract_id, action, body, options)

    def set_counterparty(self, contract_id: str, body: SetCounterpartyRequest | dict[str, Any], options: RequestOptions | None = None) -> ResponseLike:
        payload = _model_dict(body) if hasattr(body, "model_dump") else dict(body)
        safe: dict[str, Any] = {}
        if isinstance(payload.get("email"), str):
            safe["email"] = payload["email"]
        if isinstance(payload.get("name"), str):
            safe["name"] = payload["name"]
        return self.contract_action(contract_id, "counterparties", {"counterparty": safe}, options)

    def set_counterparties(self, contract_id: str, body: SetCounterpartiesRequest | dict[str, Any], options: RequestOptions | None = None) -> ResponseLike:
        warnings.warn("set_counterparties is deprecated; use set_counterparty", DeprecationWarning, stacklevel=2)
        payload = _model_dict(body) if hasattr(body, "model_dump") else dict(body)
        first = None
        if isinstance(payload.get("counterparties"), list) and payload["counterparties"]:
            first = payload["counterparties"][0]
        elif isinstance(payload.get("participants"), list) and payload["participants"]:
            first = payload["participants"][0]
        elif isinstance(payload.get("policy"), dict):
            stages = payload["policy"].get("stages")
            if isinstance(stages, list) and stages and isinstance(stages[0], dict):
                stage_participants = stages[0].get("participants")
                if isinstance(stage_participants, list) and stage_participants:
                    first = stage_participants[0]
        return self.contract_action(contract_id, "counterparties", {"counterparty": first} if isinstance(first, dict) else {}, options)

    def decide_approval(self, approval_request_id: str, body: dict[str, Any], options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/gateway/v1/cel/approvals/{_path_escape(approval_request_id)}:decide", auth="operator", idempotent=False, challenge=False, body=body, retryable=False, options=options)

    def proof_bundle(self, contract_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/gateway/v1/cel/contracts/{_path_escape(contract_id)}/proof-bundle", auth="operator", idempotent=False, challenge=False, retryable=False, options=options)


@dataclass
class PublicClient:
    signup: PublicSignupAPI
    auth: PublicAuthAPI
    agent_enrollment: PublicAgentEnrollmentAPI
    invites: PublicInvitesAPI
    shared_history: PublicSharedHistoryAPI
    signing: PublicSigningAPI


@dataclass
class OperatorGroupClient:
    admin: OperatorAdminAPI
    actor_keys: "OperatorActorKeysAPI"
    history: OperatorHistoryAPI
    envelopes: OperatorEnvelopesAPI
    security: OperatorSecurityAPI
    templates: OperatorTemplatesAPI


@dataclass
class GatewayClient:
    cel: GatewayCELAPI


class OperatorActorKeysAPI(_BaseResource):
    def challenge(self, actor_id: str, body: ActorKeyChallengeRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/actors/{_path_escape(actor_id)}/keys/challenge", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def register(self, actor_id: str, body: ActorKeyRegisterRequest, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/actors/{_path_escape(actor_id)}/keys", auth="session", idempotent=True, challenge=False, body=body, options=options)

    def list(self, actor_id: str, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="GET", path=f"/operator/v1/actors/{_path_escape(actor_id)}/keys", auth="session", idempotent=False, challenge=False, options=options)

    def revoke(self, actor_id: str, fingerprint: str, body: ActorKeyRevokeRequest | None = None, options: RequestOptions | None = None) -> ResponseLike:
        return self._call(method="POST", path=f"/operator/v1/actors/{_path_escape(actor_id)}/keys/{_path_escape(fingerprint)}:revoke", auth="session", idempotent=True, challenge=False, body=body or ActorKeyRevokeRequest(), options=options)


class OperatorClient:
    def __init__(self, options: ClientOptions) -> None:
        runtime = SyncRuntime(
            RuntimeOptions(
                base_url=options.base_url,
                timeout=options.timeout,
                retry=options.retry,
                session_token=options.session_token,
                operator_token=options.operator_token,
                challenge_headers=options.challenge_headers,
                idempotency_key_generator=options.idempotency_key_generator,
                default_headers=options.default_headers,
            ),
            client=options.httpx_client,
        )
        self._runtime = runtime
        self.public = PublicClient(
            signup=PublicSignupAPI(runtime.request),
            auth=PublicAuthAPI(runtime.request),
            agent_enrollment=PublicAgentEnrollmentAPI(runtime.request),
            invites=PublicInvitesAPI(runtime.request),
            shared_history=PublicSharedHistoryAPI(runtime.request),
            signing=PublicSigningAPI(runtime.request),
        )
        self.operator = OperatorGroupClient(
            admin=OperatorAdminAPI(runtime.request),
            actor_keys=OperatorActorKeysAPI(runtime.request),
            history=OperatorHistoryAPI(runtime.request),
            envelopes=OperatorEnvelopesAPI(runtime.request),
            security=OperatorSecurityAPI(runtime.request),
            templates=OperatorTemplatesAPI(runtime.request),
        )
        self.gateway = GatewayClient(cel=GatewayCELAPI(runtime.request))

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


class AsyncOperatorClient:
    def __init__(self, options: ClientOptions) -> None:
        runtime = AsyncRuntime(
            RuntimeOptions(
                base_url=options.base_url,
                timeout=options.timeout,
                retry=options.retry,
                session_token=options.session_token,
                operator_token=options.operator_token,
                challenge_headers=options.challenge_headers,
                idempotency_key_generator=options.idempotency_key_generator,
                default_headers=options.default_headers,
            ),
            client=options.httpx_async_client,
        )
        self._runtime = runtime
        self.public = PublicClient(
            signup=PublicSignupAPI(runtime.request),
            auth=PublicAuthAPI(runtime.request),
            agent_enrollment=PublicAgentEnrollmentAPI(runtime.request),
            invites=PublicInvitesAPI(runtime.request),
            shared_history=PublicSharedHistoryAPI(runtime.request),
            signing=PublicSigningAPI(runtime.request),
        )
        self.operator = OperatorGroupClient(
            admin=OperatorAdminAPI(runtime.request),
            actor_keys=OperatorActorKeysAPI(runtime.request),
            history=OperatorHistoryAPI(runtime.request),
            envelopes=OperatorEnvelopesAPI(runtime.request),
            security=OperatorSecurityAPI(runtime.request),
            templates=OperatorTemplatesAPI(runtime.request),
        )
        self.gateway = GatewayClient(cel=GatewayCELAPI(runtime.request))

    async def aclose(self) -> None:
        await self._runtime.aclose()
