"""Exec Approval Types.

Type definitions for the command execution approval system in plugin-shell.
Provides types for approval configuration, allowlist entries, command analysis,
and approval decisions.
"""

from __future__ import annotations

from enum import Enum

from pydantic import BaseModel, Field


class ExecSecurity(str, Enum):
    """Security levels for command execution."""

    DENY = "deny"
    ALLOWLIST = "allowlist"
    FULL = "full"


class ExecAsk(str, Enum):
    """Ask modes for approval prompts."""

    OFF = "off"
    ON_MISS = "on-miss"
    ALWAYS = "always"


class ExecHost(str, Enum):
    """Execution host types."""

    SANDBOX = "sandbox"
    GATEWAY = "gateway"
    NODE = "node"


class RiskLevel(str, Enum):
    """Risk levels for command classification."""

    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


class CommandClassification(str, Enum):
    """Classification of command types."""

    READ_ONLY = "read_only"
    WRITE = "write"
    NETWORK = "network"
    SYSTEM = "system"
    DESTRUCTIVE = "destructive"
    UNKNOWN = "unknown"


class ExecApprovalsDefaults(BaseModel):
    """Default configuration for exec approvals."""

    security: ExecSecurity | None = None
    ask: ExecAsk | None = None
    ask_fallback: ExecSecurity | None = None
    auto_allow_skills: bool | None = None


class ExecAllowlistEntry(BaseModel):
    """Allowlist entry for permitted commands."""

    id: str | None = None
    pattern: str
    last_used_at: float | None = None
    last_used_command: str | None = None
    last_resolved_path: str | None = None


class ExecApprovalsAgent(ExecApprovalsDefaults):
    """Agent-specific approval configuration."""

    allowlist: list[ExecAllowlistEntry] | None = None


class ExecApprovalsFile(BaseModel):
    """Full approval configuration file structure."""

    version: int = 1
    socket: dict[str, str | None] | None = None
    defaults: ExecApprovalsDefaults | None = None
    agents: dict[str, ExecApprovalsAgent] | None = None


class ExecApprovalsSnapshot(BaseModel):
    """Snapshot of approval configuration file."""

    path: str
    exists: bool
    raw: str | None = None
    file: ExecApprovalsFile
    hash: str


class ExecApprovalsResolved(BaseModel):
    """Resolved approval configuration for an agent."""

    path: str
    socket_path: str
    token: str
    defaults: ExecApprovalsDefaults
    agent: ExecApprovalsDefaults
    allowlist: list[ExecAllowlistEntry] = Field(default_factory=list)
    file: ExecApprovalsFile


class CommandResolution(BaseModel):
    """Command resolution result."""

    raw_executable: str
    resolved_path: str | None = None
    executable_name: str


class ExecCommandSegment(BaseModel):
    """Command segment from shell parsing."""

    raw: str
    argv: list[str]
    resolution: CommandResolution | None = None


class ExecCommandAnalysis(BaseModel):
    """Result of command analysis."""

    ok: bool
    reason: str | None = None
    segments: list[ExecCommandSegment] = Field(default_factory=list)
    chains: list[list[ExecCommandSegment]] | None = None


class ExecAllowlistEvaluation(BaseModel):
    """Result of allowlist evaluation."""

    allowlist_satisfied: bool
    allowlist_matches: list[ExecAllowlistEntry] = Field(default_factory=list)


class ExecAllowlistAnalysis(BaseModel):
    """Combined analysis and allowlist evaluation."""

    analysis_ok: bool
    allowlist_satisfied: bool
    allowlist_matches: list[ExecAllowlistEntry] = Field(default_factory=list)
    segments: list[ExecCommandSegment] = Field(default_factory=list)


class ExecApprovalDecision(str, Enum):
    """Possible approval decisions."""

    ALLOW_ONCE = "allow-once"
    ALLOW_ALWAYS = "allow-always"
    DENY = "deny"


class ExecApprovalRequest(BaseModel):
    """Request for exec approval."""

    id: str
    command: str
    cwd: str | None = None
    host: ExecHost | None = None
    security: ExecSecurity | None = None
    ask: ExecAsk | None = None
    agent_id: str | None = None
    resolved_path: str | None = None
    session_key: str | None = None
    room_id: str
    timeout_ms: int | None = None


class ApprovalResult(BaseModel):
    """Result of exec approval."""

    decision: ExecApprovalDecision
    timed_out: bool = False
    resolved_by: str | None = None


# Default safe binaries that don't need approval
DEFAULT_SAFE_BINS: tuple[str, ...] = (
    "jq",
    "grep",
    "cut",
    "sort",
    "uniq",
    "head",
    "tail",
    "tr",
    "wc",
)

# Default exec approval settings
EXEC_APPROVAL_DEFAULTS = ExecApprovalsDefaults(
    security=ExecSecurity.DENY,
    ask=ExecAsk.ON_MISS,
    ask_fallback=ExecSecurity.DENY,
    auto_allow_skills=False,
)

EXEC_APPROVAL_TIMEOUT_MS: int = 120_000
