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

from autopil.models import Decision, KeyScope, SensitivityLevel


# ── API Key schemas ───────────────────────────────────────────────────────────

class CreateKeyRequest(BaseModel):
    name:         str            = Field(..., description="Human-readable label for this key")
    scope:        KeyScope       = Field(KeyScope.ADMIN, description="admin | read | evaluate")
    expires_days: Optional[int]  = Field(None, ge=1, le=3650, description="Days until expiry; omit for no expiry")


class CreateKeyResponse(BaseModel):
    key_id:     str
    name:       str
    key:        str           = Field(..., description="Plaintext key — shown once, store it now")
    scope:      str
    expires_at: Optional[str] = None
    created_at: str


class KeySummary(BaseModel):
    key_id:        str
    name:          str
    created_at:    str
    last_used:     Optional[str] = None
    is_active:     bool
    tenant_id:     str
    is_superadmin: bool          = False
    scope:         str           = "admin"
    expires_at:    Optional[str] = None


class RotateKeyResponse(BaseModel):
    key_id:     str
    key:        str = Field(..., description="New plaintext key — shown once, store it now")
    scope:      str
    expires_at: Optional[str] = None


# ── Tenant schemas ────────────────────────────────────────────────────────────

class CreateTenantRequest(BaseModel):
    name: str = Field(..., description="Unique tenant name (e.g. company slug)")


class TenantResponse(BaseModel):
    tenant_id:  str
    name:       str
    created_at: str
    is_active:  bool


class CreateTenantResponse(BaseModel):
    tenant_id:  str
    name:       str
    created_at: str
    admin_key:  str = Field(..., description="Initial admin key for this tenant — shown once")


# ── Trial schemas ─────────────────────────────────────────────────────────────

class TrialProvisionRequest(BaseModel):
    name:     str = Field(..., description="Contact name")
    email:    str = Field(..., description="Work email")
    company:  str = Field(..., description="Company name")
    industry: str = Field("financial_services", description="Industry for policy seeding")


class TrialProvisionResponse(BaseModel):
    trial_id:      str
    tenant_id:     str
    api_key:       str = Field(..., description="Admin key for trial tenant — shown once")
    dashboard_url: str
    trial_end:     str
    email_sent:    bool


class TrialSummary(BaseModel):
    trial_id:         str
    tenant_id:        str
    name:             str
    email:            str
    company:          str
    industry:         str
    trial_start:      str
    trial_end:        str
    status:           str
    email_day7_sent:  bool
    email_day13_sent: bool


# ── Request schemas ──────────────────────────────────────────────────────────

class EvaluateRequest(BaseModel):
    query: str
    agent_role: str
    user_id: str
    source_id: str
    sensitivity_level: SensitivityLevel = SensitivityLevel.MEDIUM
    session_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    task_type: Optional[str] = Field(default=None, description="Task context for task-level policy scoping")


# ── Response schemas ─────────────────────────────────────────────────────────

class EvaluateResponse(BaseModel):
    decision: Decision
    policy_name: str
    reason: str
    event_id: str
    session_id: str
    timestamp: datetime


class AuditEventResponse(BaseModel):
    event_id: str
    session_id: str
    agent_role: str
    user_id: str
    source_id: str
    query: str
    decision: Decision
    policy_name: str
    reason: str
    timestamp: datetime
    context_hash: Optional[str] = None
    sensitivity_level: Optional[str] = None
    source_type: str = "rest"
    catalog_enriched: bool = False
    catalog_connection_id: Optional[str] = None


class AuditTrailResponse(BaseModel):
    session_id: str
    total_events: int
    allowed: int
    denied: int
    events: list[AuditEventResponse]


class ChainVerifyResponse(BaseModel):
    valid: bool
    total: int
    chained: int
    legacy: int
    broken_at: Optional[str] = None


class AuditRetentionResponse(BaseModel):
    retention_days: int
    policy: str
    anchor: Optional[dict] = None


