"""
Database Models
===============
CTO-201: Approval & AuditLog persistence

Schema 設計原則：
- UUID 主鍵 (PostgreSQL 相容)
- JSON 欄位儲存複雜結構
- 完整時間戳記
- 索引優化查詢
"""

from datetime import UTC, datetime
from typing import Any
from uuid import uuid4

from sqlalchemy import (
    JSON,
    DateTime,
    Index,
    Integer,
    String,
    Text,
)
from sqlalchemy import (
    Enum as SQLEnum,
)
from sqlalchemy.orm import Mapped, mapped_column

from src.db.base import Base
from src.models.approval import ApprovalStatus, RiskLevel
from src.models.incident import IncidentStatus, Severity

# =============================================================================
# Helper Functions
# =============================================================================

def utc_now() -> datetime:
    """Get current UTC datetime"""
    return datetime.now(UTC)


def generate_uuid() -> str:
    """Generate UUID string"""
    return str(uuid4())


# =============================================================================
# ApprovalRecord - 授權記錄持久化
# =============================================================================

class ApprovalRecord(Base):
    """
    授權記錄 - 對應 Pydantic ApprovalRequest

    Note: 與 in-memory TrustEngine 的 ApprovalRequest 同步
    """
    __tablename__ = "approval_records"

    # Primary Key
    id: Mapped[str] = mapped_column(
        String(36),
        primary_key=True,
        default=generate_uuid,
    )

    # Core Fields
    action: Mapped[str] = mapped_column(String(500), nullable=False)
    description: Mapped[str] = mapped_column(Text, nullable=False)
    status: Mapped[str] = mapped_column(
        SQLEnum(ApprovalStatus),
        default=ApprovalStatus.PENDING,
        nullable=False,
    )
    risk_level: Mapped[str] = mapped_column(
        SQLEnum(RiskLevel),
        nullable=False,
    )

    # Signature Tracking
    required_signatures: Mapped[int] = mapped_column(Integer, default=1)
    current_signatures: Mapped[int] = mapped_column(Integer, default=0)
    signatures: Mapped[dict[str, Any]] = mapped_column(JSON, default=list)

    # Blast Radius (JSON)
    blast_radius: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict)

    # Dry-Run Checks (JSON)
    dry_run_checks: Mapped[list[dict[str, Any]]] = mapped_column(JSON, default=list)

    # Metadata
    requested_by: Mapped[str] = mapped_column(String(100), nullable=False)
    rejection_reason: Mapped[str | None] = mapped_column(Text, nullable=True)
    extra_metadata: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)

    # ==========================================================================
    # 戰略 B: 告警風暴收斂 (Alert Storm Convergence)
    # ==========================================================================
    # 告警指紋 - 根據 namespace + deployment + alert_name 產生的唯一 Hash
    fingerprint: Mapped[str | None] = mapped_column(
        String(64),
        nullable=True,
        index=True,
        comment="SHA256 hash of alert identity (namespace:deployment:alert_name)",
    )
    # 聚合次數 - 相同指紋告警的累計觸發次數
    hit_count: Mapped[int] = mapped_column(
        Integer,
        default=1,
        nullable=False,
        comment="Number of times this alert pattern was triggered",
    )
    # 最後觸發時間 - 同指紋告警最近一次出現的時間
    last_seen_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=utc_now,
        nullable=False,
        comment="Last time this alert pattern was seen",
    )

    # Timestamps
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=utc_now,
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=utc_now,
        onupdate=utc_now,
    )
    expires_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )
    resolved_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )

    # Indexes
    __table_args__ = (
        Index("ix_approval_status", "status"),
        Index("ix_approval_risk_level", "risk_level"),
        Index("ix_approval_created_at", "created_at"),
        Index("ix_approval_requested_by", "requested_by"),
        Index("ix_approval_fingerprint", "fingerprint"),  # 戰略 B: 指紋查詢優化
    )


# =============================================================================
# AuditLog - 稽核日誌
# =============================================================================

