"""
Trust zone definitions for agent security classification.

Trust zones establish security boundaries that control information flow
between agents. Higher zones are more restricted and cannot be accessed
from lower zones.

Requirements: SEC-02 (trust zone boundaries)
"""

from __future__ import annotations

from datetime import datetime, timezone
from enum import Enum
from typing import Optional

from pydantic import BaseModel, Field


class TrustZone(str, Enum):
    """
    Security classification levels for agents and data.

    Trust zones follow a hierarchical model where higher zones
    represent more restricted access. Access flows from higher
    to lower zones, but not vice versa.

    Levels (from least to most restricted):
    - PUBLIC: Fully shared, no restrictions
    - INTERNAL: Project-level sharing within organization
    - CONFIDENTIAL: Phase-specific, limited access
    - SECRET: Agent-specific, no sharing allowed
    """

    PUBLIC = "public"
    INTERNAL = "internal"
    CONFIDENTIAL = "confidential"
    SECRET = "secret"

    @property
    def priority(self) -> int:
        """
        Get numeric priority for access control comparisons.

        Higher priority = more restricted zone.

        Returns:
            Integer priority (0=PUBLIC, 1=INTERNAL, 2=CONFIDENTIAL, 3=SECRET).
        """
        priorities = {
            TrustZone.PUBLIC: 0,
            TrustZone.INTERNAL: 1,
            TrustZone.CONFIDENTIAL: 2,
            TrustZone.SECRET: 3,
        }
        return priorities[self]

    def allows_access_from(self, source: TrustZone) -> bool:
        """
        Check if source zone can access this zone's data.

        Access is allowed if source has equal or higher priority
        (i.e., source is at least as restricted as this zone).

        Args:
            source: The zone requesting access.

        Returns:
            True if access is allowed, False otherwise.

        Example:
            >>> TrustZone.INTERNAL.allows_access_from(TrustZone.SECRET)
            True  # SECRET can access INTERNAL
            >>> TrustZone.SECRET.allows_access_from(TrustZone.PUBLIC)
            False  # PUBLIC cannot access SECRET
        """
        return source.priority >= self.priority

    def __lt__(self, other: TrustZone) -> bool:
        """Compare zones by priority for sorting."""
        return self.priority < other.priority

    def __le__(self, other: TrustZone) -> bool:
        """Compare zones by priority for sorting."""
        return self.priority <= other.priority

    def __gt__(self, other: TrustZone) -> bool:
        """Compare zones by priority for sorting."""
        return self.priority > other.priority

    def __ge__(self, other: TrustZone) -> bool:
        """Compare zones by priority for sorting."""
        return self.priority >= other.priority


def _utc_now() -> datetime:
    """Get current UTC datetime."""
    return datetime.now(timezone.utc)


class ZoneAssignment(BaseModel):
    """
    Assignment of an agent to a trust zone.

    Tracks which zone an agent belongs to, when it was assigned,
    and who made the assignment. This enables audit trails and
    dynamic zone changes.

    Attributes:
        agent_id: Unique identifier for the agent.
        zone: Trust zone classification for this agent.
        assigned_at: Timestamp of zone assignment (UTC).
        assigned_by: Entity that made the assignment (default: "system").
        reason: Optional explanation for the zone assignment.
    """

    model_config = {"extra": "forbid"}  # Reject unknown fields

    agent_id: str = Field(..., min_length=1, description="Agent identifier")
    zone: TrustZone = Field(..., description="Assigned trust zone")
    assigned_at: datetime = Field(
        default_factory=_utc_now,
        description="Assignment timestamp (UTC)",
    )
    assigned_by: str = Field(
        default="system",
        min_length=1,
        description="Entity that made the assignment",
    )
    reason: Optional[str] = Field(
        default=None,
        description="Optional explanation for zone assignment",
    )

    def can_access(self, target_zone: TrustZone) -> bool:
        """
        Check if this agent can access data in target zone.

        Convenience method that delegates to TrustZone.allows_access_from.

        Args:
            target_zone: Zone of the data being accessed.

        Returns:
            True if access is allowed, False otherwise.
        """
        return target_zone.allows_access_from(self.zone)

    def __repr__(self) -> str:
        """String representation for debugging."""
        return (
            f"ZoneAssignment("
            f"agent_id={self.agent_id!r}, "
            f"zone={self.zone.value}, "
            f"assigned_by={self.assigned_by!r})"
        )
