"""
Self-Improving Systems for Toxo.

This module implements autonomous self-optimization, meta-learning,
and continuous improvement capabilities.
"""

import asyncio
import numpy as np
from typing import Dict, Any, List, Optional, Tuple, Union, Callable
from dataclasses import dataclass, field
from datetime import datetime, timedelta
import json
import statistics
from pathlib import Path

from ..core.config import ToxoConfig, TrainingConfig
from ..utils.logger import get_logger
from ..utils.exceptions import ToxoError


@dataclass
class PerformanceMetric:
    """A performance metric measurement."""
    name: str
    value: float
    timestamp: datetime
    context: Dict[str, Any] = field(default_factory=dict)
    source: str = "unknown"
    confidence: float = 1.0


@dataclass
class ImprovementStrategy:
    """A strategy for improving system performance."""
    name: str
    description: str
    target_metrics: List[str]
    implementation: Callable
    priority: float = 1.0
    success_rate: float = 0.0
    last_applied: Optional[datetime] = None
    metadata: Dict[str, Any] = field(default_factory=dict)


@dataclass
class OptimizationGoal:
    """An optimization goal with target metrics."""
    name: str
    target_metric: str
    target_value: float
    current_value: float = 0.0
    importance: float = 1.0
    deadline: Optional[datetime] = None
    strategy_preferences: List[str] = field(default_factory=list)


class PerformanceMonitor:
    """
    Monitors system performance across multiple dimensions.
    
    Tracks metrics like accuracy, latency, user satisfaction,
    and identifies performance trends and anomalies.
    """
    
    def __init__(self, config: ToxoConfig):
        """Initialize performance monitor."""
        self.config = config
        self.logger = get_logger("toxo.performance_monitor")
        
        # Metric storage
        self.metrics_history: Dict[str, List[PerformanceMetric]] = {}
        self.trend_analyzers: Dict[str, 'TrendAnalyzer'] = {}
        self.anomaly_detectors: Dict[str, 'AnomalyDetector'] = {}
        
        # Performance baselines
        self.baselines: Dict[str, float] = {}
        self.targets: Dict[str, float] = {}
        
        # Monitoring configuration
        self.monitoring_window = timedelta(hours=24)
        self.trend_window = timedelta(hours=6)
        self.anomaly_threshold = 2.0  # Standard deviations
        
        self.logger.info("Performance monitor initialized")
    
    def record_metric(
        self,
        name: str,
        value: float,
        context: Optional[Dict[str, Any]] = None,
        source: str = "system"
    ) -> None:
        """Record a performance metric."""
        metric = PerformanceMetric(
            name=name,
            value=value,
            timestamp=datetime.now(),
            context=context or {},
            source=source
        )
        
        if name not in self.metrics_history:
            self.metrics_history[name] = []
        
        self.metrics_history[name].append(metric)
        
        # Cleanup old metrics
        self._cleanup_old_metrics(name)
        
        # Update trend analyzer
        if name not in self.trend_analyzers:
            self.trend_analyzers[name] = TrendAnalyzer(name)
        self.trend_analyzers[name].add_point(value, metric.timestamp)
        
        # Check for anomalies
        if name not in self.anomaly_detectors:
            self.anomaly_detectors[name] = AnomalyDetector(name)
        anomaly_score = self.anomaly_detectors[name].check_anomaly(value)
        
        if anomaly_score > self.anomaly_threshold:
            self.logger.warning(
                f"Anomaly detected in {name}: value={value:.4f}, "
                f"score={anomaly_score:.2f}"
            )
    
    def get_current_performance(self) -> Dict[str, Any]:
        """Get current performance summary."""
        summary = {}
        
        for metric_name, metrics in self.metrics_history.items():
            if not metrics:
                continue
            
            recent_metrics = [
                m for m in metrics 
                if datetime.now() - m.timestamp <= timedelta(minutes=30)
            ]
            
            if recent_metrics:
                values = [m.value for m in recent_metrics]
                summary[metric_name] = {
                    "current": values[-1],
                    "avg_30min": statistics.mean(values),
                    "trend": self.trend_analyzers[metric_name].get_trend(),
                    "anomaly_score": self.anomaly_detectors[metric_name].get_current_score()
                }
        
        return summary
    
    def analyze_performance_gaps(self) -> List[Dict[str, Any]]:
        """Analyze performance gaps and identify improvement opportunities."""
        gaps = []
        
        for metric_name, target in self.targets.items():
            if metric_name in self.metrics_history:
                recent_metrics = self._get_recent_metrics(metric_name, timedelta(hours=1))
                if recent_metrics:
                    current_avg = statistics.mean([m.value for m in recent_metrics])
                    
                    if current_avg < target:
                        gap = target - current_avg
                        gaps.append({
                            "metric": metric_name,
                            "current": current_avg,
                            "target": target,
                            "gap": gap,
                            "gap_percentage": (gap / target) * 100,
                            "trend": self.trend_analyzers[metric_name].get_trend()
                        })
        
        # Sort by gap percentage (descending)
        gaps.sort(key=lambda x: x["gap_percentage"], reverse=True)
        return gaps
    
    def _cleanup_old_metrics(self, metric_name: str) -> None:
        """Remove metrics older than monitoring window."""
        cutoff_time = datetime.now() - self.monitoring_window
        self.metrics_history[metric_name] = [
            m for m in self.metrics_history[metric_name]
            if m.timestamp > cutoff_time
        ]
    
    def _get_recent_metrics(
        self, 
        metric_name: str, 
        window: timedelta
    ) -> List[PerformanceMetric]:
        """Get metrics within specified time window."""
        if metric_name not in self.metrics_history:
            return []
        
        cutoff_time = datetime.now() - window
        return [
            m for m in self.metrics_history[metric_name]
            if m.timestamp > cutoff_time
        ]


