"""Pydantic Schemas for Norm API"""
from datetime import datetime
from typing import Optional, List, Dict, Any, Literal, Annotated
from uuid import UUID
from pydantic import BaseModel, Field, ConfigDict, StringConstraints


CreatedByRef = Annotated[
    str,
    StringConstraints(pattern=r"^(user|org|system|external):.+$"),
]


# --- Norm Schemas ---

class NormScope(BaseModel):
    """Norm scope definition"""
    roles: List[str] = Field(default_factory=list, description="Applicable agent roles")
    contexts: List[str] = Field(default_factory=list, description="Applicable contexts")


class NormCondition(BaseModel):
    """Norm condition definition"""
    trigger: str = Field(..., description="Trigger event")
    preconditions: List[str] = Field(default_factory=list, description="Required preconditions")


class NormAction(BaseModel):
    """Norm action definition"""
    required: Optional[str] = Field(None, description="Required action")
    prohibited: List[str] = Field(default_factory=list, description="Prohibited actions")


class NormConsequence(BaseModel):
    """Norm consequence definition"""
    on_compliance: Optional[Dict[str, Any]] = Field(None, description="Reward for compliance")
    on_violation: Optional[Dict[str, Any]] = Field(None, description="Sanction for violation")


class NormTagItem(BaseModel):
    """Norm tag item"""
    model_config = ConfigDict(from_attributes=True)
    tag: str = Field(..., min_length=1, max_length=100)
    tag_category: str = Field(..., description="scenario/role/tool/domain")


class NormCreate(BaseModel):
    """Schema for creating a new norm"""
    # Identity zone
    title: str = Field(..., min_length=1, max_length=255)
    field_id: Optional[UUID] = Field(None, description="Information field ID")

    # Attribute zone
    norm_type: Literal["obligation", "permission", "prohibition"]
    authority_level: Optional[Literal["legal", "industrial", "organizational", "group"]] = None
    formality_level: Optional[Literal["informal", "formal", "technical"]] = None

    # Content zone
    subject: Dict[str, Any] = Field(default_factory=dict)
    context: Dict[str, Any] = Field(default_factory=dict)
    condition: Dict[str, Any] = Field(default_factory=dict)
    action: Dict[str, Any] = Field(default_factory=dict)
    consequence: Dict[str, Any] = Field(default_factory=dict)

    # Evidence zone
    source: Optional[str] = Field(None, description="Source document/policy (brief)")
    source_details: Optional[Dict[str, Any]] = Field(None, description="Detailed source information")
    case_refs: List[str] = Field(default_factory=list)

    # Audit zone
    created_by: Optional[CreatedByRef] = Field(
        None,
        description="Creator/authority reference. Format: user:<id>|org:<id>|system:<id>|external:<id>",
    )

    # Governance zone
    status: str = Field("draft", description="draft/active/deprecated/archived")
    tags: List[NormTagItem] = Field(default_factory=list, description="Norm tags")


class NormUpdate(BaseModel):
    """Schema for updating an existing norm"""
    # Identity zone
    title: Optional[str] = Field(None, min_length=1, max_length=255)
    field_id: Optional[UUID] = None

    # Attribute zone
    norm_type: Optional[Literal["obligation", "permission", "prohibition"]] = None
    authority_level: Optional[Literal["legal", "industrial", "organizational", "group"]] = None
    formality_level: Optional[Literal["informal", "formal", "technical"]] = None

    # Content zone
    subject: Optional[Dict[str, Any]] = None
    context: Optional[Dict[str, Any]] = None
    condition: Optional[Dict[str, Any]] = None
    action: Optional[Dict[str, Any]] = None
    consequence: Optional[Dict[str, Any]] = None

    # Evidence zone
    source: Optional[str] = None
    source_details: Optional[Dict[str, Any]] = None
    case_refs: Optional[List[str]] = None

    # Audit zone
    created_by: Optional[CreatedByRef] = None

    # Governance zone
    status: Optional[str] = Field(None, description="draft/active/deprecated/archived")
    tags: Optional[List[NormTagItem]] = None


class NormResponse(BaseModel):
    """Schema for norm response"""
    model_config = ConfigDict(from_attributes=True)
    
    # Identity zone
    id: UUID
    title: str
    field_id: Optional[UUID] = None  # Information field ID

    # Attribute zone
    norm_type: str
    authority_level: Optional[str] = None
    formality_level: Optional[str] = None

    # Content zone
    subject: Dict[str, Any]
    context: Dict[str, Any]
    condition: Dict[str, Any]
    action: Dict[str, Any]
    consequence: Dict[str, Any]

    # Evidence zone
    source: Optional[str] = None
    source_details: Optional[Dict[str, Any]] = None
    case_refs: List[str]

    # Audit zone
    created_by: Optional[str] = None
    created_at: datetime
    updated_at: datetime

    # Governance zone
    status: str
    version: int
    tags: List[NormTagItem] = Field(default_factory=list)


