"""
ID Wispera Type Definitions
Pydantic models for type-safe credential governance
"""

from datetime import datetime
from enum import Enum
from typing import Any, Optional
from pydantic import BaseModel, ConfigDict, Field
import uuid


class VisaType(str, Enum):
    """Category of authorization a credential provides"""
    ACCESS = "access"
    PRIVILEGE = "privilege"
    DATA = "data"
    COMPLIANCE = "compliance"
    ECOSYSTEM = "ecosystem"
    CUSTOM = "custom"


class CredentialType(str, Enum):
    """Type of credential"""
    API_KEY = "api-key"
    OAUTH_TOKEN = "oauth-token"
    SECRET = "secret"
    CERTIFICATE = "certificate"
    MCP_CREDENTIAL = "mcp-credential"
    JWT = "jwt"
    CONNECTION_STRING = "connection-string"
    PRIVATE_KEY = "private-key"
    SESSION_KEYS = "session-keys"
    BOT_TOKEN = "bot-token"
    CUSTOM = "custom"


class Platform(str, Enum):
    """Supported platforms"""
    MCP = "mcp"
    OPENAI = "openai"
    ANTHROPIC = "anthropic"
    GOOGLE_A2A = "google-a2a"
    LANGCHAIN = "langchain"
    AZURE_AI = "azure-ai"
    AWS = "aws"
    CREWAI = "crewai"
    OPENCLAW = "openclaw"
    GITHUB = "github"
    CUSTOM = "custom"


class PassportStatus(str, Enum):
    """Lifecycle status of a passport"""
    ACTIVE = "active"
    EXPIRING = "expiring"
    EXPIRED = "expired"
    REVOKED = "revoked"
    SUSPENDED = "suspended"


class AuditAction(str, Enum):
    """Actions that can be logged"""
    CREATED = "created"
    VIEWED = "viewed"
    SHARED = "shared"
    MODIFIED = "modified"
    REVOKED = "revoked"
    RENEWED = "renewed"
    ACCESSED = "accessed"
    POLICY_CHECKED = "policy-checked"
    DETECTED = "detected"
    EXPORTED = "exported"
    IMPORTED = "imported"


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


class DelegationHop(BaseModel):
    """A single hop in the delegation chain"""
    from_entity: str = Field(alias="from", description="Entity that granted the delegation")
    to: str = Field(description="Entity that received the delegation")
    granted_at: datetime = Field(alias="grantedAt", description="When the delegation was granted")
    scope: Optional[list[str]] = Field(default=None, description="What scopes were delegated")
    expires_at: Optional[datetime] = Field(
        default=None, alias="expiresAt", description="When this delegation expires"
    )
    notes: Optional[str] = Field(default=None, description="Optional notes")

    class Config:
        populate_by_name = True


class Passport(BaseModel):
    """
    The core Passport model
    A passport wraps a credential with identity, authorization, and lifecycle management
    """
    id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique identifier")
    version: int = Field(default=1, description="Schema version")

    # Identity
    name: str = Field(description="Human-readable name")
    agent_id: Optional[str] = Field(default=None, alias="agentId", description="Machine identifier")
    credential_type: CredentialType = Field(alias="credentialType", description="Type of credential")
    credential_value: str = Field(alias="credentialValue", description="The credential value")

    # Visa (Authorization)
    visa_type: VisaType = Field(alias="visaType", description="Category of authorization")
    issuing_authority: str = Field(
        default="Manual", alias="issuingAuthority", description="Who issued this credential"
    )
    scope: list[str] = Field(default_factory=list, description="Permitted operations")
    platforms: list[Platform] = Field(description="Valid platforms")

    # Lifecycle
    status: PassportStatus = Field(default=PassportStatus.ACTIVE, description="Current status")
    issued_at: datetime = Field(
        default_factory=datetime.utcnow, alias="issuedAt", description="When issued"
    )
    valid_from: datetime = Field(
        default_factory=datetime.utcnow, alias="validFrom", description="When valid from"
    )
    valid_until: Optional[datetime] = Field(
        default=None, alias="validUntil", description="When expires"
    )
    revoked_at: Optional[datetime] = Field(default=None, alias="revokedAt")
    revoked_by: Optional[str] = Field(default=None, alias="revokedBy")
    revoked_reason: Optional[str] = Field(default=None, alias="revokedReason")

    # Delegation
    delegation_chain: list[DelegationHop] = Field(
        default_factory=list, alias="delegationChain", description="Chain of custody"
    )
    human_owner: str = Field(alias="humanOwner", description="Human accountable for this credential")

    # Metadata
    tags: list[str] = Field(default_factory=list, description="Tags for organization")
    notes: Optional[str] = Field(default=None, description="Free-form notes")

    # Timestamps
    created_at: datetime = Field(
        default_factory=datetime.utcnow, alias="createdAt", description="When created"
    )
    updated_at: datetime = Field(
        default_factory=datetime.utcnow, alias="updatedAt", description="When last updated"
    )

    class Config:
        populate_by_name = True
        use_enum_values = True


