"""
Universal DPO Interface - Problem-specific configurations for DPO optimizer.
Provides SOTA hyperparameter tuning for different problem domains.
Uses core DPO algorithm from optimizer.py
"""

import numpy as np
import logging
from typing import Dict, Optional, Any

from .config import DPO_Config
from .optimizer import DPO_NAS
from .problem import Problem, ContinuousOptimizationProblem
from ..evaluation.ensemble import EnsembleEstimator, ProblemBasedEstimator
from ..constraints.handler import AdvancedConstraintHandler
from ..utils.logger import get_logger


# =============================================================================
# SOTA Problem-Specific Configurations
# =============================================================================

class DPO_Presets:
    """
    State-of-the-art hyperparameter configurations for different problem domains.
    Tuned for SOTA performance across NAS, resource allocation, pathfinding, HPO, scheduling.
    """
    
    @staticmethod
    def NAS_Config(
        population_size: int = 60,
        max_iterations: int = 250,
        aggressive_mode: bool = False
    ) -> DPO_Config:
        """
        Neural Architecture Search (SOTA Configuration) - UPGRADED WITH SOTA TECHNIQUES.
        
        SOTA Improvements Integrated:
        - NSGA-II Pareto ranking for multi-objective survival
        - Momentum-accelerated repayment (Nesterov-style)
        - Objective-aware debt (accuracy vs cost debt)
        - Hybrid discrete mutation (categorical + Gaussian)
        - Island specialization (accuracy/cost/balanced)
        - Population-based annealing (per-island temperatures)
        - Local elite micro-search for basin exploitation
        - Age-based regularized evolution
        - Late-phase ruthless greedy (>75% iterations)
        - Orthogonal debt vectors for diverse exploration
        
        Optimized for:
        - High-dimensional discrete search spaces (10^100+)
        - Multi-objective: high accuracy + low cost
        - Fast convergence with strong exploration-exploitation balance
        - CIFAR-10, CIFAR-100, ImageNet, NAS-Bench variants
        """
        if aggressive_mode:
            return DPO_Config(
                population_size=population_size,
                max_iterations=max_iterations,
                num_workers=4,
                
                # SOTA Debt Dynamics: INCREASED for stronger exploitation
                # Higher beta/gamma = stronger repayment and overshoot
                alpha_0=0.22,       # Reduced: less noise in early phase for better AUC
                beta_0=1.7,         # SOTA UPGRADE: +0.2 for stronger convergence exploitation
                gamma_0=1.3,        # SOTA UPGRADE: +0.1 for bigger overshoot jumps
                delta_0=0.55,       # AUC FIX: stronger global pull → faster early convergence
                
                decay_power=0.5,
                
                # SOTA Simplified Debt Memory: Momentum-like accumulation
                debt_memory_lambda=0.82,        # Simplified: fast decay for momentum
                debt_persistence_start=0.85,
                debt_persistence_end=0.50,
                debt_persistence_decay='exponential',
                min_debt_memory=0.65,
                max_debt_memory=0.92,
                
                repayment_cap_early=0.6,
                repayment_cap_mid=1.2,
                repayment_cap_late=2.0,
                
                adaptive_alpha=True,
                adaptive_beta=True,
                adaptive_patience=True,
                adaptive_acceptance_scaling=True,
                
                # SOTA Island Specialization: 3-way speciation with INCREASED preservation
                elite_ratio=0.25,   # CONVERGENCE UPGRADE: aggressive elite preservation for final exploitation
                diversity_inject_freq=5,
                island_model=True,           # CRITICAL for SOTA
                num_islands=3,               # 3 specialized islands: accuracy/cost/balanced
                migration_freq=8,            # AUC FIX: faster cross-island sharing of good solutions
                min_diversity_threshold=0.05,
                adaptive_mutation=True,
                
                # SOTA Population-Based Annealing: Per-island temps
                temperature_start=0.7,       # AUC FIX: lower start → less early bad-solution acceptance
                temperature_min=0.01,
                temperature_decay=0.955,
                acceptance_scaling_factor=1.1,
                
                stagnation_threshold=15,
                stagnation_exploration_boost=1.6,
                stagnation_debt_injection=0.15,
                min_debt_for_exploration=0.05,
                
                force_late_debt=True,
                late_debt_start_ratio=0.70,
                late_debt_epsilon=0.08,
                late_phase_exploration_boost=1.25,
                
                exploration_phase_ratio=0.10,  # AUC FIX: start exploiting much sooner
                debt_accumulation_phase=0.45,  # AUC FIX: enter convergence mode earlier
                
                convergence_threshold=1e-5,
                convergence_window=25,
                patience=30,
                adaptive_early_stop=True,
                
                # SOTA Fitness Weights: Accuracy-dominant for NAS
                w_accuracy=0.95,    # PROVEN BEST for NAS
                w_cost=0.04,        # Multi-objective Pareto balancing
                w_penalty=0.01,
                w_loss=0.0,         # Use accuracy-aware fitness, NOT loss
                
                latency_constraint=100.0,
                memory_constraint=50.0,
                flops_constraint=300.0,
                constraint_penalty_scale=1.5,
                
                eval_strategy='ensemble',  # Ensemble for noise reduction
                cache_evaluations=True,
                use_gpu_eval=True,
                fitness_mode='scalar',     # Scalar fitness + Pareto survival separate
                pareto_archive_size=60,
                verbose=True
            )
        else:
            # Standard mode: More balanced, less aggressive (but still with exploitation boost)
            return DPO_Config(
                population_size=population_size,
                max_iterations=max_iterations,
                num_workers=4,
                
                # SOTA Debt Dynamics - UPGRADED with increased exploitation
                alpha_0=0.20,       # AUC FIX: less noise early
                beta_0=1.65,        # Raised for stronger basin convergence
                gamma_0=1.20,
                delta_0=0.50,       # AUC FIX: stronger global pull → faster early convergence
                
                decay_power=0.55,
                
                debt_memory_lambda=0.84,
                debt_persistence_start=0.87,
                debt_persistence_end=0.55,
                debt_persistence_decay='cosine',
                min_debt_memory=0.68,
                max_debt_memory=0.94,
                
                repayment_cap_early=0.65,
                repayment_cap_mid=1.15,
                repayment_cap_late=1.85,
                
                adaptive_alpha=True,
                adaptive_beta=True,
                adaptive_patience=True,
                adaptive_acceptance_scaling=True,
                
                # SOTA Island Specialization - UPGRADED
                elite_ratio=0.20,   # Raised to match aggressive-mode preservation
                diversity_inject_freq=5,
                island_model=True,
                num_islands=3,
                migration_freq=8,   # AUC FIX: fast early cross-island sharing
                min_diversity_threshold=0.05,
                adaptive_mutation=True,
                
                # SOTA Population-Based Annealing
                temperature_start=0.7,       # AUC FIX: lower start → faster early exploitation
                temperature_min=0.02,
                temperature_decay=0.955,
                acceptance_scaling_factor=1.08,
                
                stagnation_threshold=12,
                stagnation_exploration_boost=1.5,
                stagnation_debt_injection=0.14,
                min_debt_for_exploration=0.05,
                
                force_late_debt=True,
                late_debt_start_ratio=0.68,
                late_debt_epsilon=0.09,
                late_phase_exploration_boost=1.22,
                
                exploration_phase_ratio=0.10,   # AUC FIX: very short exploration window
                debt_accumulation_phase=0.42,   # AUC FIX: enter convergence mode much earlier
                
                convergence_threshold=1e-5,
                convergence_window=22,
                patience=28,
                adaptive_early_stop=True,
                
                # SOTA Accuracy-Dominant Fitness
                w_accuracy=0.95,    # Keep proven best
                w_cost=0.04,
                w_penalty=0.01,
                w_loss=0.0,
                
                latency_constraint=100.0,
                memory_constraint=50.0,
                flops_constraint=300.0,
                constraint_penalty_scale=1.6,
                
                eval_strategy='ensemble',
                cache_evaluations=True,
                use_gpu_eval=True,
                fitness_mode='scalar',
                pareto_archive_size=50,
                verbose=True
            )
    
    @staticmethod
    def ResourceAllocation_Config(
        population_size: int = 50,
        max_iterations: int = 150,
        num_resources: int = 100
    ) -> DPO_Config:
        """
        Resource Allocation/Load Balancing (SOTA Configuration).
        
        Optimized for:
        - Constraint-heavy optimization
        - Continuous decision variables
        - Load balancing and fairness optimization
        
        Applications:
        - Cloud resource allocation
        - Data center scheduling
        - Network traffic optimization
        """
        return DPO_Config(
            population_size=population_size,
            max_iterations=max_iterations,
            num_workers=4,
            
            # Precise allocation: lower exploration
            alpha_0=0.12,
            beta_0=1.3,
            gamma_0=0.6,
            delta_0=0.30,
            
            decay_power=0.6,
            
            debt_memory_lambda=0.90,
            debt_persistence_start=0.95,
            debt_persistence_end=0.70,
            debt_persistence_decay='linear',
            min_debt_memory=0.75,
            max_debt_memory=0.98,
            
            repayment_cap_early=0.5,
            repayment_cap_mid=0.9,
            repayment_cap_late=1.5,
            
            adaptive_alpha=True,
            adaptive_beta=True,
            adaptive_patience=True,
            adaptive_acceptance_scaling=True,
            
            elite_ratio=0.15,
            diversity_inject_freq=8,
            island_model=True,
            num_islands=4,
            migration_freq=12,
            min_diversity_threshold=0.04,
            adaptive_mutation=True,
            
            temperature_start=0.8,
            temperature_min=0.01,
            temperature_decay=0.94,
            acceptance_scaling_factor=1.2,
            
            stagnation_threshold=25,
            stagnation_exploration_boost=1.2,
            stagnation_debt_injection=0.10,
            min_debt_for_exploration=0.04,
            
            force_late_debt=False,
            late_debt_start_ratio=0.80,
            late_debt_epsilon=0.05,
            late_phase_exploration_boost=1.1,
            
            exploration_phase_ratio=0.30,
            debt_accumulation_phase=0.60,
            
            convergence_threshold=1e-6,
            convergence_window=30,
            patience=35,
            adaptive_early_stop=True,
            
            w_accuracy=0.5,
            w_cost=0.2,
            w_penalty=0.3,
            w_loss=0.0,
            
            latency_constraint=100.0,
            memory_constraint=50.0,
            flops_constraint=300.0,
            constraint_penalty_scale=3.0,
            
            eval_strategy='ensemble',
            cache_evaluations=True,
            use_gpu_eval=False,
            fitness_mode='scalar',
            pareto_archive_size=30,
            verbose=True
        )
    
    @staticmethod
    def Pathfinding_Config(
        population_size: int = 60,
        max_iterations: int = 100,
        grid_size: int = 100
    ) -> DPO_Config:
        """
        Pathfinding/Routing/TSP (SOTA Configuration).
        
        Optimized for:
        - Combinatorial optimization
        - Graph-based problems
        - Path quality vs length tradeoff
        
        Applications:
        - Traveling Salesman Problem (TSP)
        - Vehicle Routing Problem (VRP)
        - Motion planning in robotics
        """
        return DPO_Config(
            population_size=population_size,
            max_iterations=max_iterations,
            num_workers=4,
            
            # High exploration for discrete space
            alpha_0=0.25,
            beta_0=0.9,
            gamma_0=1.2,
            delta_0=0.15,
            
            decay_power=0.4,
            
            debt_memory_lambda=0.80,
            debt_persistence_start=0.85,
            debt_persistence_end=0.50,
            debt_persistence_decay='exponential',
            min_debt_memory=0.65,
            max_debt_memory=0.92,
            
            repayment_cap_early=0.7,
            repayment_cap_mid=1.1,
            repayment_cap_late=1.6,
            
            adaptive_alpha=True,
            adaptive_beta=True,
            adaptive_patience=True,
            adaptive_acceptance_scaling=True,
            
            elite_ratio=0.08,
            diversity_inject_freq=4,
            island_model=True,
            num_islands=5,
            migration_freq=8,
            min_diversity_threshold=0.06,
            adaptive_mutation=True,
            
            temperature_start=1.5,
            temperature_min=0.03,
            temperature_decay=0.97,
            acceptance_scaling_factor=0.8,
            
            stagnation_threshold=12,
            stagnation_exploration_boost=1.6,
            stagnation_debt_injection=0.18,
            min_debt_for_exploration=0.06,
            
            force_late_debt=True,
            late_debt_start_ratio=0.60,
            late_debt_epsilon=0.12,
            late_phase_exploration_boost=1.4,
            
            exploration_phase_ratio=0.35,
            debt_accumulation_phase=0.60,
            
            convergence_threshold=1e-4,
            convergence_window=15,
            patience=20,
            adaptive_early_stop=True,
            
            w_accuracy=0.7,
            w_cost=0.25,
            w_penalty=0.05,
            w_loss=0.0,
            
            latency_constraint=1000.0,
            memory_constraint=500.0,
            flops_constraint=5000.0,
            constraint_penalty_scale=1.5,
            
            eval_strategy='ensemble',
            cache_evaluations=True,
            use_gpu_eval=False,
            fitness_mode='scalar',
            pareto_archive_size=40,
            verbose=True
        )
    
    @staticmethod
    def HyperparameterTuning_Config(
        population_size: int = 30,
        max_iterations: int = 100,
        num_params: int = 10
    ) -> DPO_Config:
        """
        Hyperparameter Optimization (SOTA Configuration).
        
        Optimized for:
        - Continuous optimization
        - Noisy objective functions
        - Sample efficiency
        
        Applications:
        - ML hyperparameter tuning
        - AutoML optimization
        - Expensive black-box optimization
        """
        return DPO_Config(
            population_size=population_size,
            max_iterations=max_iterations,
            num_workers=4,
            
            alpha_0=0.18,
            beta_0=1.0,
            gamma_0=0.5,
            delta_0=0.45,
            
            decay_power=0.55,
            
            debt_memory_lambda=0.84,
            debt_persistence_start=0.90,
            debt_persistence_end=0.65,
            debt_persistence_decay='cosine',
            min_debt_memory=0.72,
            max_debt_memory=0.96,
            
            repayment_cap_early=0.65,
            repayment_cap_mid=1.05,
            repayment_cap_late=1.7,
            
            adaptive_alpha=True,
            adaptive_beta=True,
            adaptive_patience=True,
            adaptive_acceptance_scaling=True,
            
            elite_ratio=0.12,
            diversity_inject_freq=6,
            island_model=False,
            num_islands=1,
            migration_freq=15,
            min_diversity_threshold=0.045,
            adaptive_mutation=True,
            
            temperature_start=1.15,
            temperature_min=0.015,
            temperature_decay=0.955,
            acceptance_scaling_factor=1.1,
            
            stagnation_threshold=18,
            stagnation_exploration_boost=1.35,
            stagnation_debt_injection=0.13,
            min_debt_for_exploration=0.045,
            
            force_late_debt=True,
            late_debt_start_ratio=0.68,
            late_debt_epsilon=0.09,
            late_phase_exploration_boost=1.25,
            
            exploration_phase_ratio=0.20,
            debt_accumulation_phase=0.48,
            
            convergence_threshold=1e-5,
            convergence_window=22,
            patience=28,
            adaptive_early_stop=True,
            
            # Continuous HPO is a single-objective problem in this benchmark.
            # Use raw objective/loss directly instead of NAS-style accuracy+cost.
            w_accuracy=0.0,
            w_cost=0.0,
            w_penalty=0.0,
            w_loss=1.0,
            w_latency=0.0,
            w_memory=0.0,
            w_flops=0.0,
            
            latency_constraint=1000.0,
            memory_constraint=1000.0,
            flops_constraint=10000.0,
            constraint_penalty_scale=0.0,
            
            eval_strategy='ensemble',
            cache_evaluations=True,
            use_gpu_eval=True,
            fitness_mode='scalar',
            pareto_archive_size=25,
            continuous_mode=True,
            verbose=True
        )

    @staticmethod
    def ContinuousAnalytic_Config(
        population_size: int = 30,
        max_iterations: int = 100,
        num_params: int = 20
    ) -> DPO_Config:
        """
        Continuous Analytic / Synthetic Benchmark Configuration.

        Tuned for smooth and multimodal analytic functions (Ackley, Rastrigin,
        Schwefel, Lévy, Rosenbrock, Griewank) in ℝ^D.  Key differences from
        HyperparameterTuning_Config:

        - **Balanced overshoot** (gamma_0 = 0.5): directed search via debt
          repayment with moderate overshoot for exploitation.
        - **Balanced alpha** (0.15): adequate exploration noise.
        - **Balanced global pull** (delta_0 = 0.40): convergence toward
          running best without over-constraining search.
        - **Short exploration phase** (0.05): start exploitation almost
          immediately — analytic functions have no warm-up cost.
        - **Single island** (island_model = False): avoids migration overhead
          for low-D continuous problems; simpler exploitation.
        - **continuous_mode = True**: signals optimizer to use clean 4-step
          DPO (debt→repay→double pay→smart learning) with full evaluation.
        """
        return DPO_Config(
            population_size=population_size,
            max_iterations=max_iterations,
            num_workers=1,

            # Balanced exploration-exploitation for continuous DPO
            alpha_0=0.15,
            beta_0=1.0,
            gamma_0=0.5,           # Debt overshoot for directed search
            delta_0=0.40,          # Balanced global-best pull

            decay_power=0.5,

            debt_memory_lambda=0.85,
            debt_persistence_start=0.88,
            debt_persistence_end=0.60,
            debt_persistence_decay='cosine',
            min_debt_memory=0.70,
            max_debt_memory=0.95,

            repayment_cap_early=0.4,
            repayment_cap_mid=0.8,
            repayment_cap_late=1.2,

            adaptive_alpha=True,
            adaptive_beta=True,
            adaptive_patience=True,
            adaptive_acceptance_scaling=True,

            # Single island — no migration overhead for analytic functions
            elite_ratio=0.20,
            diversity_inject_freq=8,
            island_model=False,
            num_islands=1,
            migration_freq=999,
            min_diversity_threshold=0.03,
            adaptive_mutation=True,

            # Aggressive convergence: low start temp, fast decay
            temperature_start=1.2,
            temperature_min=0.01,
            temperature_decay=0.96,
            acceptance_scaling_factor=1.05,

            stagnation_threshold=10,
            stagnation_exploration_boost=1.5,
            stagnation_debt_injection=0.10,
            min_debt_for_exploration=0.03,

            force_late_debt=False,
            late_debt_start_ratio=0.70,
            late_debt_epsilon=0.05,
            late_phase_exploration_boost=1.1,

            # Very short exploration — exploit from iteration 5 onwards
            exploration_phase_ratio=0.05,
            debt_accumulation_phase=0.30,

            convergence_threshold=1e-7,
            convergence_window=15,
            patience=20,
            adaptive_early_stop=True,

            # Pure loss minimisation — no NAS cost/penalty terms
            w_accuracy=0.0,
            w_cost=0.0,
            w_penalty=0.0,
            w_loss=1.0,

            latency_constraint=1e9,
            memory_constraint=1e9,
            flops_constraint=1e9,
            constraint_penalty_scale=0.0,

            eval_strategy='ensemble',
            cache_evaluations=False,
            use_gpu_eval=False,
            fitness_mode='scalar',
            pareto_archive_size=10,

            # Signal to optimizer: skip pareto-rank noise, lazy repayment
            continuous_mode=True,

            verbose=False
        )

    @staticmethod
    def Scheduling_Config(
        population_size: int = 45,
        max_iterations: int = 120,
        num_jobs: int = 50
    ) -> DPO_Config:
        """
        Job Scheduling/Factory Scheduling (SOTA Configuration).
        
        Optimized for:
        - Discrete job assignments
        - Time-based constraints
        - Makespan minimization
        
        Applications:
        - Manufacturing job scheduling
        - Batch job submission
        - Facility scheduling
        """
        return DPO_Config(
            population_size=population_size,
            max_iterations=max_iterations,
            num_workers=4,
            
            alpha_0=0.22,
            beta_0=1.15,
            gamma_0=1.0,
            delta_0=0.22,
            
            decay_power=0.52,
            
            debt_memory_lambda=0.83,
            debt_persistence_start=0.88,
            debt_persistence_end=0.58,
            debt_persistence_decay='linear',
            min_debt_memory=0.68,
            max_debt_memory=0.94,
            
            repayment_cap_early=0.68,
            repayment_cap_mid=1.08,
            repayment_cap_late=1.65,
            
            adaptive_alpha=True,
            adaptive_beta=True,
            adaptive_patience=True,
            adaptive_acceptance_scaling=True,
            
            elite_ratio=0.11,
            diversity_inject_freq=5,
            island_model=True,
            num_islands=4,
            migration_freq=9,
            min_diversity_threshold=0.048,
            adaptive_mutation=True,
            
            temperature_start=1.1,
            temperature_min=0.018,
            temperature_decay=0.955,
            acceptance_scaling_factor=0.95,
            
            stagnation_threshold=16,
            stagnation_exploration_boost=1.4,
            stagnation_debt_injection=0.14,
            min_debt_for_exploration=0.048,
            
            force_late_debt=True,
            late_debt_start_ratio=0.66,
            late_debt_epsilon=0.095,
            late_phase_exploration_boost=1.28,
            
            exploration_phase_ratio=0.32,
            debt_accumulation_phase=0.62,
            
            convergence_threshold=5e-5,
            convergence_window=20,
            patience=26,
            adaptive_early_stop=True,
            
            w_accuracy=0.55,
            w_cost=0.35,
            w_penalty=0.10,
            w_loss=0.0,
            
            latency_constraint=500.0,
            memory_constraint=300.0,
            flops_constraint=2000.0,
            constraint_penalty_scale=2.2,
            
            eval_strategy='ensemble',
            cache_evaluations=True,
            use_gpu_eval=False,
            fitness_mode='scalar',
            pareto_archive_size=35,
            verbose=True
        )


