"""Command envelope and policy result models for active agent (0.1.19)."""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Callable, Literal


ConfirmationResult = Literal["approve", "decline", "defer"]
ConfirmationCallback = Callable[["CommandEnvelope", "PolicyDecision"], ConfirmationResult]


class RiskLevel(str, Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


CANONICAL_CAPABILITY_KEYS = frozenset(
    {
        "READ_ONLY_SYSTEM_INFO",
        "READ_FILES_ALLOWED_PATHS",
        "WRITE_FILES_ALLOWED_PATHS",
        "RUN_SAFE_COMMANDS",
        "INSTALL_PACKAGES",
        "RESTART_SERVICES",
        "MANAGE_DESKTOP_APPS",
        "BROWSER_OPEN_URL",
        "PROJECT_WORKSPACE_ACCESS",
        "AI_ASSISTED_EXECUTION",
        "LOCAL_MODEL_EXECUTION",
        "OPENAI_ASSISTED_EXECUTION",
        "SCREEN_CAPTURE",
    }
)

BACKEND_CAPABILITY_TO_CANONICAL: dict[str, str] = {
    "agent.status.read": "READ_ONLY_SYSTEM_INFO",
    "agent.diagnostics.read": "READ_ONLY_SYSTEM_INFO",
    "agent.logs.collect": "READ_ONLY_SYSTEM_INFO",
    "agent.update.check": "READ_ONLY_SYSTEM_INFO",
    "agent.ui.notify": "READ_ONLY_SYSTEM_INFO",
    "agent.network.diagnostics": "READ_ONLY_SYSTEM_INFO",
    "agent.workspace.file.read": "READ_FILES_ALLOWED_PATHS",
    "agent.workspace.file.write": "WRITE_FILES_ALLOWED_PATHS",
    "agent.service.restart": "RESTART_SERVICES",
    "agent.package.install.dry_run": "INSTALL_PACKAGES",
    "agent.lifecycle.restart": "RESTART_SERVICES",
    "agent.shell.template": "RUN_SAFE_COMMANDS",
    "agent.desktop.app": "MANAGE_DESKTOP_APPS",
    "agent.desktop.input": "MANAGE_DESKTOP_APPS",
    "agent.browser.open_url": "BROWSER_OPEN_URL",
    "agent.network.fetch": "BROWSER_OPEN_URL",
    "agent.content.summarize": "BROWSER_OPEN_URL",
    "agent.desktop.document.edit": "MANAGE_DESKTOP_APPS",
    "agent.update.apply": "INSTALL_PACKAGES",
    "agent.screen.capture": "SCREEN_CAPTURE",
    "agent.screen.verify": "SCREEN_CAPTURE",
}


@dataclass(frozen=True)
class CommandEnvelope:
    command_id: str
    command_type: str
    payload: dict[str, Any]
    requested_at: str = ""
    expires_at: str = ""

    @classmethod
    def from_poll_response(cls, response: dict[str, Any]) -> CommandEnvelope:
        command = response.get("command") or {}
        if not isinstance(command, dict):
            raise ValueError("invalid_poll_response:missing_command")
        command_id = str(command.get("id") or "").strip()
        command_type = str(command.get("command_type") or "").strip()
        payload = command.get("payload") or {}
        if not command_id or not command_type:
            raise ValueError("invalid_poll_response:incomplete_command")
        if not isinstance(payload, dict):
            raise ValueError("invalid_poll_response:invalid_payload")
        return cls(
            command_id=command_id,
            command_type=command_type,
            payload=dict(payload),
            requested_at=str(command.get("requested_at") or ""),
            expires_at=str(command.get("expires_at") or ""),
        )

    @property
    def required_capability(self) -> str:
        return str(self.payload.get("required_capability") or "").strip().lower()

    @property
    def risk_level(self) -> str:
        return str(
            self.payload.get("capability_risk_level")
            or self.payload.get("risk_level")
            or "low"
        ).strip().lower()

    @property
    def scope(self) -> dict[str, Any]:
        raw = self.payload.get("scope")
        if isinstance(raw, dict) and raw:
            return dict(raw)
        effective = self.payload.get("capability_scope_effective")
        if isinstance(effective, dict) and effective:
            return dict(effective)
        return {}


@dataclass(frozen=True)
class PolicyDecision:
    allowed: bool
    reason_code: str = ""
    error_message: str = ""
    require_confirmation: bool = False
    capability_key: str = ""
    confirm_type: str = "none"
    stop_zone: str | None = None
    action_session_id: str = ""
    confirmation_skip_reason: str = ""
    plan_id: str = ""

    @property
    def policy_decision(self) -> str:
        return "allowed" if self.allowed else "denied"


@dataclass
class ExecutionResult:
    """Stub for Phase 4 executor integration."""

    success: bool
    execution_result: str = "ok"
    exit_code: int = 0
    evidence: dict[str, Any] = field(default_factory=dict)
    error_message: str = ""
    policy_decision: str = "allowed"
    capability_key: str = ""
    audit_record_id: str = ""

    def to_result_payload(self) -> dict[str, Any]:
        payload: dict[str, Any] = {
            "execution_result": self.execution_result,
            "exit_code": self.exit_code,
            "evidence": dict(self.evidence),
            "policy_decision": self.policy_decision,
        }
        if self.capability_key:
            payload["capability_key"] = self.capability_key
        if self.audit_record_id:
            payload["audit_record_id"] = self.audit_record_id
        if not self.success:
            payload["reason_code"] = self.execution_result
        return payload
