"""Execution-kernel contract boundary models and interfaces.

These types define the acceptance boundary between raw execution intent,
immutable resolved runtime truth, ephemeral session state, and mutable agent
state. They intentionally omit orchestration, persistence, and adapter logic.
"""

from __future__ import annotations

from typing import Callable, Literal, Protocol, TypeAlias

from pydantic import BaseModel, ConfigDict, Field

from anima.core.contracts.execution import (
    CONTRACT_SCHEMA_VERSION,
    EXECUTION_INTENT_VERSION,
    EXECUTION_SESSION_VERSION,
    ContractIdentity,
    PersonaProvenance,
    RuntimeModelContext,
    RuntimeOutputPolicy,
    RuntimeToolAccess,
    SessionTransportState,
)
from anima.core.contracts.specs import JobSpec
from anima.core.execution.state import AgentResult, TokenUsage
from anima.core.schemas.enums import (
    AgentState,
    CompletionPolicy,
    LifecycleType,
    SideEffectPolicy,
)
from anima.core.schemas.models import PersonaSpec


class ExecutionIntentOverrides(BaseModel):
    """Raw CLI and request-layer overrides before precedence resolution."""

    model_config = ConfigDict(extra="forbid", frozen=True)

    requested_model: str | None = None
    requested_timeout: str | None = None
    requested_work_dir: str | None = None
    requested_project_root: str | None = None
    requested_filesystem_scope: str | None = None
    requested_cli_tools: tuple[str, ...] = ()
    requested_mcp_tools: tuple[str, ...] = ()
    requested_lifecycle: LifecycleType | None = None
    requested_completion_policy: CompletionPolicy | None = None
    requested_side_effect_policy: SideEffectPolicy | None = None


class ExecutionIntentDefaults(BaseModel):
    """Config/default values available during execution intent resolution."""

    model_config = ConfigDict(extra="forbid", frozen=True)

    default_model: str | None = None
    default_timeout: str | None = None
    default_work_dir: str | None = None
    default_project_root: str | None = None
    default_filesystem_scope: str | None = None
    default_side_effect_policy: SideEffectPolicy | None = None
    default_output_provider_profile: str | None = None
    default_per_call_tool_output_chars: int | None = None
    default_per_turn_tool_output_chars: int | None = None
    default_truncation_strategy: str | None = None


class ExecutionIntent(BaseModel):
    """Raw requested execution inputs before precedence and runtime probes."""

    model_config = ConfigDict(extra="forbid", frozen=True)

    intent_version: Literal["0.1.0"] = EXECUTION_INTENT_VERSION
    persona_spec: PersonaSpec | None = None
    job_spec: JobSpec | None = None
    overrides: ExecutionIntentOverrides = Field(
        default_factory=ExecutionIntentOverrides
    )
    defaults: ExecutionIntentDefaults = Field(default_factory=ExecutionIntentDefaults)


class ResolvedRuntime(BaseModel):
    """Immutable effective runtime settings after resolution completes."""

    model_config = ConfigDict(extra="forbid", frozen=True)

    effective_model: str = Field(min_length=1)
    timeout: str | None = None
    max_turns: int | None = None
    max_tokens: int | None = None
    work_dir: str | None = None
    project_root: str | None = None
    filesystem_scope: str | None = None
    sandbox_posture: str | None = None


class ResolvedLifecyclePolicy(BaseModel):
    """Immutable lifecycle and completion posture consumed by runtime control."""

    model_config = ConfigDict(extra="forbid", frozen=True)

    lifecycle: LifecycleType
    completion_policy: CompletionPolicy
    attachable: bool = True


class ResolvedExecutionContract(BaseModel):
    """Single immutable source of truth for effective runtime facts."""

    model_config = ConfigDict(extra="forbid", frozen=True)

    identity: ContractIdentity
    runtime: ResolvedRuntime
    tool_access: RuntimeToolAccess
    persona_provenance: PersonaProvenance
    lifecycle_policy: ResolvedLifecyclePolicy
    output_policy: RuntimeOutputPolicy
    model_context: RuntimeModelContext = Field(default_factory=RuntimeModelContext)


