# src/paper/paper_runner.py
from typing import Dict
import pandas as pd

from src.core.strategy import Signal
from src.core.trade import TradeType
from src.paper.broker import PaperBroker
from src.paper.state_store import StateStore
from src.risk.sizing.percent_risk import PercentRiskSizer
from src.risk.stops.trailing_stop import TrailingStop
from src.strategies.base import Strategy

class PaperRunner:
    """
    Ejecuta estrategias en modo incremental.

    ⚠️ Solo ejecuta trades cuando is_live=True
    """

    def __init__(
        self,
        symbol: str,
        strategies: Dict[str, Strategy],
        broker: PaperBroker,
        store: StateStore,
        risk_sizers: Dict[str, PercentRiskSizer],
        stop: TrailingStop,
        lookback: int = 500,
    ):
        self.symbol = symbol
        self.strategies = strategies
        self.broker = broker
        self.store = store
        self.risk_sizers = risk_sizers
        self.stop = stop
        self.lookback = lookback

    # --------------------------------------------------

    def on_new_candle(self, *, df_buffer: pd.DataFrame, is_live: bool):
        if len(df_buffer) < self.lookback:
            return

        if not is_live:
            return  # 🔒 BOOTSTRAP → NO TRADING

        last_idx = len(df_buffer) - 1
        last_price = float(df_buffer.iloc[last_idx]["close"])

        # Mark-to-market
        self.broker.update_price(self.symbol, last_price)

        for name, strategy in self.strategies.items():
            strategy.set_data(df_buffer)
            signal = strategy.generate_signal(last_idx)

            if signal is None or signal == Signal.HOLD:
                continue

            self._handle_signal(
                strategy_name=name,
                signal=signal,
                price=last_price,
                risk_sizer=self.risk_sizers[name],
                data=df_buffer,
                idx=last_idx,
            )

    # --------------------------------------------------

    def _handle_signal(
        self,
        strategy_name: str,
        signal: Signal,
        price: float,
        risk_sizer: PercentRiskSizer,
        data: pd.DataFrame,
        idx: int,
    ):
        position_id = f"{self.symbol}::{strategy_name}"
        pos = self.broker.get_position(position_id, symbol=self.symbol)

        # BUY
        if signal == Signal.BUY and not pos.is_open():
            capital = self.broker.get_equity()

            stop_price = self.stop.get_stop_price(
                data=data,
                idx=idx,
                entry_price=price,
                trade_type=TradeType.LONG,
            )

            qty = risk_sizer.calculate_size(
                capital=capital,
                entry_price=price,
                stop_price=stop_price,
                max_capital=self.broker.cash,
            )

            if qty <= 0:
                return

            trade = self.broker.place_market_order(
                position_id=position_id,
                symbol=self.symbol,
                side="BUY",
                qty=qty,
                price=price,
                meta={
                    "strategy": strategy_name,
                    "stop_price": stop_price,
                },
                allow_partial=True,
            )

            self.store.append_trade(trade.__dict__)

        # SELL
        elif signal == Signal.SELL and pos.is_open():
            trade = self.broker.place_market_order(
                position_id=position_id,
                symbol=self.symbol,
                side="SELL",
                qty=pos.qty,
                price=price,
                meta={"strategy": strategy_name},
            )

            self.store.append_trade(trade.__dict__)