class TrendAnalyzer:
    """Analyzes trends in performance metrics."""
    
    def __init__(self, metric_name: str):
        """Initialize trend analyzer."""
        self.metric_name = metric_name
        self.data_points: List[Tuple[datetime, float]] = []
        self.max_points = 100
    
    def add_point(self, value: float, timestamp: datetime) -> None:
        """Add a data point."""
        self.data_points.append((timestamp, value))
        
        # Keep only recent points
        if len(self.data_points) > self.max_points:
            self.data_points = self.data_points[-self.max_points:]
    
    def get_trend(self) -> Dict[str, Any]:
        """Calculate trend information."""
        if len(self.data_points) < 2:
            return {"direction": "unknown", "strength": 0.0, "slope": 0.0}
        
        # Simple linear regression for trend
        x_values = [(t - self.data_points[0][0]).total_seconds() for t, _ in self.data_points]
        y_values = [v for _, v in self.data_points]
        
        n = len(x_values)
        x_mean = statistics.mean(x_values)
        y_mean = statistics.mean(y_values)
        
        # Calculate slope
        numerator = sum((x_values[i] - x_mean) * (y_values[i] - y_mean) for i in range(n))
        denominator = sum((x_values[i] - x_mean) ** 2 for i in range(n))
        
        slope = numerator / denominator if denominator != 0 else 0.0
        
        # Determine direction and strength
        if abs(slope) < 1e-6:
            direction = "stable"
            strength = 0.0
        elif slope > 0:
            direction = "increasing"
            strength = min(abs(slope) * 1000, 1.0)  # Normalize
        else:
            direction = "decreasing"
            strength = min(abs(slope) * 1000, 1.0)
        
        return {
            "direction": direction,
            "strength": strength,
            "slope": slope,
            "correlation": self._calculate_correlation(x_values, y_values)
        }
    
    def _calculate_correlation(self, x_values: List[float], y_values: List[float]) -> float:
        """Calculate correlation coefficient."""
        if len(x_values) < 2:
            return 0.0
        
        x_mean = statistics.mean(x_values)
        y_mean = statistics.mean(y_values)
        
        numerator = sum((x_values[i] - x_mean) * (y_values[i] - y_mean) for i in range(len(x_values)))
        x_variance = sum((x - x_mean) ** 2 for x in x_values)
        y_variance = sum((y - y_mean) ** 2 for y in y_values)
        
        denominator = (x_variance * y_variance) ** 0.5
        
        return numerator / denominator if denominator != 0 else 0.0