class TimelineEvent(Base):
    """
    時間軸事件 - Phase 4 Action Timeline

    事件類型:
    - system: 系統告警接收
    - agent: OpenClaw AI 分析
    - security: 權限阻擋
    - human: 人類授權
    - exec: 執行完成
    """
    __tablename__ = "timeline_events"

    # Primary Key
    id: Mapped[str] = mapped_column(
        String(36),
        primary_key=True,
        default=generate_uuid,
    )

    # Event Type & Status
    event_type: Mapped[str] = mapped_column(
        String(20),
        nullable=False,
        comment="system, agent, security, human, exec",
    )
    status: Mapped[str] = mapped_column(
        String(20),
        nullable=False,
        default="info",
        comment="info, success, warning, error",
    )

    # Content
    title: Mapped[str] = mapped_column(String(500), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)

    # Actor
    actor: Mapped[str | None] = mapped_column(String(100), nullable=True)
    actor_role: Mapped[str | None] = mapped_column(String(50), nullable=True)

    # Context
    risk_level: Mapped[str | None] = mapped_column(String(20), nullable=True)
    approval_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)

    # Timestamp
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=utc_now,
    )

    # Indexes
    __table_args__ = (
        Index("ix_timeline_event_type", "event_type"),
        Index("ix_timeline_created_at", "created_at"),
    )


class AuditLog(Base):
    """
    稽核日誌 - 記錄所有執行結果

    每次 K8s 操作完成後寫入一筆記錄
    """
    __tablename__ = "audit_logs"

    # Primary Key
    id: Mapped[str] = mapped_column(
        String(36),
        primary_key=True,
        default=generate_uuid,
    )

    # Reference to Approval
    approval_id: Mapped[str] = mapped_column(
        String(36),
        nullable=False,
        index=True,
    )

    # Operation Details
    operation_type: Mapped[str] = mapped_column(
        String(50),
        nullable=False,
        comment="e.g., RESTART_DEPLOYMENT, DELETE_POD",
    )
    target_resource: Mapped[str] = mapped_column(
        String(200),
        nullable=False,
        comment="e.g., deployment/api-backend, pod/nginx-xxx",
    )
    namespace: Mapped[str] = mapped_column(
        String(63),
        default="default",
        nullable=False,
    )

    # Execution Result
    success: Mapped[bool] = mapped_column(default=False, nullable=False)
    error_message: Mapped[str | None] = mapped_column(Text, nullable=True)

    # K8s Response (Raw)
    k8s_response: Mapped[dict[str, Any] | None] = mapped_column(
        JSON,
        nullable=True,
        comment="Raw Kubernetes API response",
    )

    # Execution Context
    executed_by: Mapped[str] = mapped_column(
        String(100),
        nullable=False,
        comment="Who triggered the execution",
    )
    execution_duration_ms: Mapped[int | None] = mapped_column(
        Integer,
        nullable=True,
        comment="Execution time in milliseconds",
    )

    # Dry-Run Result (pre-execution validation)
    dry_run_passed: Mapped[bool] = mapped_column(
        default=True,
        nullable=False,
    )
    dry_run_message: Mapped[str | None] = mapped_column(Text, nullable=True)

    # ==========================================================================
    # Phase 18: 失敗自動修復閉環欄位 (2026-03-26)
    # ==========================================================================

    # 授權來源追蹤
    authorization_channel: Mapped[str | None] = mapped_column(
        String(20),
        nullable=True,
        comment="Authorization source: web, telegram, auto",
    )

    # 重試與修復追蹤
    retry_count: Mapped[int] = mapped_column(
        Integer,
        default=0,
        nullable=False,
        comment="Number of retry attempts",
    )
    failure_classification: Mapped[str | None] = mapped_column(
        String(50),
        nullable=True,
        comment="Failure type: TIMEOUT, K8S_ERROR, NETWORK_ERROR, PERMISSION_DENIED",
    )
    source_approval_id: Mapped[str | None] = mapped_column(
        String(36),
        nullable=True,
        index=True,
        comment="Original approval ID if this is a repair attempt",
    )

    # 自動修復狀態
    auto_repair_attempted: Mapped[bool] = mapped_column(
        default=False,
        nullable=False,
        comment="Whether auto-repair was attempted",
    )
    auto_repair_result: Mapped[str | None] = mapped_column(
        Text,
        nullable=True,
        comment="Auto-repair result: AI analysis and repair outcome",
    )

    # Timestamps
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=utc_now,
    )

    # Indexes
    __table_args__ = (
        Index("ix_audit_approval_id", "approval_id"),
        Index("ix_audit_operation_type", "operation_type"),
        Index("ix_audit_success", "success"),
        Index("ix_audit_created_at", "created_at"),
        Index("ix_audit_authorization_channel", "authorization_channel"),  # Phase 18
        Index("ix_audit_failure_classification", "failure_classification"),  # Phase 18
    )