class AuditEntry(BaseModel):
    """A single audit log entry"""
    id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique identifier")
    passport_id: str = Field(alias="passportId", description="Related passport")
    action: AuditAction = Field(description="What action was performed")
    actor: str = Field(description="Who performed the action")
    timestamp: datetime = Field(
        default_factory=datetime.utcnow, description="When the action occurred"
    )
    platform: Optional[Platform] = Field(default=None, description="Which platform")
    details: Optional[str] = Field(default=None, description="Human-readable description")
    metadata: Optional[dict] = Field(default=None, description="Additional structured data")

    class Config:
        populate_by_name = True
        use_enum_values = True


class DetectionResult(BaseModel):
    """Result of detecting a credential in text"""
    type: CredentialType = Field(description="Type of credential detected")
    value: str = Field(description="The detected value")
    start_index: int = Field(alias="startIndex", description="Start position")
    end_index: int = Field(alias="endIndex", description="End position")
    confidence: float = Field(ge=0, le=1, description="Confidence score")
    line: Optional[int] = Field(default=None, description="Line number (1-indexed)")
    column: Optional[int] = Field(default=None, description="Column number (1-indexed)")
    pattern: Optional[str] = Field(default=None, description="Pattern that matched")
    context: Optional[str] = Field(default=None, description="Surrounding text")
    risk_level: RiskLevel = Field(
        default=RiskLevel.MEDIUM, alias="riskLevel", description="Risk classification"
    )

    class Config:
        populate_by_name = True
        use_enum_values = True


class CreatePassportInput(BaseModel):
    """Input for creating a new passport"""
    name: str
    agent_id: Optional[str] = Field(default=None, alias="agentId")
    credential_type: CredentialType = Field(alias="credentialType")
    credential_value: str = Field(alias="credentialValue")
    visa_type: VisaType = Field(alias="visaType")
    issuing_authority: Optional[str] = Field(default="Manual", alias="issuingAuthority")
    scope: list[str] = Field(default_factory=list)
    platforms: list[Platform]
    valid_from: Optional[datetime] = Field(default=None, alias="validFrom")
    valid_until: Optional[datetime] = Field(default=None, alias="validUntil")
    delegation_chain: list[DelegationHop] = Field(default_factory=list, alias="delegationChain")
    human_owner: str = Field(alias="humanOwner")
    tags: list[str] = Field(default_factory=list)
    notes: Optional[str] = None

    class Config:
        populate_by_name = True
        use_enum_values = True


class ShareScope(str, Enum):
    """Scope of what is shared"""
    FULL = "full"
    METADATA_ONLY = "metadata-only"
    READ_ONLY = "read-only"


class PolicyEffect(str, Enum):
    """Effect of a policy rule"""
    ALLOW = "allow"
    DENY = "deny"
    REQUIRE_APPROVAL = "require-approval"


class PolicyCondition(BaseModel):
    """Conditions for policy evaluation"""
    visa_types: Optional[list[VisaType]] = Field(None, alias="visaTypes")
    platforms: Optional[list[Platform]] = None
    scopes: Optional[list[str]] = None
    max_delegation_depth: Optional[int] = Field(None, alias="maxDelegationDepth")
    require_human_owner: Optional[bool] = Field(None, alias="requireHumanOwner")
    max_validity_days: Optional[int] = Field(None, alias="maxValidityDays")
    credential_types: Optional[list[CredentialType]] = Field(None, alias="credentialTypes")
    tags: Optional[list[str]] = None
    # Note: custom condition not serializable, use at runtime only
    custom: Optional[Any] = Field(None, exclude=True)
    model_config = ConfigDict(populate_by_name=True)


class PolicyRule(BaseModel):
    """A policy rule for credential governance"""
    id: str
    name: str
    description: str
    condition: PolicyCondition
    effect: PolicyEffect
    priority: int = 50
    enabled: bool = True
    model_config = ConfigDict(populate_by_name=True)


class PolicyDecision(BaseModel):
    """Result of policy evaluation"""
    allowed: bool
    effect: PolicyEffect
    matched_rules: list["PolicyRule"] = Field(default_factory=list, alias="matchedRules")
    reason: str
    model_config = ConfigDict(populate_by_name=True)


class ValidationResult(BaseModel):
    """Result of validating a passport against rules"""
    rule: PolicyRule
    violation: str
    severity: str  # "warning" or "error"


class ShareOptions(BaseModel):
    """Options for creating a share link"""
    scope: ShareScope
    expires_at: Optional[str] = Field(None, alias="expiresAt")
    max_views: Optional[int] = Field(None, alias="maxViews")
    require_verification: bool = Field(False, alias="requireVerification")
    recipient: Optional[str] = None
    model_config = ConfigDict(populate_by_name=True)


class SharePayload(BaseModel):
    """Encrypted share payload"""
    version: int
    encrypted: str
    options: ShareOptions
    created_at: str = Field(alias="createdAt")
    passport_id: str = Field(alias="passportId")
    view_count: int = Field(0, alias="viewCount")
    model_config = ConfigDict(populate_by_name=True)