# =============================================================================
# Universal DPO Interface
# =============================================================================

class DPO_Universal:
    """
    Universal interface for DPO optimization across different problem domains.
    Uses core DPO algorithm from optimizer.py with SOTA presets for each domain.
    
    Supported problem types:
    - NAS (Neural Architecture Search)
    - Resource Allocation
    - Pathfinding/Routing/TSP
    - Hyperparameter Tuning (HPO)
    - Job Scheduling
    """
    
    def __init__(self,
                 problem: Optional[Problem] = None,
                 config: Optional[DPO_Config] = None,
                 preset: Optional[str] = None,
                 logger: Optional[logging.Logger] = None,
                 **kwargs):
        """
        Initialize universal DPO optimizer.
        
        Args:
            problem: Problem instance (optional for standalone use)
            config: Custom DPO configuration (overrides preset)
            preset: Preset name ('nas', 'resource', 'pathfinding', 'hpo', 'scheduling')
            logger: Optional logger
            **kwargs: Additional arguments for preset configuration
        """
        self.problem = problem
        self.logger = logger or get_logger('DPO-Universal', True)
        
        # Auto-detect problem type if no preset specified
        if config is None and preset is None and problem is not None:
            preset = self._auto_detect_preset(problem)
            self.logger.info(f"Auto-detected problem type: {preset}")
        
        # Get configuration
        if config is not None:
            self.config = config
        elif preset is not None:
            self.config = self._get_preset_config(preset, **kwargs)
        else:
            self.config = DPO_Config()
        
        # Validate configuration
        self.config.validate()

        # If the problem provides constraints, align config limits
        if self.problem is not None and hasattr(self.problem, 'get_constraints'):
            constraints = self.problem.get_constraints() or {}
            if 'latency' in constraints:
                self.config.latency_constraint = float(constraints['latency'][0])
            if 'memory' in constraints:
                self.config.memory_constraint = float(constraints['memory'][0])
            if 'flops' in constraints:
                self.config.flops_constraint = float(constraints['flops'][0])
        
        # Initialize optimizer (core algorithm)
        estimator = None
        if self.problem is not None:
            if isinstance(self.problem, ContinuousOptimizationProblem):
                # ── Continuous-optimisation mode ──────────────────────────────
                # DPO must call the *real* objective, not the NAS surrogate.
                bounds_low  = [lo for lo, _  in self.problem.param_bounds]
                bounds_high = [hi for _,  hi in self.problem.param_bounds]
                estimator = ProblemBasedEstimator(
                    problem     = self.problem,
                    param_names = self.problem.param_names,
                    bounds_low  = bounds_low,
                    bounds_high = bounds_high,
                )
                # Switch the config so DPO minimises the raw problem fitness
                # directly (w_loss = 1), ignoring NAS-specific cost terms.
                self.config.continuous_mode          = True
                self.config.n_continuous_params      = len(self.problem.param_names)
                self.config.w_loss                   = 1.0
                self.config.w_accuracy               = 0.0
                self.config.w_cost                   = 0.0
                self.config.w_penalty                = 0.0
                self.config.w_latency                = 0.0
                self.config.w_memory                 = 0.0
                self.config.w_flops                  = 0.0
                self.config.constraint_penalty_scale = 0.0
                self.logger.info(
                    "Continuous optimisation mode activated – "
                    f"{len(self.problem.param_names)} parameters, "
                    "ProblemBasedEstimator wired up."
                )
            else:
                evaluator = getattr(self.problem, 'evaluator', None)
                if evaluator is not None and hasattr(evaluator, 'estimate'):
                    estimator = evaluator
        self.optimizer = DPO_NAS(
            config=self.config,
            estimator=estimator or EnsembleEstimator(use_cache=self.config.cache_evaluations),
            constraint_handler=AdvancedConstraintHandler(self.config),
            logger=self.logger
        )
    
    def _auto_detect_preset(self, problem: Problem) -> str:
        """Auto-detect appropriate preset from problem type."""
        problem_info = problem.get_problem_info()
        problem_type = problem_info.get('type', '').lower()
        problem_name = problem_info.get('name', '').lower()
        
        if problem_type == 'nas' or 'architecture' in problem_name:
            return 'nas'
        elif problem_type == 'resource' or 'allocation' in problem_name:
            return 'resource'
        elif problem_type == 'pathfinding' or 'routing' in problem_name or 'path' in problem_name or 'tsp' in problem_name:
            return 'pathfinding'
        elif problem_type == 'hpo' or 'hyperparameter' in problem_name or 'tuning' in problem_name:
            return 'hpo'
        elif problem_type == 'scheduling' or 'schedule' in problem_name or 'job' in problem_name:
            return 'scheduling'
        else:
            self.logger.warning(f"Unknown problem type '{problem_type}', using NAS preset")
            return 'nas'
    
    def _get_preset_config(self, preset: str, **kwargs) -> DPO_Config:
        """Get preset configuration by name."""
        preset = preset.lower().strip()
        
        if preset in ['nas', 'neural_architecture_search', 'architecture']:
            return DPO_Presets.NAS_Config(**kwargs)
        elif preset in ['resource', 'resource_allocation', 'allocation']:
            return DPO_Presets.ResourceAllocation_Config(**kwargs)
        elif preset in ['pathfinding', 'routing', 'path', 'tsp', 'vrp']:
            return DPO_Presets.Pathfinding_Config(**kwargs)
        elif preset in ['hpo', 'hyperparameter', 'tuning', 'hyperparameter_tuning']:
            return DPO_Presets.HyperparameterTuning_Config(**kwargs)
        elif preset in ['scheduling', 'job_scheduling', 'schedule']:
            return DPO_Presets.Scheduling_Config(**kwargs)
        elif preset in ['synthetic', 'analytic', 'continuous_analytic', 'continuousanalytic']:
            return DPO_Presets.ContinuousAnalytic_Config(**kwargs)
        else:
            raise ValueError(
                f"Unknown preset: '{preset}'\n"
                f"Available presets:\n"
                f"  - 'nas' (Neural Architecture Search)\n"
                f"  - 'resource' (Resource Allocation)\n"
                f"  - 'pathfinding' (Pathfinding/Routing/TSP)\n"
                f"  - 'hpo' (Hyperparameter Optimization)\n"
                f"  - 'scheduling' (Job Scheduling)\n"
                f"  - 'synthetic' (Continuous Analytic / Synthetic Benchmarks)"
            )
    
    def optimize(self) -> Dict[str, Any]:
        """Run optimization using core DPO algorithm."""
        if self.problem:
            info = self.problem.get_problem_info()
            problem_name = info.get('name', 'UnknownProblem')
            problem_type = info.get('type', 'unknown')
            self.logger.info("="*70)
            self.logger.info("DPO Universal Optimizer")
            self.logger.info(f"Problem: {problem_name}")
            self.logger.info(f"Type: {problem_type}")
            self.logger.info(f"Configuration: {self._get_preset_name()}")
            self.logger.info("="*70)
        
        return self.optimizer.optimize()
    
    def _get_preset_name(self) -> str:
        """Get the name of the currently active preset."""
        # Try to infer from config values
        if self.config.island_model and self.config.num_islands == 3:
            return "NAS"
        elif self.config.num_islands == 4:
            return "Resource Allocation"
        elif self.config.num_islands == 5:
            return "Pathfinding"
        elif self.config.num_islands == 1:
            return "Hyperparameter Tuning"
        else:
            return "Custom"
    
    def get_best_solution(self):
        """Get best solution found."""
        if self.optimizer.best_agent:
            return self.optimizer.best_agent.gene.to_architecture_dict()
        return None
    
    def get_history(self) -> Dict:
        """Get optimization history."""
        return self.optimizer.history
    
    def get_config(self) -> DPO_Config:
        """Get current configuration."""
        return self.config
