"""Runtime instructions history processor.

This module provides a history processor that injects runtime context
instructions (elapsed time, token usage, system reminders) into the
message history before each model request.

The runtime instructions are inserted into the last ModelRequest's parts
as a UserPromptPart before ordinary user prompt content, providing the model
with up-to-date context about the current session state while keeping tool
response and retry prompt parts before injected instructions.

Note:
    This processor should be used with AgentContext that has model_cfg set
    for handoff threshold warnings to be displayed.

Example::

    from contextlib import AsyncExitStack
    from pydantic_ai import Agent

    from ya_agent_sdk.context import AgentContext, ModelConfig
    from ya_agent_sdk.environment.local import LocalEnvironment
    from ya_agent_sdk.filters.runtime_instructions import inject_runtime_instructions

    async with AsyncExitStack() as stack:
        env = await stack.enter_async_context(LocalEnvironment())
        ctx = await stack.enter_async_context(
            AgentContext(
                env=env,
                model_cfg=ModelConfig(
                    context_window=200000,
                    proactive_context_management_threshold=0.5,
                ),
            )
        )
        agent = Agent(
            'openai-chat:gpt-4',
            deps_type=AgentContext,
            history_processors=[inject_runtime_instructions],
            metadata=lambda _: {'context_manage_tool': 'handoff'},
        )
        result = await agent.run('Your prompt here', deps=ctx)
"""

from pydantic_ai.messages import ModelMessage, ModelRequest, RetryPromptPart, ToolReturnPart, UserPromptPart
from pydantic_ai.tools import RunContext

from ya_agent_sdk.context import AgentContext


async def inject_runtime_instructions(
    ctx: RunContext[AgentContext],
    message_history: list[ModelMessage],
) -> list[ModelMessage]:
    """Inject runtime instructions into the last ModelRequest.

    This is a pydantic-ai history_processor that inserts runtime context
    instructions (elapsed time, token usage, handoff warnings) into the last
    ModelRequest in the message history before ordinary user prompt content, while
    keeping tool response and retry prompt parts before injected instructions.

    The instructions are generated by AgentContext.get_context_instructions()
    and include:
    - Elapsed time since session start
    - Model configuration (context window size)
    - Token usage from the current request
    - System reminders (e.g., handoff threshold warning)

    Args:
        ctx: Runtime context containing AgentContext with model configuration.
        message_history: Current message history to process.

    Returns:
        Processed message history with runtime instructions injected into
        the last ModelRequest, or unchanged history if no ModelRequest found.

    Example:
        agent = Agent(
            'openai-chat:gpt-4',
            deps_type=AgentContext,
            history_processors=[inject_runtime_instructions],
        )
    """
    # Find the last ModelRequest in message history
    last_request: ModelRequest | None = None
    for msg in reversed(message_history):
        if isinstance(msg, ModelRequest):
            last_request = msg
            break

    if not last_request:
        return message_history

    # Determine if this is a user prompt (not a tool response or retry)
    # We include subagent info only on user prompts to reduce noise
    # Exception: force_inject_instructions overrides this after context reset (handoff/compact)
    is_user_prompt = not any(isinstance(part, (ToolReturnPart, RetryPromptPart)) for part in last_request.parts)
    if ctx.deps.force_inject_instructions:
        is_user_prompt = True

    # Get runtime instructions from AgentContext
    instructions = await ctx.deps.get_context_instructions(ctx, is_user_prompt=is_user_prompt)

    if not instructions:
        return message_history

    # Insert before ordinary user prompt content, while keeping any tool responses
    # and retry prompts before injected instructions for protocol-required ordering.
    runtime_part = UserPromptPart(content=instructions)
    insert_at = 0
    for index, part in enumerate(last_request.parts):
        if isinstance(part, (ToolReturnPart, RetryPromptPart)):
            insert_at = index + 1
    last_request.parts = [*last_request.parts[:insert_at], runtime_part, *last_request.parts[insert_at:]]

    return message_history