class AnomalyDetector:
    """Detects anomalies in performance metrics using statistical methods."""
    
    def __init__(self, metric_name: str):
        """Initialize anomaly detector."""
        self.metric_name = metric_name
        self.values: List[float] = []
        self.max_history = 50
        self.current_score = 0.0
    
    def check_anomaly(self, value: float) -> float:
        """Check if value is anomalous. Returns anomaly score (z-score)."""
        self.values.append(value)
        
        # Keep only recent values
        if len(self.values) > self.max_history:
            self.values = self.values[-self.max_history:]
        
        if len(self.values) < 3:
            self.current_score = 0.0
            return 0.0
        
        # Calculate z-score
        mean_val = statistics.mean(self.values[:-1])  # Exclude current value
        std_val = statistics.stdev(self.values[:-1]) if len(self.values) > 2 else 1.0
        
        z_score = abs(value - mean_val) / std_val if std_val > 0 else 0.0
        self.current_score = z_score
        
        return z_score
    
    def get_current_score(self) -> float:
        """Get current anomaly score."""
        return self.current_score
    
    def get_state(self) -> Dict[str, Any]:
        """Get the current state for serialization."""
        return {
            "config_available": self.config is not None,
            "metrics_count": len(getattr(self, 'metrics', {})),
            "performance_history_count": len(getattr(self, 'performance_history', [])),
            "current_score": getattr(self, 'current_score', 0.0),
            "system_type": "PerformanceMonitor"
        }


