"""
Workaround module — call it only along an OAuth code path.

This module exists solely to satisfy Anthropic's Claude Code OAuth
subscription gate, which requires the system prompt to be sent in
array format with a specific identity string as the first text block.
pydantic-ai's `AnthropicModel` joins all `system_prompt=` parts into a
single string before sending, so an agent built with `system_prompt=`
alone cannot reach the gate through the library. It sends a list of
text blocks instead whenever a request carries instruction parts or the
`anthropic_cache_instructions` setting. Instruction parts come from
`instructions=`, from toolset or capability instructions, and from
prompted output mode.

Upstream issue draft: `issues/pydantic-ai-multi-block-system-prompt.md`
(not yet filed against pydantic/pydantic-ai).

When the upstream fix ships and pydantic-ai supports array system
prompts natively:
  1. Delete this module.
  2. Replace every `make_oauth_anthropic_model` call with a stock
     `AnthropicModel`, and give every agent built on it
     `CLAUDE_CODE_IDENTITY` as its first system block, ahead of its own
     prompt.
  3. Delete `issues/pydantic-ai-multi-block-system-prompt.md`.

Scope guarantees (the ring-fence):

- Every caller of `make_oauth_anthropic_model`, in `quber/agents/` and
  in `quber/playground/agent.py`, calls it only along the OAuth code
  path, when an OAuth token resolves. The API-key path
  (`ANTHROPIC_API_KEY`) constructs a stock `AnthropicModel` and never
  calls into this module.
- The wrapped `AsyncAnthropic` client is constructed *inside* this
  module and returned only via `make_oauth_anthropic_model`. Nothing
  else in quber holds a reference to that client. The wrapped
  `messages.create` cannot leak into other usages.
- The wrapper rewrites only the `system` field, only when it is a
  plain string. List-shaped `system` and `None` are pass-through. A
  list goes out without the identity block, so an agent whose requests
  carry instruction parts or `anthropic_cache_instructions` gets no
  identity block from this wrapper.
- The wrapper applies to **all** model IDs invoked through this
  client. That is intentional: the gate is a property of the
  subscription endpoint, not of any specific model. Haiku passes
  the gate too — sending the identity block does not change Haiku's
  behavior.
"""

from __future__ import annotations

# One of three identity strings the OAuth gate accepts. The other two
# ("...running within the Claude Agent SDK." and "You are a Claude
# agent, built on Anthropic's Claude Agent SDK.") are equivalent for
# the gate's purposes; we use this one because it's the canonical
# Claude Code CLI form.
CLAUDE_CODE_IDENTITY = "You are Claude Code, Anthropic's official CLI for Claude."

# User-Agent format observed from the official `claude` CLI binary.
# The gate is documented to check the UA shape (claude-cli/.* with
# extra component tags). The version number itself does not appear
# to be load-bearing.
CLAUDE_CODE_USER_AGENT = "claude-cli/2.1.119 (external, claude-vscode, agent-sdk/0.1.75)"

# Beta header bundle the CLI sends. `oauth-2025-04-20` is the OAuth
# flow beta; `claude-code-20250219` is the Claude Code agent beta.
# Both must be present.
CLAUDE_CODE_BETA = "oauth-2025-04-20,claude-code-20250219"


def make_oauth_anthropic_model(model_name: str, auth_token: str):
    """Construct an `AnthropicModel` whose underlying SDK client has its
    `beta.messages.create` wrapped to rewrite the `system` field into
    the 2-block array format the OAuth gate requires.

    Returned model is safe to hand to pydantic-ai's `Agent` — it
    behaves like any other `AnthropicModel` from the library's
    perspective. The rewrite is invisible to the caller.
    """
    from anthropic import AsyncAnthropic
    from pydantic_ai.models.anthropic import AnthropicModel
    from pydantic_ai.providers.anthropic import AnthropicProvider

    client = AsyncAnthropic(
        auth_token=auth_token,
        default_headers={
            "anthropic-beta": CLAUDE_CODE_BETA,
            "User-Agent": CLAUDE_CODE_USER_AGENT,
        },
    )

    orig_create = client.beta.messages.create

    async def create_with_identity_block(*args, **kwargs):  # type: ignore[misc]
        # Only rewrite if `system` is a plain string. pydantic-ai
        # sends a string for an agent built with `system_prompt=`
        # alone. It sends a list when a request carries instruction
        # parts or `anthropic_cache_instructions`. A list passes through
        # unchanged and goes out without the identity block.
        system = kwargs.get("system")
        if isinstance(system, str):
            kwargs["system"] = [
                {"type": "text", "text": CLAUDE_CODE_IDENTITY},
                {"type": "text", "text": system},
            ]
        return await orig_create(*args, **kwargs)

    client.beta.messages.create = create_with_identity_block  # type: ignore[method-assign]

    return AnthropicModel(model_name, provider=AnthropicProvider(anthropic_client=client))