class PolicySummary(BaseModel):
    name: str
    agent_role: str
    allowed_sources: list[str]
    denied_sources: list[str]
    max_sensitivity: str


class HealthResponse(BaseModel):
    status: str
    version: str
    policy_file: str
    audit_db: str


class CreatePolicyRequest(BaseModel):
    name: str = Field(..., description="Unique policy name")
    agent_role: str = Field(..., description="Agent role this policy applies to")
    allowed_sources: list[str] = Field(default=[], description="Allowed data sources (empty = all non-denied)")
    denied_sources: list[str] = Field(default=[], description="Always-blocked data sources")
    max_sensitivity: str = Field(default="high", description="Sensitivity ceiling: low | medium | high | restricted")
    allowed_tasks: list[str] = Field(default=[], description="Tasks this role may perform (empty = all non-denied)")
    denied_tasks: list[str] = Field(default=[], description="Tasks always blocked for this role")
    industry: Optional[str] = Field(default=None, description="Industry vertical (e.g. financial_services, healthcare)")
    category: Optional[str] = Field(default=None, description="Functional category within the industry (e.g. consumer_banking)")


class UpdatePolicyRequest(BaseModel):
    agent_role: str
    allowed_sources: list[str] = []
    denied_sources: list[str] = []
    max_sensitivity: str = "high"
    allowed_tasks: list[str] = []
    denied_tasks: list[str] = []
    industry: Optional[str] = None
    category: Optional[str] = None


class PolicyDetailResponse(BaseModel):
    policy_id: str
    name: str
    agent_role: str
    allowed_sources: list[str]
    denied_sources: list[str]
    max_sensitivity: str
    allowed_tasks: list[str] = []
    denied_tasks: list[str] = []
    industry: Optional[str] = None
    category: Optional[str] = None
    version: int
    created_at: str
    updated_at: str
    changed_by: Optional[str] = None


class PolicyVersionResponse(BaseModel):
    version_id: str
    version: int
    agent_role: str
    allowed_sources: list[str]
    denied_sources: list[str]
    max_sensitivity: str
    allowed_tasks: list[str] = []
    denied_tasks: list[str] = []
    industry: Optional[str] = None
    category: Optional[str] = None
    changed_by: Optional[str] = None
    changed_at: str


# ── Lineage schemas ───────────────────────────────────────────────────────────

class RecordActionRequest(BaseModel):
    event_id:      str  = Field(..., description="audit event_id that drove this action")
    session_id:    str  = Field(..., description="session_id from the audit event")
    action_type:   str  = Field(..., description="e.g. 'loan_decision', 'tool_call', 'response'")
    action_detail: dict = Field(default={}, description="Free-form JSON describing the action")
    outcome:       Optional[str] = Field(default=None, description="Optional outcome summary")


class AgentActionResponse(BaseModel):
    action_id:     str
    event_id:      str
    session_id:    str
    agent_role:    str
    action_type:   str
    action_detail: dict
    outcome:       Optional[str]
    timestamp:     datetime


class LineageResponse(BaseModel):
    event_id: str
    event:    AuditEventResponse
    actions:  list[AgentActionResponse]


# ── Session schemas ───────────────────────────────────────────────────────────

class SessionResponse(BaseModel):
    session_id:  str
    agent_role:  str
    user_id:     str
    created_at:  str
    last_active: str
    expires_at:  Optional[str] = None
    ttl_minutes: Optional[int] = None
    is_revoked:  bool
    status:      str  # "active" | "expired" | "revoked"


# ── Alert schemas ─────────────────────────────────────────────────────────────

class AlertRuleType(str, Enum):
    denial_spike        = "denial_spike"
    new_source          = "new_source"
    isolation_violation = "isolation_violation"
    high_deny_rate      = "high_deny_rate"


