"""Policy models for orchestration history and review behavior."""

from __future__ import annotations

from typing import Literal

from pydantic import BaseModel, ConfigDict, Field, model_validator


class AgentHistoryPolicy(BaseModel):
    """How an orchestrator should prepare history for an execution agent."""

    model_config = ConfigDict(extra="forbid")

    window: Literal["full", "recent"]
    message_limit: int | None = None
    format: Literal["messages", "text", "markdown", "json"]
    include_turn_prompt: bool = True

    @model_validator(mode="after")
    def validate_window(self) -> "AgentHistoryPolicy":
        """Require a limit only when recent-window history is selected."""
        if self.window == "recent":
            if self.message_limit is None or self.message_limit < 1:
                raise ValueError(
                    "AgentHistoryPolicy.message_limit must be >= 1 when window='recent'"
                )
        else:
            self.message_limit = None
        return self


class HistoryContextPolicy(BaseModel):
    """Default and per-agent history configuration for execution agents."""

    model_config = ConfigDict(extra="forbid")

    default: AgentHistoryPolicy
    per_agent: dict[str, AgentHistoryPolicy] = Field(default_factory=dict)


class SelectorContextPolicy(BaseModel):
    """How AIOrchestrator should format context for agent selection."""

    model_config = ConfigDict(extra="forbid")

    window: Literal["full", "recent"] = "recent"
    message_limit: int | None = 12
    format: Literal["summary", "markdown", "json"] = "summary"

    @model_validator(mode="after")
    def validate_window(self) -> "SelectorContextPolicy":
        """Require a limit only when recent-window selector context is selected."""
        if self.window == "recent":
            if self.message_limit is None or self.message_limit < 1:
                raise ValueError(
                    "SelectorContextPolicy.message_limit must be >= 1 when window='recent'"
                )
        else:
            self.message_limit = None
        return self


class ReviewGatePolicy(BaseModel):
    """Review approval and revision-loop configuration for plan orchestration."""

    model_config = ConfigDict(extra="forbid")

    enabled: bool = False
    reviewer_agent_name: str = "reviewer"
    revision_agent_name: str = "writer"
    approval_signal: str = "APPROVED"
    max_revision_rounds: int = 2

    @model_validator(mode="after")
    def validate_rounds(self) -> "ReviewGatePolicy":
        """Ensure configured revision rounds are non-negative."""
        if self.max_revision_rounds < 0:
            raise ValueError("ReviewGatePolicy.max_revision_rounds must be >= 0")
        return self


class FinalResultPolicy(BaseModel):
    """Policy for selecting and cleaning the final result from shared messages."""

    model_config = ConfigDict(extra="forbid")

    prefer_agent: str | None = None
    """Agent name whose last AssistantMessage is returned as final_result.
    Falls back to last assistant message from any agent when no match is found."""

    strip_signals: list[str] = Field(default_factory=list)
    """Signal strings to remove from the selected message content."""

    strip_mode: Literal["trailing", "anywhere"] = "trailing"
    """trailing: remove only when the signal occupies the last line of content.
    anywhere: remove all occurrences from anywhere in the content."""
