"""
Wrapped Custom Algorithm: MyOptimizer
Contributed by: TestContributor
Email: contributor@test.com
Date: 2026-04-02T01:27:01.053280

Auto-generated wrapper that adapts the custom algorithm to BaseOptimizer interface.
Original algorithm parameters are automatically mapped to standard MHA parameters.
"""

from mha_toolbox.base import BaseOptimizer
import numpy as np
import importlib.util
import os

# ============================================================
# ORIGINAL ALGORITHM CODE (preserved unchanged)
# ============================================================

import numpy as np

class MyOptimizer:
    def __init__(self, A=30, B=100, C=10):
        self.A = A
        self.B = B
        self.C = C
    
    def optimize(self, fitness_func, bounds=None):
        pop = np.random.uniform(-100, 100, (self.A, self.C))
        fitness = np.array([fitness_func(x) for x in pop])
        best = pop[0].copy()
        best_fit = fitness[0]
        history = [best_fit]
        
        for t in range(self.B):
            for i in range(self.A):
                new_pos = pop[i] + np.random.randn(self.C)
                new_fit = fitness_func(new_pos)
                if new_fit < fitness[i]:
                    pop[i] = new_pos
                    fitness[i] = new_fit
                    if new_fit < best_fit:
                        best = new_pos.copy()
                        best_fit = new_fit
            history.append(best_fit)
        
        return best, best_fit, history, None, None


# ============================================================  
# WRAPPED ADAPTER CLASS
# ============================================================
class MyOptimizerWrapped(BaseOptimizer):
    """
    MyOptimizer - Wrapped for MHA Flow compatibility.
    
    Contributed by: TestContributor
    
    Parameter Mapping:
        max_iterations -> A
        dimensions -> C
    """
    
    CONTRIBUTOR = {
        "author": "TestContributor",
        "email": "contributor@test.com",
        "date": "2026-04-02T01:27:01.053280",
        "original_class": "MyOptimizer"
    }
    
    def __init__(self, population_size=30, max_iterations=100, **kwargs):
        super().__init__(population_size=population_size, 
                        max_iterations=max_iterations, **kwargs)
        self.algorithm_name_ = "MyOptimizer"

        # Create the original algorithm instance with mapped parameters
        original_kwargs = {}
        original_kwargs['A'] = self.max_iterations_
        original_kwargs['C'] = self.dimensions_

        # Pass remaining kwargs (skip standard MHA params already handled by BaseOptimizer)
        _STANDARD_PARAMS = {'population_size', 'max_iterations', 'dimensions',
                            'lower_bound', 'upper_bound', 'verbose', 'mode'}
        for k, v in kwargs.items():
            if k not in original_kwargs and k not in _STANDARD_PARAMS:
                original_kwargs[k] = v
        
        try:
            self._original_algo = MyOptimizer(**original_kwargs)
        except TypeError:
            # Fallback: try with only recognized params
            self._original_algo = MyOptimizer(**{k: v for k, v in original_kwargs.items() 
                                                    if v is not None})

    def _parse_result(self, result):
        """Normalize algorithm result to 5-tuple."""
        if isinstance(result, tuple) and len(result) >= 5:
            return result
        elif isinstance(result, tuple) and len(result) >= 2:
            best_sol, best_fit = result[0], result[1]
            gf = result[2] if len(result) > 2 else [best_fit]
            lf = result[3] if len(result) > 3 else None  
            lp = result[4] if len(result) > 4 else None
            return best_sol, best_fit, gf, lf, lp
        elif hasattr(result, 'best_solution_'):
            return (result.best_solution_, result.best_fitness_, 
                    result.global_fitness_, 
                    getattr(result, 'local_fitness_', None),
                    getattr(result, 'local_positions_', None))
        else:
            raise TypeError(f"Unexpected result type: {type(result)}")

    def _optimize(self, objective_function, X=None, y=None, **kwargs):
        """Run the original algorithm's optimization with mapped parameters."""
        algo = self._original_algo
        
        # Update bounds/dims on the original if they were set later
        for attr in ['population_size', 'max_iterations', 'dimensions',
                     'lower_bound', 'upper_bound']:
            std_val = getattr(self, attr + '_', None)
            if std_val is not None:
                if attr == 'max_iterations':
                    try:
                        setattr(algo, 'A', std_val)
                    except AttributeError:
                        pass
                if attr == 'dimensions':
                    try:
                        setattr(algo, 'C', std_val)
                    except AttributeError:
                        pass

        # Try different calling conventions (most permissive first)
        signatures = [
            lambda: algo.optimize(objective_function),
            lambda: algo.optimize(objective_function, X=X, y=y, **kwargs),
            lambda: algo.optimize(objective_function,
                                  bounds=(self.lower_bound_, self.upper_bound_),
                                  dimension=self.dimensions_),
            lambda: algo.optimize(objective_function, **kwargs),
        ]
        
        last_err = None
        for sig in signatures:
            try:
                result = sig()
                return self._parse_result(result)
            except TypeError as e:
                last_err = e
                continue
        raise TypeError(f"Could not call original algorithm optimize(): {last_err}")