class CreateAlertRuleRequest(BaseModel):
    name:             str           = Field(..., description="Human-readable label for this rule")
    rule_type:        AlertRuleType
    threshold:        int           = Field(default=5,  ge=1, description="Count (denial_spike) or percent (high_deny_rate) to trigger")
    window_minutes:   int           = Field(default=60, ge=1, description="Look-back window in minutes")
    cooldown_minutes: int           = Field(default=60, ge=0, description="Minimum minutes between consecutive fires (0 = no cooldown)")
    webhook_url:      Optional[str] = Field(default=None, description="HTTP endpoint to POST alert payload")
    email:            Optional[str] = Field(default=None, description="Email address (requires SMTP_HOST env var)")


class UpdateAlertRuleRequest(BaseModel):
    name:             Optional[str]  = None
    threshold:        Optional[int]  = Field(default=None, ge=1)
    window_minutes:   Optional[int]  = Field(default=None, ge=1)
    cooldown_minutes: Optional[int]  = Field(default=None, ge=0)
    webhook_url:      Optional[str]  = None
    email:            Optional[str]  = None
    is_enabled:       Optional[bool] = None


class AlertRuleResponse(BaseModel):
    rule_id:          str
    name:             str
    rule_type:        str
    threshold:        int
    window_minutes:   int
    cooldown_minutes: int
    webhook_url:      Optional[str] = None
    email:            Optional[str] = None
    is_enabled:       bool
    created_at:       str
    last_fired_at:    Optional[str] = None


class AlertDeliveryResponse(BaseModel):
    delivery_id: str
    rule_id:     str
    rule_name:   str
    rule_type:   str
    fired_at:    str
    detail:      dict
    status:      str
    error:       Optional[str] = None


# ── Catalog schemas ───────────────────────────────────────────────────────────

class RegisterCatalogConnectionRequest(BaseModel):
    catalog_type:           str   = Field(..., description="unity_catalog | collibra | alation | purview")
    display_name:           str   = Field(..., description="Human-readable name for this connection")
    base_url:               str   = Field(..., description="Catalog base URL (e.g. https://workspace.azuredatabricks.net)")
    credentials:            dict  = Field(..., description="Connector-specific credentials (encrypted at rest, never returned)")
    sync_interval_minutes:  int   = Field(default=15, ge=1, description="How often to pull fresh classifications")
    webhook_secret:         Optional[str] = Field(default=None, description="HMAC secret for inbound push events")


class UpdateCatalogConnectionRequest(BaseModel):
    display_name:           Optional[str]  = None
    sync_interval_minutes:  Optional[int]  = Field(default=None, ge=1)
    is_enabled:             Optional[bool] = None
    webhook_secret:         Optional[str]  = None


class UpdateCatalogCredentialsRequest(BaseModel):
    credentials: dict = Field(
        ...,
        description="New connector-specific credentials. Must pass test_connection() before being saved.",
    )


class CatalogStatsResponse(BaseModel):
    total_connections:        int
    active_connections:       int
    degraded_connections:     int
    disabled_connections:     int
    total_classifications:    int
    sensitivity_distribution: dict  # label → count
    coverage_by_catalog_type: dict  # catalog_type → classification count


class CatalogConnectionResponse(BaseModel):
    connection_id:          str
    catalog_type:           str
    display_name:           str
    base_url:               str
    sync_interval_minutes:  int
    is_enabled:             bool
    status:                 str = "active"   # active | degraded | disabled
    created_at:             str
    updated_at:             str
    last_sync_at:           Optional[str] = None


class CatalogClassificationResponse(BaseModel):
    classification_id:  str
    connection_id:      str
    asset_fqn:          str
    asset_type:         str
    sensitivity_label:  str
    raw_label:          str
    data_classes:       list[str]
    is_certified:       Optional[bool]  = None
    trust_score:        Optional[float] = None
    fetched_at:         str
    expires_at:         str


class SyncResultResponse(BaseModel):
    sync_id:        str
    connection_id:  str
    status:         str
    assets_synced:  int
    assets_skipped: int
    started_at:     str
    completed_at:   Optional[str] = None
    error_message:  Optional[str] = None

