from sqlalchemy import CheckConstraint, Column, Integer, String, DateTime, Text, Boolean, ForeignKey, Index, Float
from sqlalchemy.orm import relationship
from database.models import Base
from datetime import datetime


class AgentContext(Base):
    """
    共享上下文表（替代硬編碼鏈），支援多 Agent 存取與 TTL。
    索引：(session_id, agent_name, context_key) 以加速跨 Agent 查詢。
    """
    __tablename__ = 'agent_context'

    id = Column(Integer, primary_key=True, autoincrement=True)
    session_id = Column(String(64), nullable=False, index=True)
    agent_name = Column(String(50), nullable=False, index=True)
    context_key = Column(String(100), nullable=False)
    context_val = Column(Text)  # JSON string
    created_at = Column(DateTime, default=datetime.now)
    ttl_minutes = Column(Integer, default=60)

    __table_args__ = (
        Index('idx_agent_context_session_key', 'session_id', 'agent_name', 'context_key'),
        Index('idx_agent_context_session_ttl', 'session_id', 'created_at'),
        {'extend_existing': True},
    )


class ActionPlan(Base):
    """
    行動計畫表 — 統一 schema（超集）。
    Group A（01-init.sql / CodeReview / OpenClaw）:
      action_type, description, priority, metadata_json
    Group B（migration 017 / watcher_agent / ai_orchestrator）:
      session_id, plan_type, sku, payload, created_by, approved_by, executed_at
    migration 019 已在 DB 補齊所有欄位。
    """
    __tablename__ = 'action_plans'

    id = Column(Integer, primary_key=True, autoincrement=True)
    # Group A columns
    action_type = Column(String(100), nullable=True)    # code_review_fix / openclaw_recommendation
    description = Column(Text)                          # 人類可讀的行動說明
    status = Column(String(50), default='pending')      # pending/auto_pending/pending_review/executed
    priority = Column(Integer, default=3)               # 1=critical 2=high 3=medium 4=low
    metadata_json = Column(Text)                        # JSON: pipeline_id/commit_sha/findings
    created_at = Column(DateTime, default=datetime.now)
    # Group B columns (ADR-012 / NemoTron)
    session_id = Column(String(64), nullable=True)
    plan_type = Column(String(50), nullable=True)       # price_adjust / restock / campaign
    sku = Column(String(100), nullable=True)
    payload = Column(Text)                              # JSON 行動內容
    created_by = Column(String(50))                     # nemotron / openclaw
    approved_by = Column(String(100), nullable=True)    # Telegram user_id
    executed_at = Column(DateTime, nullable=True)

    __table_args__ = (
        CheckConstraint(
            "action_type IS NOT NULL OR created_by IS NOT NULL",
            name="chk_action_plans_source_marker",
        ),
        CheckConstraint(
            "action_type IS NULL OR action_type IN ('auto', 'code_review_fix', 'openclaw_recommendation')",
            name="chk_action_plans_action_type",
        ),
        CheckConstraint(
            "created_by IS NULL OR created_by IN ("
            "'nemotron', 'openclaw', 'code_review_pipeline', "
            "'ai_orchestrator', 'watcher_agent', 'agent_actions', "
            "'elephant_alpha', 'manual', 'system'"
            ")",
            name="chk_action_plans_created_by",
        ),
        CheckConstraint(
            "status IS NULL OR status IN ("
            "'pending', 'approved', 'rejected', 'executed', "
            "'auto_pending', 'auto_disabled', 'pending_review'"
            ")",
            name="chk_action_plans_status",
        ),
        Index('idx_action_plans_type', 'action_type'),
        Index('idx_action_plan_sku_status', 'sku', 'status'),
        Index('idx_action_plan_created', 'created_at'),
        {'extend_existing': True},
    )


class ActionOutcome(Base):
    """
    行動結果追蹤（閉環學習核心）。
    """
    __tablename__ = 'action_outcomes'
    __table_args__ = {'extend_existing': True}

    id = Column(Integer, primary_key=True, autoincrement=True)
    plan_id = Column(Integer, ForeignKey('action_plans.id'), nullable=False)
    metric_type = Column(String(50), nullable=True)      # sales_7d / price_rank / conversion
    before_val = Column(Float)
    after_val = Column(Float)
    measured_at = Column(DateTime)
    verdict = Column(String(20))                         # effective / neutral / backfired
    created_at = Column(DateTime, default=datetime.now)

    plan = relationship("ActionPlan", backref="outcomes")


