"""Comprehensive test of all 149 registered algorithms"""
import numpy as np
import importlib
import inspect
import sys

from mha_toolbox.complete_algorithm_registry_v2 import AlgorithmRegistry
from mha_toolbox.base import BaseOptimizer

registry = AlgorithmRegistry()
algos = registry.algorithms

# Simple sphere function
def sphere(x):
    return np.sum(np.array(x)**2)


def load_algo_class(name, info):
    """Load algorithm class using same logic as Flask app"""
    file_name = info.get("file", "").replace(".py", "")
    if not file_name:
        return None
    
    if "/" in file_name:
        module_path = f"mha_toolbox.algorithms.{file_name.replace('/', '.')}"
    else:
        module_path = f"mha_toolbox.algorithms.{file_name}"
    
    try:
        module = importlib.import_module(module_path)
    except ModuleNotFoundError:
        category = info.get("category", "")
        if category == "Hybrid" or "hybrid" in file_name.lower():
            module_path = f"mha_toolbox.algorithms.hybrid.{file_name}"
            module = importlib.import_module(module_path)
        else:
            raise
    
    algo_classes = []
    for cname, obj in inspect.getmembers(module, inspect.isclass):
        if obj != BaseOptimizer and issubclass(obj, BaseOptimizer):
            algo_classes.append(obj)
    
    return algo_classes[0] if algo_classes else None


def run_algo(cls, objective_func, pop_size=5, max_iter=3, dims=5, lb=-10, ub=10):
    """Run algorithm handling both new and legacy patterns"""
    # Try standard pattern
    try:
        opt = cls(population_size=pop_size, max_iterations=max_iter)
        opt.dimensions_ = dims
        opt.lower_bound_ = lb
        opt.upper_bound_ = ub
        result = opt.optimize(objective_function=objective_func)
        return result
    except TypeError:
        pass
    
    # Legacy pattern
    bounds = np.array([[lb, ub]] * dims)
    try:
        opt = cls(objective_function=objective_func, dimensions=dims, bounds=bounds,
                  population_size=pop_size, max_iterations=max_iter)
    except TypeError:
        opt = cls(objective_func, dims, bounds, pop_size, max_iter)
    
    result = opt.optimize()
    return result

results = {"pass": [], "fail": [], "no_class": [], "import_fail": []}

for name, info in sorted(algos.items()):
    # Load class
    try:
        cls = load_algo_class(name, info)
    except Exception as e:
        results["import_fail"].append((name, str(e)[:80]))
        continue
    
    if cls is None:
        results["no_class"].append((name, info.get("file", "?")))
        continue
    
    # Run
    try:
        result = run_algo(cls, sphere)
        
        # Check result
        if result is not None:
            if hasattr(result, 'best_fitness_'):
                best_fit = result.best_fitness_
                if isinstance(best_fit, (int, float, np.floating)):
                    results["pass"].append(name)
                else:
                    results["fail"].append((name, f"bad fitness type: {type(best_fit)}"))
            elif isinstance(result, tuple) and len(result) >= 2:
                best_fit = result[1]
                if isinstance(best_fit, (int, float, np.floating)):
                    results["pass"].append(name)
                else:
                    results["fail"].append((name, f"bad fitness type: {type(best_fit)}"))
            else:
                results["fail"].append((name, f"unexpected return: {type(result)}"))
        else:
            results["fail"].append((name, "None result"))
    except Exception as e:
        results["fail"].append((name, str(e)[:100]))

total = len(algos)
p = len(results["pass"])
f = len(results["fail"])
nc = len(results["no_class"])
im = len(results["import_fail"])

print("=" * 60)
print(f"ALGORITHM TEST RESULTS: {p}/{total} PASS")
print("=" * 60)
print(f"  PASS:        {p}")
print(f"  FAIL:        {f}")
print(f"  NO CLASS:    {nc}")
print(f"  IMPORT FAIL: {im}")
print()

if results["fail"]:
    print("--- FAILURES ---")
    for name, err in results["fail"]:
        print(f"  {name}: {err}")
    print()

if results["import_fail"]:
    print("--- IMPORT FAILURES ---")
    for name, err in results["import_fail"]:
        print(f"  {name}: {err}")
    print()

if results["no_class"]:
    print("--- NO CLASS FOUND (override optimize directly) ---")
    for name, path in results["no_class"]:
        print(f"  {name}: {path}")
