"""
Rollback Manager.
[AC-AISVC-RES-07] 策略回退与审计管理器。
"""

import logging
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any

from app.services.retrieval.strategy.config import RetrievalStrategyConfig, StrategyType

logger = logging.getLogger(__name__)


class RollbackTrigger(str, Enum):
    """回退触发原因。"""
    MANUAL = "manual"
    ERROR = "error"
    PERFORMANCE = "performance"
    TIMEOUT = "timeout"


@dataclass
class AuditLog:
    """审计日志记录。"""
    timestamp: str
    action: str
    from_strategy: str
    to_strategy: str
    trigger: str
    reason: str
    tenant_id: str | None = None
    details: dict[str, Any] = field(default_factory=dict)


@dataclass
class RollbackResult:
    """回退结果。"""
    success: bool
    previous_strategy: StrategyType
    current_strategy: StrategyType
    trigger: RollbackTrigger
    reason: str
    audit_log: AuditLog | None = None


class RollbackManager:
    """
    策略回退管理器。【AC-AISVC-RES-07】
    
    职责：
    1. 策略异常时回退到默认策略
    2. 记录审计日志
    3. 支持手动触发回退
    """
    
    def __init__(
        self,
        config: RetrievalStrategyConfig | None = None,
        max_audit_logs: int = 1000,
    ):
        self._config = config or RetrievalStrategyConfig()
        self._max_audit_logs = max_audit_logs
        self._audit_logs: list[AuditLog] = []
        self._previous_strategy: StrategyType = StrategyType.DEFAULT
    
    def rollback(
        self,
        trigger: RollbackTrigger,
        reason: str,
        tenant_id: str | None = None,
        details: dict[str, Any] | None = None,
    ) -> RollbackResult:
        """执行策略回退。【AC-AISVC-RES-07】"""
        previous = self._config.active_strategy
        current = StrategyType.DEFAULT
        
        if previous == StrategyType.DEFAULT:
            return RollbackResult(
                success=False,
                previous_strategy=previous,
                current_strategy=current,
                trigger=trigger,
                reason="Already on default strategy",
            )
        
        self._previous_strategy = previous
        self._config.active_strategy = current
        
        audit_log = AuditLog(
            timestamp=datetime.utcnow().isoformat(),
            action="rollback",
            from_strategy=previous.value,
            to_strategy=current.value,
            trigger=trigger.value,
            reason=reason,
            tenant_id=tenant_id,
            details=details or {},
        )
        
        self._add_audit_log(audit_log)
        
        logger.info(
            f"[RollbackManager] Rollback executed: from={previous.value}, "
            f"to={current.value}, trigger={trigger.value}"
        )
        
        return RollbackResult(
            success=True,
            previous_strategy=previous,
            current_strategy=current,
            trigger=trigger,
            reason=reason,
            audit_log=audit_log,
        )
    
    def check_and_rollback(
        self, metrics: dict[str, float], tenant_id: str | None = None
    ) -> RollbackResult | None:
        """检查性能指标并自动回退。【AC-AISVC-RES-08】"""
        thresholds = self._config.performance_thresholds
        
        latency = metrics.get("latency_ms", 0)
        if latency > thresholds.get("max_latency_ms", 2000):
            return self.rollback(
                trigger=RollbackTrigger.PERFORMANCE,
                reason=f"Latency {latency}ms exceeds threshold",
                tenant_id=tenant_id,
            )
        
        error_rate = metrics.get("error_rate", 0)
        if error_rate > thresholds.get("max_error_rate", 0.05):
            return self.rollback(
                trigger=RollbackTrigger.ERROR,
                reason=f"Error rate {error_rate} exceeds threshold",
                tenant_id=tenant_id,
            )
        
        return None
    
    def _add_audit_log(self, log: AuditLog) -> None:
        self._audit_logs.append(log)
        if len(self._audit_logs) > self._max_audit_logs:
            self._audit_logs = self._audit_logs[-self._max_audit_logs:]
    
    def record_audit(
        self,
        action: str,
        details: dict[str, Any],
        tenant_id: str | None = None,
    ) -> AuditLog:
        """记录审计日志。"""
        audit_log = AuditLog(
            timestamp=datetime.utcnow().isoformat(),
            action=action,
            from_strategy=self._config.active_strategy.value,
            to_strategy=self._config.active_strategy.value,
            trigger="n/a",
            reason=details.get("reason", ""),
            tenant_id=tenant_id,
            details=details,
        )
        
        self._add_audit_log(audit_log)
        
        logger.info(
            f"[RollbackManager] Audit recorded: action={action}, "
            f"strategy={self._config.active_strategy.value}"
        )
        
        return audit_log
    
    def get_audit_logs(self, limit: int = 100) -> list[AuditLog]:
        return self._audit_logs[-limit:]
    
    def get_config(self) -> RetrievalStrategyConfig:
        return self._config
    
    def update_config(self, config: RetrievalStrategyConfig) -> None:
        self._config = config


_rollback_manager: RollbackManager | None = None


def get_rollback_manager() -> RollbackManager:
    global _rollback_manager
    if _rollback_manager is None:
        _rollback_manager = RollbackManager()
    return _rollback_manager