class ExecutionSessionState(BaseModel):
    """Ephemeral attach/session state that never redefines execution truth."""

    model_config = ConfigDict(extra="forbid")

    session_version: Literal["0.1.0"] = EXECUTION_SESSION_VERSION
    instance_id: str = Field(min_length=1)
    contract_version: Literal["0.1.0"] = CONTRACT_SCHEMA_VERSION
    transport: SessionTransportState = Field(default_factory=SessionTransportState)


ExecutionContractResolver = Callable[[ExecutionIntent], ResolvedExecutionContract]


class ExecutionToolAccessView(Protocol):
    """Narrow consumer view for effective tool-access decisions."""

    tool_access: RuntimeToolAccess


class ExecutionLaunchView(Protocol):
    """Narrow consumer view for launch orchestration decisions."""

    identity: ContractIdentity
    runtime: ResolvedRuntime
    tool_access: RuntimeToolAccess
    lifecycle_policy: ResolvedLifecyclePolicy
    output_policy: RuntimeOutputPolicy
    model_context: RuntimeModelContext


class ExecutionSpawnabilityView(Protocol):
    """Narrow consumer view for child-agent spawnability truth."""

    persona_provenance: PersonaProvenance


RuntimeContextFactValue: TypeAlias = str | int | float | bool | None


class OutputPolicyProviderProfileView(Protocol):
    """Narrow output-policy view for provider-profile selection."""

    provider_profile: str


class OutputPolicyPerCallCapView(Protocol):
    """Narrow output-policy view for single-call output governance."""

    per_call_tool_output_chars: int | None


class OutputPolicyPerTurnBudgetView(Protocol):
    """Narrow output-policy view for current-turn aggregate governance."""

    per_turn_tool_output_chars: int | None


class OutputPolicyTruncationStrategyView(Protocol):
    """Narrow output-policy view for truncation or pagination behavior."""

    truncation_strategy: str


class RuntimeOutputPolicyView(
    OutputPolicyProviderProfileView,
    OutputPolicyPerCallCapView,
    OutputPolicyPerTurnBudgetView,
    OutputPolicyTruncationStrategyView,
    Protocol,
):
    """Composed view for adapter-facing tool-output governance facts."""


class RuntimeContextFactsView(Protocol):
    """Narrow view for model-visible runtime context facts only."""

    values: dict[str, RuntimeContextFactValue]


class ExecutionOutputPolicyView(Protocol):
    """Contract consumer view for output-policy readers only."""

    output_policy: RuntimeOutputPolicyView


class ExecutionModelContextView(Protocol):
    """Contract consumer view for model-context readers only."""

    model_context: RuntimeContextFactsView


class ExecutionOutputGovernanceView(
    ExecutionOutputPolicyView, ExecutionModelContextView, Protocol
):
    """Contract consumer view for output-policy plus runtime-context readers."""


class ExecutionControlView(Protocol):
    """Narrow consumer view for control-path decisions."""

    identity: ContractIdentity
    lifecycle_policy: ResolvedLifecyclePolicy
    persona_provenance: PersonaProvenance


class AgentMutableStateView(Protocol):
    """Mutable execution-state facts owned by AgentStateData consumers only."""

    state: AgentState
    lifecycle: LifecycleType
    parent_id: str | None
    children: list[str]
    depth: int
    max_depth: int
    pid: int | None
    mcp_socket: str | None
    created_at: str | None
    updated_at: str | None
    token_usage: TokenUsage
    current_turn: int
    max_turns: int | None
    budget_total: int | None
    grace_budget: int
    error: str | None
    result_ref: str | None
    result: AgentResult | None
    resume_after: str | None