class NormListResponse(BaseModel):
    """Schema for norm list response"""
    total: int
    items: List[NormResponse]
    page: int = 1
    page_size: int = 20


# --- Norm Version Schemas ---

class NormVersionResponse(BaseModel):
    """Schema for norm version response"""
    model_config = ConfigDict(from_attributes=True)
    
    id: UUID
    norm_id: UUID
    version: int
    snapshot: Dict[str, Any]
    change_note: Optional[str] = None
    created_at: datetime


# --- Norm Relation Schemas ---

class NormRelationCreate(BaseModel):
    """Schema for creating norm relation"""
    target_norm_id: UUID
    relation_type: str  # conflicts_with/derives_from/supersedes/requires
    resolution: Optional[str] = None


class NormRelationResponse(BaseModel):
    """Schema for norm relation response"""
    model_config = ConfigDict(from_attributes=True)
    
    source_norm_id: UUID
    target_norm_id: UUID
    relation_type: str
    resolution: Optional[str] = None


# --- Retrieve Schemas ---

class NormRetrieveRequest(BaseModel):
    """Schema for norm retrieval request"""
    context: Dict[str, Any] = Field(default_factory=dict, description="Task context")
    agent_role: Optional[str] = Field(None, description="Optional agent role")
    tag_filters: Optional[Dict[str, List[str]]] = Field(
        None,
        description="Optional tag filters by category. Keys: role/scenario/domain/tool",
    )
    field_ids: Optional[List[UUID]] = Field(None, description="Information field IDs to search in")
    top_k: int = Field(5, ge=1, le=50, description="Number of norms to retrieve")


class NormRetrieveResponse(BaseModel):
    """Schema for norm retrieval response"""
    norms: List[NormResponse]
    scores: List[float]
    total: int
    usage_token: str
    cache_hit: bool = False


class ComplianceCheckRequest(BaseModel):
    """Schema for action compliance check request."""
    usage_token: str = Field(..., min_length=1, max_length=100)
    action_description: str = Field(..., min_length=1)
    norm_ids: Optional[List[UUID]] = None


class ComplianceViolation(BaseModel):
    """One detected compliance violation."""
    norm_id: UUID
    violation_type: str
    message: str


class ComplianceCheckResponse(BaseModel):
    """Schema for action compliance check result."""
    compliant: bool
    violations: List[ComplianceViolation] = Field(default_factory=list)


class NormOutcomeReportRequest(BaseModel):
    """Schema for norm usage outcome reporting."""
    usage_token: str = Field(..., min_length=1, max_length=100)
    norm_id: UUID
    outcome: str = Field(..., description="complied/violated/exception/inapplicable")
    details: Dict[str, Any] = Field(default_factory=dict)
    agent_id: Optional[str] = None
    project_id: Optional[str] = None
    task_context: Optional[str] = None


class NormOutcomeReportResponse(BaseModel):
    """Schema for norm usage outcome report ack."""
    id: UUID
    usage_token: str
    norm_id: UUID
    outcome: str
    created_at: datetime


# --- Role Suggestion Schemas ---

class RoleCandidate(BaseModel):
    """One suggested role candidate for retrieval."""
    role: str
    score: float
    norm_count: int
    matched_contexts: List[str] = Field(default_factory=list)


class RoleSuggestRequest(BaseModel):
    """Schema for role suggestion request."""
    context: Dict[str, Any] = Field(default_factory=dict, description="Task context")
    field_ids: Optional[List[UUID]] = Field(None, description="Optional information field IDs")
    top_k: int = Field(5, ge=1, le=20, description="Number of candidate roles")


class RoleSuggestResponse(BaseModel):
    """Schema for role suggestion response."""
    candidates: List[RoleCandidate]
    recommended_role: Optional[str] = None


class RetrievalPlanResponse(BaseModel):
    """Schema for retrieval planning response."""
    candidates: List[RoleCandidate]
    recommended_role: Optional[str] = None
    role_is_global: bool = False
    suggested_tag_filters: Dict[str, List[str]] = Field(default_factory=dict)


# --- Field Schemas ---

class FieldCreate(BaseModel):
    """Schema for creating an information field."""
    name: str = Field(..., min_length=1, max_length=255)
    description: Optional[str] = None
    org_id: Optional[UUID] = None
    status: Literal["active", "inactive", "archived"] = "active"


class FieldUpdate(BaseModel):
    """Schema for partially updating an information field."""
    name: Optional[str] = Field(None, min_length=1, max_length=255)
    description: Optional[str] = None
    org_id: Optional[UUID] = None
    status: Optional[Literal["active", "inactive", "archived"]] = None


class FieldResponse(BaseModel):
    """Schema for information field response."""
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    name: Optional[str] = None
    org_id: Optional[UUID] = None
    description: Optional[str] = None
    status: str
    created_at: datetime
    updated_at: datetime
