"""Built-in backtest integration for the Autopilot deploy pipeline."""

from __future__ import annotations

import logging
import math
import random
from dataclasses import dataclass
from typing import Any, Callable

logger = logging.getLogger("horizon.fund.backtest_runner")


@dataclass(frozen=True)
class SyntheticTick:
    """A single tick of synthetic price data."""
    timestamp: int
    price: float
    bid: float
    ask: float
    volume: float


class BacktestRunner:
    """Runs backtests for the Autopilot deploy pipeline.

    Generates synthetic prediction-market price data based on the
    candidate's edge estimate, runs the pipeline through horizon's
    backtest engine, and returns structured results suitable for
    Autopilot.evaluate().
    """

    def __init__(
        self,
        default_ticks: int = 500,
        default_initial_capital: float = 1_000.0,
        default_spread: float = 0.02,
    ) -> None:
        self._default_ticks = default_ticks
        self._default_capital = default_initial_capital
        self._default_spread = default_spread

    def run(self, candidate: Any) -> Any:
        """Run a backtest on a deploy candidate.

        Args:
            candidate: A DeployCandidate with pipeline and market_id.

        Returns:
            BacktestResult from horizon.backtest.
        """
        if candidate.pipeline is None:
            raise ValueError(f"Candidate {candidate.market_id} has no pipeline")

        from horizon.backtest import backtest

        ticks = self._generate_price_series(
            edge=candidate.edge_estimate,
            n_ticks=self._default_ticks,
            spread=self._default_spread,
        )

        name = f"auto_{candidate.strategy_type}_{candidate.market_id[:20]}"

        result = backtest(
            name=name,
            markets=[candidate.market_id],
            data=ticks,
            pipeline=candidate.pipeline,
            initial_capital=self._default_capital,
        )

        return result

    def run_robustness(self, result: Any) -> Any:
        """Run a robustness test on a backtest result.

        Args:
            result: BacktestResult from a previous run().

        Returns:
            RobustnessReport from horizon.robustness.
        """
        from horizon.robustness import robustness_test

        return robustness_test(result, n_simulations=200)

    def as_backtest_fn(self) -> Callable:
        """Return a callable matching Autopilot.evaluate(backtest_fn=...) signature."""
        return self.run

    def as_robustness_fn(self) -> Callable:
        """Return a callable matching Autopilot.evaluate(robustness_fn=...) signature."""
        return self.run_robustness

    @staticmethod
    def _generate_price_series(
        edge: float,
        n_ticks: int,
        spread: float = 0.02,
    ) -> list[dict[str, Any]]:
        """Generate synthetic prediction-market price data.

        Creates a bounded random walk in [0.02, 0.98] with a slight
        drift proportional to the edge estimate. Suitable for testing
        prediction market strategies.

        Args:
            edge: Expected edge (positive = market underpriced).
            n_ticks: Number of ticks to generate.
            spread: Bid-ask spread width.

        Returns:
            List of dicts with timestamp, price, bid, ask, volume keys.
        """
        price = 0.50
        half_spread = spread / 2.0
        drift = max(-0.001, min(0.001, edge * 0.01))  # Scale edge to small drift
        vol = 0.02  # Per-tick volatility

        ticks: list[dict[str, Any]] = []
        for i in range(n_ticks):
            # Random walk with drift
            price += drift + vol * random.gauss(0, 1)
            price = max(0.02, min(0.98, price))

            volume = max(1.0, 100.0 + random.gauss(0, 30))

            ticks.append({
                "timestamp": i,
                "price": round(price, 4),
                "bid": round(max(0.01, price - half_spread), 4),
                "ask": round(min(0.99, price + half_spread), 4),
                "volume": round(volume, 1),
            })

        return ticks