# =============================================================================
# IncidentRecord - Phase 6.2 Episodic Memory (PostgreSQL)
# =============================================================================

class IncidentRecord(Base):
    """
    事件記錄 - 對應 Pydantic Incident Schema v0.3

    Phase 6.2: Episodic Memory (長期記憶)
    - 從 Working Memory (Redis) 遷移過來
    - 永久保留，供 RAG 檢索
    - 複雜結構使用 JSONB 欄位

    三層記憶架構:
    - Working Memory (Redis): 7 天 TTL
    - Episodic Memory (PostgreSQL): 此表，永久保留
    - Semantic Memory (Vector DB): Phase 6.3+
    """
    __tablename__ = "incidents"

    # === 主鍵 ===
    incident_id: Mapped[str] = mapped_column(
        String(30),
        primary_key=True,
        comment="事件唯一識別碼 (如 INC-20260322-A1B2C3)",
    )

    # === 狀態與嚴重度 ===
    status: Mapped[str] = mapped_column(
        SQLEnum(IncidentStatus),
        default=IncidentStatus.INVESTIGATING,
        nullable=False,
        comment="事件狀態 (investigating, mitigating, resolved, closed, escalated)",
    )
    severity: Mapped[str] = mapped_column(
        SQLEnum(Severity),
        nullable=False,
        comment="事件嚴重度 (P0, P1, P2, P3)",
    )

    # === 感知層 (Signals) - JSONB ===
    signals: Mapped[list[dict[str, Any]]] = mapped_column(
        JSON,
        default=list,
        nullable=False,
        comment="關聯的告警信號列表 (JSONB)",
    )
    affected_services: Mapped[list[str]] = mapped_column(
        JSON,
        default=list,
        nullable=False,
        comment="受影響的服務列表",
    )

    # === 認知層 (AI Decision Chain) - JSONB ===
    decision_chain: Mapped[dict[str, Any] | None] = mapped_column(
        JSON,
        nullable=True,
        comment="AI 決策鏈 (完整推論過程)",
    )

    # === 決策層 (Proposals) ===
    proposal_ids: Mapped[list[str]] = mapped_column(
        JSON,
        default=list,
        nullable=False,
        comment="關聯的 ApprovalRequest ID 列表",
    )

    # === 結果層 (Outcome) - JSONB ===
    outcome: Mapped[dict[str, Any] | None] = mapped_column(
        JSON,
        nullable=True,
        comment="事件結果與人類回饋",
    )

    # === 時間軸 ===
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=utc_now,
        nullable=False,
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=utc_now,
        onupdate=utc_now,
        nullable=False,
    )
    resolved_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )
    closed_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )

    # === 記憶管理 ===
    ttl_days: Mapped[int] = mapped_column(
        Integer,
        default=7,
        nullable=False,
        comment="Working Memory TTL (天)",
    )
    vectorized: Mapped[bool] = mapped_column(
        default=False,
        nullable=False,
        comment="是否已向量化到 Vector DB (Semantic Memory)",
    )

    # === 索引 ===
    __table_args__ = (
        Index("ix_incident_status", "status"),
        Index("ix_incident_severity", "severity"),
        Index("ix_incident_created_at", "created_at"),
        Index("ix_incident_resolved_at", "resolved_at"),
    )
