"""Norm Database Models"""
import uuid
from datetime import datetime
from typing import Optional, List, Dict, Any
from sqlalchemy import String, Text, Integer, ForeignKey, CheckConstraint
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship
from normbase.db.connection import Base


class Norm(Base):
    """Norm database model"""
    __tablename__ = "norms"
    
    __table_args__ = {"extend_existing": True}

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), 
        primary_key=True, 
        default=uuid.uuid4
    )
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    norm_type: Mapped[str] = mapped_column(
        String(50), 
        nullable=False,
        comment="obligation/prohibition/permission"
    )
    authority_level: Mapped[Optional[str]] = mapped_column(
        String(50),
        comment="legal/industry/organizational"
    )
    domain: Mapped[Optional[str]] = mapped_column(String(100))
    field_id: Mapped[Optional[uuid.UUID]] = mapped_column(
        UUID(as_uuid=True),
        comment="Information field this norm belongs to"
    )
    
    # Scope: which agents/roles/contexts this norm applies to
    scope_roles: Mapped[List[str]] = mapped_column(JSONB, default=list)
    scope_contexts: Mapped[List[str]] = mapped_column(JSONB, default=list)
    
    # Core norm elements
    condition: Mapped[Dict[str, Any]] = mapped_column(JSONB, default=dict)
    action: Mapped[Dict[str, Any]] = mapped_column(JSONB, default=dict)
    consequence: Mapped[Dict[str, Any]] = mapped_column(JSONB, default=dict)
    
    # LLM-readable format
    formatted_prompt: Mapped[Optional[str]] = mapped_column(Text)
    
    # Metadata
    source: Mapped[Optional[str]] = mapped_column(Text)  # Brief source (e.g., "EU AI Act Article 5(1)(a)")
    source_details: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB)  # Detailed source info
    version: Mapped[int] = mapped_column(Integer, default=1)
    status: Mapped[str] = mapped_column(
        String(20), 
        default="draft",
        comment="draft/active/deprecated"
    )
    
    # Relations to other norms
    case_refs: Mapped[List[str]] = mapped_column(JSONB, default=list)
    
    # Timestamps
    created_by: Mapped[Optional[str]] = mapped_column(String(100))
    created_at: Mapped[datetime] = mapped_column(
        default=datetime.utcnow,
        nullable=False
    )
    updated_at: Mapped[datetime] = mapped_column(
        default=datetime.utcnow,
        onupdate=datetime.utcnow,
        nullable=False
    )
    
    # Relationships
    versions: Mapped[List["NormVersion"]] = relationship(
        "NormVersion",
        back_populates="norm",
        cascade="all, delete-orphan"
    )
    
    __table_args__ = (
        CheckConstraint(
            "norm_type IN ('obligation', 'prohibition', 'permission')",
            name="ck_norm_type"
        ),
        CheckConstraint(
            "authority_level IN ('legal', 'industry', 'organizational') OR authority_level IS NULL",
            name="ck_authority_level"
        ),
        CheckConstraint(
            "status IN ('draft', 'active', 'deprecated')",
            name="ck_status"
        ),
    )
    
    def __repr__(self) -> str:
        return f"<Norm(id={self.id}, name={self.name}, type={self.norm_type})>"


class NormVersion(Base):
    """Norm version history"""
    __tablename__ = "norm_versions"
    
    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), 
        primary_key=True, 
        default=uuid.uuid4
    )
    norm_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("norms.id", ondelete="CASCADE"),
        nullable=False
    )
    version: Mapped[int] = mapped_column(Integer, nullable=False)
    snapshot: Mapped[Dict[str, Any]] = mapped_column(JSONB, nullable=False)
    change_note: Mapped[Optional[str]] = mapped_column(Text)
    created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
    
    # Relationship
    norm: Mapped["Norm"] = relationship("Norm", back_populates="versions")
    
    def __repr__(self) -> str:
        return f"<NormVersion(norm_id={self.norm_id}, version={self.version})>"


class NormRelation(Base):
    """Norm-to-norm relationships"""
    __tablename__ = "norm_relations"
    
    source_norm_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("norms.id", ondelete="CASCADE"),
        primary_key=True
    )
    target_norm_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("norms.id", ondelete="CASCADE"),
        primary_key=True
    )
    relation_type: Mapped[str] = mapped_column(
        String(50),
        primary_key=True,
        comment="conflicts_with/derives_from/supersedes/requires"
    )
    resolution: Mapped[Optional[str]] = mapped_column(String(50))
    
    __table_args__ = (
        CheckConstraint(
            "relation_type IN ('conflicts_with', 'derives_from', 'supersedes', 'requires')",
            name="ck_relation_type"
        ),
    )
    
    def __repr__(self) -> str:
        return f"<NormRelation({self.source_norm_id} -{self.relation_type}-> {self.target_norm_id})>"


class AuditLog(Base):
    """API audit trail"""
    __tablename__ = "audit_logs"
    
    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), 
        primary_key=True, 
        default=uuid.uuid4
    )
    api_key_id: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True))
    tool_name: Mapped[Optional[str]] = mapped_column(String(100))
    request: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB)
    response: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB)
    latency_ms: Mapped[Optional[int]] = mapped_column(Integer)
    created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
    
    def __repr__(self) -> str:
        return f"<AuditLog(id={self.id}, tool={self.tool_name})>"


class APIKey(Base):
    """API key for agent authentication"""
    __tablename__ = "api_keys"
    
    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), 
        primary_key=True, 
        default=uuid.uuid4
    )
    key_hash: Mapped[str] = mapped_column(String(255), nullable=False)
    name: Mapped[Optional[str]] = mapped_column(String(100))
    agent_id: Mapped[Optional[str]] = mapped_column(String(100))
    is_active: Mapped[bool] = mapped_column(default=True)
    created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
    expires_at: Mapped[Optional[datetime]] = mapped_column()
    
    def __repr__(self) -> str:
        return f"<APIKey(id={self.id}, name={self.name})>"
