"""Adversarial simulation for strategy robustness testing."""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from typing import Any, Callable

from horizon._horizon import (
    AdversaryType,
    AdversaryConfig,
    AdversaryAction,
    SimulationMetrics,
    AdversarialResult,
    whale_action,
    front_runner_action,
    spoofing_action,
    liquidity_drainer_action,
    compute_simulation_metrics,
    vulnerability_score,
)

logger = logging.getLogger("horizon")

# Preset adversary configurations
WHALE_PRESET = AdversaryConfig(AdversaryType.Whale, "default", intensity=1.0, size_multiplier=5.0)
FRONT_RUNNER_PRESET = AdversaryConfig(AdversaryType.FrontRunner, "default", intensity=1.0, size_multiplier=1.0)
SPOOFING_PRESET = AdversaryConfig(AdversaryType.Spoofing, "default", intensity=1.0, size_multiplier=10.0)
DRAINER_PRESET = AdversaryConfig(AdversaryType.LiquidityDrainer, "default", intensity=1.0, size_multiplier=1.0)


@dataclass
class AdversarialSimConfig:
    """Configuration for adversarial simulation."""
    adversaries: list[AdversaryConfig] = field(default_factory=list)
    num_cycles: int = 100
    seed: int = 42


def adversarial_sim(
    pipeline_factory: Callable,
    data: Any = None,
    adversaries: list[AdversaryConfig] | None = None,
    num_cycles: int = 100,
    seed: int = 42,
) -> AdversarialResult:
    """Run adversarial simulation: baseline vs adversarial.

    Compares strategy performance with and without adversarial agents.
    """
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    advs = adversaries or [WHALE_PRESET]

    # Run baseline
    try:
        from horizon import backtest
        baseline_result = backtest(pipeline_factory({}), data=data)
        baseline_pnls = getattr(baseline_result, "pnl_curve", [0.0] * num_cycles)
        if not isinstance(baseline_pnls, list):
            baseline_pnls = [0.0] * num_cycles
    except Exception as e:
        logger.warning("Baseline backtest failed: %s", e)
        baseline_pnls = [0.0] * num_cycles

    # Run with adversaries (inject random perturbations)
    adversarial_pnls = []
    rng_state = seed
    for i, pnl in enumerate(baseline_pnls):
        # Simulate adversary impact
        impact = 0.0
        for adv in advs:
            rng_state = (rng_state * 6364136223846793005 + 1) & 0xFFFFFFFFFFFFFFFF
            noise = ((rng_state >> 11) / (1 << 53) - 0.5) * adv.intensity * 0.1
            impact += noise
        adversarial_pnls.append(pnl + impact * abs(pnl + 1))

    return compute_simulation_metrics(baseline_pnls, adversarial_pnls)


def anti_fragile(
    pipeline_factory: Callable,
    param_bounds: list[dict[str, Any]],
    adversaries: list[AdversaryConfig] | None = None,
    data: Any = None,
    pop_size: int = 30,
    generations: int = 50,
    seed: int = 42,
) -> dict[str, Any]:
    """Evolutionary optimization for adversarial robustness.

    Wraps evolution with adversarial fitness: optimizes for best
    performance UNDER adversarial conditions.
    """
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    advs = adversaries or [WHALE_PRESET, FRONT_RUNNER_PRESET]

    def adversarial_fitness(result: Any) -> float:
        pnls = getattr(result, "pnl_curve", [0.0])
        if not isinstance(pnls, list) or len(pnls) < 2:
            return float("-inf")

        adv_pnls = []
        rng = seed
        for p in pnls:
            impact = 0.0
            for adv in advs:
                rng = (rng * 6364136223846793005 + 1) & 0xFFFFFFFFFFFFFFFF
                noise = ((rng >> 11) / (1 << 53) - 0.5) * adv.intensity * 0.1
                impact += noise
            adv_pnls.append(p + impact * abs(p + 1))

        total = sum(adv_pnls)
        mean = total / len(adv_pnls)
        var = sum((p - mean) ** 2 for p in adv_pnls) / max(len(adv_pnls) - 1, 1)
        std = var ** 0.5
        return mean / max(std, 1e-10) if std > 0 else mean

    try:
        from horizon.evolve import evolve
        result = evolve(
            data=data,
            pipeline_factory=pipeline_factory,
            param_bounds=param_bounds,
            pop_size=pop_size,
            generations=generations,
            fitness_fn=adversarial_fitness,
            seed=seed,
        )
        return {
            "best_genome": result.best_genome,
            "best_fitness": result.best_fitness,
            "generations": result.generations_run,
        }
    except Exception as e:
        logger.warning("Anti-fragile optimization failed: %s", e)
        return {"best_genome": [], "best_fitness": float("-inf"), "error": str(e)}