class AgentStrategyWeights(Base):
    """
    Agent strategy weights (OpenClaw learning accumulation).
    Index: strategy_key for fast updates/query.
    """
    __tablename__ = 'agent_strategy_weights'

    id = Column(Integer, primary_key=True, autoincrement=True)
    strategy_key = Column(String(100), unique=True, nullable=False)  # e.g. price_cut_when_gap_gt_5pct
    weight = Column(Float, default=1.0)
    success_cnt = Column(Integer, default=0)
    fail_cnt = Column(Integer, default=0)
    updated_at = Column(DateTime, default=datetime.now)

    __table_args__ = (
        Index('idx_strategy_key', 'strategy_key'),
        {'extend_existing': True},
    )


class Incident(Base):
    """
    Incident tracking for AIOps auto-healing.
    """
    __tablename__ = 'incidents'

    id = Column(Integer, primary_key=True, autoincrement=True)
    task_name = Column(String(100), nullable=False)
    error_type = Column(String(50), nullable=False)
    error_message = Column(Text, nullable=False)
    error_traceback = Column(Text)
    traceback_str = Column(Text)
    severity = Column(String(20), default='medium')
    status = Column(String(20), default='open')  # open/healing/closed/escalated
    retry_count = Column(Integer, default=0)
    playbook_id = Column(Integer, ForeignKey('playbooks.id'), nullable=True)
    matched_playbook_id = Column(Integer, ForeignKey('playbooks.id'), nullable=True)
    resolved_at = Column(DateTime, nullable=True)
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now)

    # Relationship
    playbook = relationship("Playbook", foreign_keys=[matched_playbook_id], backref="incidents")


class Playbook(Base):
    """
    Playbook definitions for auto-healing actions.
    """
    __tablename__ = 'playbooks'

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(100), nullable=False)
    description = Column(Text)
    error_type = Column(String(50), nullable=False)
    match_pattern = Column(Text)  # JSON array of patterns
    action_type = Column(String(50), nullable=False)  # DOCKER_RESTART/SSH_CMD/ALERT_ONLY/WAIT_RETRY
    action_params = Column(Text)  # JSON params
    max_retries = Column(Integer, default=3)
    cooldown_min = Column(Integer, default=30)
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now)

    def get_match_patterns(self):
        """Parse match_pattern JSON to list"""
        if self.match_pattern:
            try:
                import json
                return json.loads(self.match_pattern)
            except:
                return []
        return []

    def get_action_params(self):
        """Parse action_params JSON to dict"""
        if self.action_params:
            try:
                import json
                return json.loads(self.action_params)
            except:
                return {}
        return {}


class HealLog(Base):
    """
    Healing execution logs.
    """
    __tablename__ = 'heal_logs'

    id = Column(Integer, primary_key=True, autoincrement=True)
    incident_id = Column(Integer, ForeignKey('incidents.id'), nullable=False)
    playbook_id = Column(Integer, ForeignKey('playbooks.id'), nullable=False)
    action_type = Column(String(50), nullable=False)
    action_detail = Column(Text)
    result = Column(String(20), default='unknown')  # success/failed/skipped
    result_output = Column(Text)
    duration_ms = Column(Float)
    created_at = Column(DateTime, default=datetime.now)

    # Relationships
    incident = relationship("Incident", backref="heal_logs")
    playbook = relationship("Playbook", backref="heal_logs")


# Seed playbooks for common issues
SEED_PLAYBOOKS = [
    {
        'name': 'Database Connection Recovery',
        'error_type': 'database',
        'match_pattern': '["connection", "timeout", "unreachable"]',
        'action_type': 'WAIT_RETRY',
        'action_params': '{"wait_minutes": 5}',
        'max_retries': 3,
        'cooldown_min': 15
    },
    {
        'name': 'Disk Space Alert',
        'error_type': 'disk_space',
        'match_pattern': '["disk", "space", "full", "no space"]',
        'action_type': 'ALERT_ONLY',
        'action_params': '{"message": "Disk space critical - manual intervention required"}',
        'max_retries': 1,
        'cooldown_min': 60
    }
]