class StrategyEngine:
    """
    Engine for managing and applying improvement strategies.
    
    Maintains a catalog of improvement strategies and selects
    the best strategies based on current performance gaps.
    """
    
    def __init__(self, config: ToxoConfig):
        """Initialize strategy engine."""
        self.config = config
        self.logger = get_logger("toxo.strategy_engine")
        
        # Strategy catalog
        self.strategies: Dict[str, ImprovementStrategy] = {}
        self.strategy_history: List[Dict[str, Any]] = []
        
        # Strategy effectiveness tracking
        self.effectiveness_tracker = {}
        
        # Initialize built-in strategies
        self._initialize_builtin_strategies()
        
        self.logger.info("Strategy engine initialized")
    
    def _initialize_builtin_strategies(self) -> None:
        """Initialize built-in improvement strategies."""
        
        # Hyperparameter tuning strategy
        self.register_strategy(ImprovementStrategy(
            name="hyperparameter_tuning",
            description="Optimize learning rate, batch size, and other hyperparameters",
            target_metrics=["accuracy", "loss", "convergence_speed"],
            implementation=self._hyperparameter_tuning_strategy,
            priority=0.8
        ))
        
        # Prompt optimization strategy
        self.register_strategy(ImprovementStrategy(
            name="prompt_optimization",
            description="Refine and optimize prompt templates",
            target_metrics=["response_quality", "task_completion"],
            implementation=self._prompt_optimization_strategy,
            priority=0.9
        ))
        
        # Memory management strategy
        self.register_strategy(ImprovementStrategy(
            name="memory_optimization",
            description="Optimize memory usage and retrieval",
            target_metrics=["memory_efficiency", "retrieval_accuracy"],
            implementation=self._memory_optimization_strategy,
            priority=0.7
        ))
        
        # Data quality improvement strategy
        self.register_strategy(ImprovementStrategy(
            name="data_quality_improvement",
            description="Enhance training data quality and diversity",
            target_metrics=["training_effectiveness", "generalization"],
            implementation=self._data_quality_strategy,
            priority=0.8
        ))
        
        # Response reranking strategy
        self.register_strategy(ImprovementStrategy(
            name="response_reranking_optimization",
            description="Optimize response selection and ranking",
            target_metrics=["response_quality", "user_satisfaction"],
            implementation=self._reranking_optimization_strategy,
            priority=0.6
        ))
    
    def register_strategy(self, strategy: ImprovementStrategy) -> None:
        """Register a new improvement strategy."""
        self.strategies[strategy.name] = strategy
        self.effectiveness_tracker[strategy.name] = {
            "applications": 0,
            "successes": 0,
            "failures": 0,
            "avg_improvement": 0.0
        }
        self.logger.info(f"Registered strategy: {strategy.name}")
    
    def select_strategies(
        self,
        performance_gaps: List[Dict[str, Any]],
        max_strategies: int = 3
    ) -> List[ImprovementStrategy]:
        """Select best strategies for addressing performance gaps."""
        if not performance_gaps:
            return []
        
        # Score strategies based on relevance to current gaps
        strategy_scores = []
        
        for strategy_name, strategy in self.strategies.items():
            score = self._calculate_strategy_score(strategy, performance_gaps)
            strategy_scores.append((score, strategy))
        
        # Sort by score and return top strategies
        strategy_scores.sort(key=lambda x: x[0], reverse=True)
        return [strategy for _, strategy in strategy_scores[:max_strategies]]
    
    def _calculate_strategy_score(
        self,
        strategy: ImprovementStrategy,
        performance_gaps: List[Dict[str, Any]]
    ) -> float:
        """Calculate relevance score for a strategy."""
        base_score = strategy.priority
        
        # Relevance to current gaps
        relevance_score = 0.0
        for gap in performance_gaps:
            if gap["metric"] in strategy.target_metrics:
                relevance_score += gap["gap_percentage"] / 100.0
        
        # Historical effectiveness
        effectiveness = self.effectiveness_tracker[strategy.name]
        if effectiveness["applications"] > 0:
            success_rate = effectiveness["successes"] / effectiveness["applications"]
            effectiveness_score = success_rate * effectiveness["avg_improvement"]
        else:
            effectiveness_score = 0.5  # Neutral for untested strategies
        
        # Recency penalty (prefer strategies not recently applied)
        recency_penalty = 0.0
        if strategy.last_applied:
            time_since = datetime.now() - strategy.last_applied
            if time_since < timedelta(hours=1):
                recency_penalty = 0.5
        
        total_score = (base_score + relevance_score + effectiveness_score) - recency_penalty
        return max(0.0, total_score)
    
    async def apply_strategy(
        self,
        strategy: ImprovementStrategy,
        context: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Apply an improvement strategy."""
        self.logger.info(f"Applying strategy: {strategy.name}")
        
        try:
            # Apply the strategy
            result = await strategy.implementation(context)
            
            # Update strategy metadata
            strategy.last_applied = datetime.now()
            
            # Track application
            self.effectiveness_tracker[strategy.name]["applications"] += 1
            
            # Record in history
            self.strategy_history.append({
                "strategy": strategy.name,
                "timestamp": datetime.now(),
                "context": context,
                "result": result,
                "success": result.get("success", False)
            })
            
            if result.get("success", False):
                self.effectiveness_tracker[strategy.name]["successes"] += 1
                improvement = result.get("improvement", 0.0)
                
                # Update average improvement
                tracker = self.effectiveness_tracker[strategy.name]
                current_avg = tracker["avg_improvement"]
                new_avg = (current_avg * (tracker["successes"] - 1) + improvement) / tracker["successes"]
                tracker["avg_improvement"] = new_avg
                
                self.logger.info(f"Strategy {strategy.name} succeeded with improvement: {improvement:.4f}")
            else:
                self.effectiveness_tracker[strategy.name]["failures"] += 1
                self.logger.warning(f"Strategy {strategy.name} failed: {result.get('error', 'Unknown error')}")
            
            return result
            
        except Exception as e:
            self.logger.error(f"Strategy {strategy.name} raised exception: {str(e)}")
            self.effectiveness_tracker[strategy.name]["failures"] += 1
            return {"success": False, "error": str(e)}
    
    async def _hyperparameter_tuning_strategy(self, context: Dict[str, Any]) -> Dict[str, Any]:
        """Hyperparameter tuning strategy implementation."""
        # This would implement actual hyperparameter optimization
        # For now, return a simulated result
        
        current_lr = context.get("learning_rate", 0.01)
        
        # Simulate testing different learning rates
        test_rates = [current_lr * 0.5, current_lr, current_lr * 1.5]
        best_rate = current_lr * 1.2  # Simulated best
        improvement = 0.05  # Simulated improvement
        
        return {
            "success": True,
            "improvement": improvement,
            "changes": {
                "learning_rate": best_rate
            },
            "details": "Optimized learning rate based on recent performance"
        }
    
    async def _prompt_optimization_strategy(self, context: Dict[str, Any]) -> Dict[str, Any]:
        """Prompt optimization strategy implementation."""
        # This would implement actual prompt optimization
        return {
            "success": True,
            "improvement": 0.08,
            "changes": {
                "prompt_template": "optimized_template_v2"
            },
            "details": "Enhanced prompt structure and clarity"
        }
    
    async def _memory_optimization_strategy(self, context: Dict[str, Any]) -> Dict[str, Any]:
        """Memory optimization strategy implementation."""
        return {
            "success": True,
            "improvement": 0.03,
            "changes": {
                "memory_consolidation": "enabled",
                "retrieval_threshold": 0.8
            },
            "details": "Optimized memory consolidation and retrieval thresholds"
        }
    
    async def _data_quality_strategy(self, context: Dict[str, Any]) -> Dict[str, Any]:
        """Data quality improvement strategy implementation."""
        return {
            "success": True,
            "improvement": 0.12,
            "changes": {
                "data_augmentation": "enabled",
                "quality_filtering": "enhanced"
            },
            "details": "Enhanced data quality through augmentation and filtering"
        }
    
    async def _reranking_optimization_strategy(self, context: Dict[str, Any]) -> Dict[str, Any]:
        """Response reranking optimization strategy implementation."""
        return {
            "success": True,
            "improvement": 0.06,
            "changes": {
                "reranking_weights": "optimized",
                "diversity_factor": 0.3
            },
            "details": "Optimized response reranking weights and diversity"
        }


class MetaLearner:
    """
    Meta-learning component that learns how to learn better.
    
    Analyzes learning patterns and adapts the learning process
    to improve efficiency and effectiveness.
    """
    
    def __init__(self, config: ToxoConfig):
        """Initialize meta-learner."""
        self.config = config
        self.logger = get_logger("toxo.meta_learner")
        
        # Learning pattern storage
        self.learning_patterns: List[Dict[str, Any]] = []
        self.adaptation_strategies: Dict[str, Any] = {}
        
        # Meta-learning state
        self.current_learning_profile = {
            "adaptation_speed": 1.0,
            "exploration_rate": 0.1,
            "memory_retention": 0.9,
            "transfer_efficiency": 0.5
        }
        
        self.logger.info("Meta-learner initialized")
    
    def record_learning_episode(
        self,
        task_type: str,
        learning_data: Dict[str, Any],
        performance_data: Dict[str, Any]
    ) -> None:
        """Record a learning episode for analysis."""
        episode = {
            "timestamp": datetime.now(),
            "task_type": task_type,
            "learning_data": learning_data,
            "performance_data": performance_data,
            "learning_profile": self.current_learning_profile.copy()
        }
        
        self.learning_patterns.append(episode)
        
        # Analyze patterns periodically
        if len(self.learning_patterns) % 10 == 0:
            asyncio.create_task(self._analyze_learning_patterns())
    
    async def _analyze_learning_patterns(self) -> None:
        """Analyze learning patterns to identify optimization opportunities."""
        if len(self.learning_patterns) < 5:
            return
        
        self.logger.info("Analyzing learning patterns for meta-learning insights")
        
        # Analyze adaptation speed patterns
        self._analyze_adaptation_speed()
        
        # Analyze task transfer patterns
        self._analyze_transfer_patterns()
        
        # Analyze memory utilization patterns
        self._analyze_memory_patterns()
        
        # Update learning profile based on insights
        self._update_learning_profile()
    
    def _analyze_adaptation_speed(self) -> None:
        """Analyze how quickly the system adapts to new tasks."""
        recent_episodes = self.learning_patterns[-10:]
        
        adaptation_speeds = []
        for episode in recent_episodes:
            convergence_time = episode["learning_data"].get("convergence_time", 0)
            initial_performance = episode["performance_data"].get("initial_accuracy", 0)
            final_performance = episode["performance_data"].get("final_accuracy", 0)
            
            if convergence_time > 0 and final_performance > initial_performance:
                speed = (final_performance - initial_performance) / convergence_time
                adaptation_speeds.append(speed)
        
        if adaptation_speeds:
            avg_speed = statistics.mean(adaptation_speeds)
            self.adaptation_strategies["current_adaptation_speed"] = avg_speed
    
    def _analyze_transfer_patterns(self) -> None:
        """Analyze knowledge transfer effectiveness between tasks."""
        task_groups = {}
        for episode in self.learning_patterns:
            task_type = episode["task_type"]
            if task_type not in task_groups:
                task_groups[task_type] = []
            task_groups[task_type].append(episode)
        
        # Calculate transfer effectiveness between task types
        transfer_matrix = {}
        for task_type, episodes in task_groups.items():
            if len(episodes) > 1:
                improvements = []
                for i in range(1, len(episodes)):
                    prev_performance = episodes[i-1]["performance_data"].get("final_accuracy", 0)
                    curr_initial = episodes[i]["performance_data"].get("initial_accuracy", 0)
                    
                    if prev_performance > 0:
                        transfer_benefit = curr_initial / prev_performance
                        improvements.append(transfer_benefit)
                
                if improvements:
                    transfer_matrix[task_type] = statistics.mean(improvements)
        
        self.adaptation_strategies["transfer_effectiveness"] = transfer_matrix
    
    def _analyze_memory_patterns(self) -> None:
        """Analyze memory usage and retention patterns."""
        memory_utilizations = []
        for episode in self.learning_patterns[-20:]:
            memory_usage = episode["learning_data"].get("memory_usage", 0)
            memory_utilizations.append(memory_usage)
        
        if memory_utilizations:
            avg_utilization = statistics.mean(memory_utilizations)
            self.adaptation_strategies["avg_memory_utilization"] = avg_utilization
    
    def _update_learning_profile(self) -> None:
        """Update the learning profile based on analyzed patterns."""
        # Adjust adaptation speed based on recent performance
        if "current_adaptation_speed" in self.adaptation_strategies:
            speed = self.adaptation_strategies["current_adaptation_speed"]
            if speed > 0.1:  # Fast adaptation
                self.current_learning_profile["exploration_rate"] *= 0.9  # Reduce exploration
            else:  # Slow adaptation
                self.current_learning_profile["exploration_rate"] *= 1.1  # Increase exploration
        
        # Adjust memory retention based on utilization
        if "avg_memory_utilization" in self.adaptation_strategies:
            utilization = self.adaptation_strategies["avg_memory_utilization"]
            if utilization > 0.8:  # High utilization
                self.current_learning_profile["memory_retention"] *= 0.95  # Slightly reduce retention
            elif utilization < 0.3:  # Low utilization
                self.current_learning_profile["memory_retention"] *= 1.05  # Slightly increase retention
        
        # Ensure values stay in reasonable bounds
        self.current_learning_profile["exploration_rate"] = max(0.01, min(0.5, self.current_learning_profile["exploration_rate"]))
        self.current_learning_profile["memory_retention"] = max(0.5, min(1.0, self.current_learning_profile["memory_retention"]))
        
        self.logger.info(f"Updated learning profile: {self.current_learning_profile}")
    
    def get_learning_recommendations(self, task_context: Dict[str, Any]) -> Dict[str, Any]:
        """Get learning recommendations based on meta-learning insights."""
        recommendations = {
            "learning_rate_modifier": 1.0,
            "exploration_bonus": self.current_learning_profile["exploration_rate"],
            "memory_priority": self.current_learning_profile["memory_retention"],
            "transfer_strategy": "adaptive"
        }
        
        # Task-specific recommendations
        task_type = task_context.get("task_type", "general")
        if task_type in self.adaptation_strategies.get("transfer_effectiveness", {}):
            transfer_score = self.adaptation_strategies["transfer_effectiveness"][task_type]
            if transfer_score > 1.2:  # Good transfer
                recommendations["learning_rate_modifier"] = 1.2
                recommendations["transfer_strategy"] = "aggressive"
        
        return recommendations


class SelfImprovementEngine:
    """
    Main self-improvement engine that coordinates all components.
    
    Orchestrates performance monitoring, strategy selection,
    and meta-learning to continuously improve system performance.
    """
    
    def __init__(self, config: ToxoConfig):
        """Initialize self-improvement engine."""
        self.config = config
        self.logger = get_logger("toxo.self_improvement")
        
        # Initialize components
        self.performance_monitor = PerformanceMonitor(config)
        self.strategy_engine = StrategyEngine(config)
        self.meta_learner = MetaLearner(config)
        
        # Improvement state
        self.is_active = False
        self.improvement_cycle_interval = timedelta(hours=1)
        self.last_improvement_cycle = datetime.now()
        
        # Goals and targets
        self.optimization_goals: List[OptimizationGoal] = []
        
        self.logger.info("Self-improvement engine initialized")
    
    def set_performance_targets(self, targets: Dict[str, float]) -> None:
        """Set performance targets for monitoring."""
        self.performance_monitor.targets = targets
        self.logger.info(f"Performance targets set: {targets}")
    
    def add_optimization_goal(self, goal: OptimizationGoal) -> None:
        """Add an optimization goal."""
        self.optimization_goals.append(goal)
        self.logger.info(f"Added optimization goal: {goal.name}")
    
    async def start_continuous_improvement(self) -> None:
        """Start the continuous improvement process."""
        self.is_active = True
        self.logger.info("Starting continuous self-improvement")
        
        while self.is_active:
            try:
                await self._run_improvement_cycle()
                await asyncio.sleep(self.improvement_cycle_interval.total_seconds())
            except Exception as e:
                self.logger.error(f"Improvement cycle error: {str(e)}")
                await asyncio.sleep(60)  # Wait before retrying
    
    def stop_continuous_improvement(self) -> None:
        """Stop the continuous improvement process."""
        self.is_active = False
        self.logger.info("Stopped continuous self-improvement")
    
    async def _run_improvement_cycle(self) -> None:
        """Run a single improvement cycle."""
        self.logger.info("Running improvement cycle")
        
        # 1. Analyze current performance
        current_performance = self.performance_monitor.get_current_performance()
        performance_gaps = self.performance_monitor.analyze_performance_gaps()
        
        # 2. Check if improvement is needed
        if not performance_gaps:
            self.logger.info("No performance gaps detected")
            return
        
        # 3. Select improvement strategies
        strategies = self.strategy_engine.select_strategies(performance_gaps, max_strategies=2)
        
        if not strategies:
            self.logger.info("No suitable strategies found")
            return
        
        # 4. Apply strategies
        improvements_made = []
        for strategy in strategies:
            context = {
                "performance_gaps": performance_gaps,
                "current_performance": current_performance,
                "meta_learning_profile": self.meta_learner.current_learning_profile
            }
            
            result = await self.strategy_engine.apply_strategy(strategy, context)
            
            if result.get("success", False):
                improvements_made.append({
                    "strategy": strategy.name,
                    "improvement": result.get("improvement", 0.0),
                    "changes": result.get("changes", {})
                })
        
        # 5. Update meta-learner
        if improvements_made:
            learning_data = {
                "strategies_applied": [imp["strategy"] for imp in improvements_made],
                "total_improvement": sum(imp["improvement"] for imp in improvements_made)
            }
            
            self.meta_learner.record_learning_episode(
                task_type="self_improvement",
                learning_data=learning_data,
                performance_data=current_performance
            )
        
        self.last_improvement_cycle = datetime.now()
        self.logger.info(f"Improvement cycle complete. Applied {len(improvements_made)} improvements")
    
    def get_improvement_status(self) -> Dict[str, Any]:
        """Get current self-improvement status."""
        return {
            "is_active": self.is_active,
            "last_cycle": self.last_improvement_cycle,
            "performance_summary": self.performance_monitor.get_current_performance(),
            "strategy_effectiveness": self.strategy_engine.effectiveness_tracker,
            "meta_learning_profile": self.meta_learner.current_learning_profile,
            "optimization_goals": [
                {
                    "name": goal.name,
                    "target": goal.target_value,
                    "current": goal.current_value,
                    "progress": (goal.current_value / goal.target_value) * 100 if goal.target_value > 0 else 0
                }
                for goal in self.optimization_goals
            ]
        }
    
    def get_state(self) -> Dict[str, Any]:
        """Get the current state for serialization."""
        return {
            "config_available": self.config is not None,
            "performance_monitor_available": hasattr(self, 'performance_monitor') and self.performance_monitor is not None,
            "strategy_engine_available": hasattr(self, 'strategy_engine') and self.strategy_engine is not None,
            "meta_learner_available": hasattr(self, 'meta_learner') and self.meta_learner is not None,
            "is_active": getattr(self, 'is_active', False),
            "optimization_goals_count": len(getattr(self, 'optimization_goals', [])),
            "system_type": "SelfImprovementEngine"
        } 