# src/paper/loop.py

from datetime import datetime, timezone
import time
import pandas as pd

from src.paper.paper_runner import PaperRunner
from src.paper.broker import PaperBroker
from src.paper.state_store import StateStore
from src.data.storage import StorageManager
from src.utils.logger import log


class PaperTradingLoop:
    """
    Loop principal de paper trading.

    Estados:
    - BOOTSTRAP: carga histórico, indicadores, warm-up (NO trading)
    - LIVE: procesa solo velas nuevas (trading activo)
    """

    def __init__(self):
        self.symbol = "BTC/USDT"
        self.timeframe = "1m"
        self.sleep_seconds = 5

        # Estado y persistencia
        self.store = StateStore(db_path="data/paper_trading/state.db")
        self.storage = StorageManager.from_env()

        # Broker
        self.broker = PaperBroker(initial_cash=10_000)

        # Runner
        self.runner = PaperRunner(
            symbol=self.symbol,
            strategies=self._load_strategies(),
            broker=self.broker,
            store=self.store,
            risk_sizers=self._load_risk(),
            stop=self._load_stop(),
            lookback=500,
        )

        # Estado del loop
        self.is_live = False

    # --------------------------------------------------
    # Loaders
    # --------------------------------------------------

    def _load_strategies(self):
        from src.strategies.moving_average import MovingAverageCrossover
        from src.strategies.trend_filtered import TrendFilteredMACrossover
        from src.strategies.demo_pingpong import DemoPingPongStrategy

        return {
            "demo": DemoPingPongStrategy(period=15),
            "ma_crossover": MovingAverageCrossover(),
            "trend_filtered": TrendFilteredMACrossover(),
        }

    def _load_risk(self):
        from src.risk.sizing.percent_risk import PercentRiskSizer

        return {
            "demo": PercentRiskSizer(risk_fraction=0.1),
            "ma_crossover": PercentRiskSizer(risk_fraction=0.01),
            "trend_filtered": PercentRiskSizer(risk_fraction=0.01),
        }

    def _load_stop(self):
        from src.risk.stops.trailing_stop import TrailingStop

        return TrailingStop(trailing_fraction=0.05)

    def _get_downloader(self):
        from src.data.downloader import OHLCVDownloader

        return OHLCVDownloader(exchange_name="binance")

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

    def run_forever(self):
        log.info("🚀 Paper trading loop iniciado")

        while True:
            try:
                self.run_once()
                time.sleep(self.sleep_seconds)
            except KeyboardInterrupt:
                log.warning("⛔ Paper loop detenido manualmente")
                break
            except Exception:
                log.exception("❌ Paper loop error")
                try:
                    self.store.save_loop_state("ERROR")
                except Exception:
                    pass
                time.sleep(5)

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

    def run_once(self):
        # 1️⃣ Sincronizar OHLCV
        self.storage.sync_ohlcv(
            symbol=self.symbol,
            timeframe=self.timeframe,
            downloader=self._get_downloader(),
        )

        # 2️⃣ Cargar histórico completo (solo contexto)
        df = self.storage.load_ohlcv(
            symbol=self.symbol,
            timeframe=self.timeframe,
        )

        if df is None or df.empty:
            log.warning("Sin datos OHLCV")
            return

        # 3️⃣ Determinar si ya estamos LIVE
        last_candle_ts = df.index[-1].replace(tzinfo=timezone.utc)
        now = datetime.now(timezone.utc)

        timeframe_delta = self.storage._timeframe_delta(self.timeframe)
        expected_last = (
            now.replace(minute=0, second=0, microsecond=0)
            - timeframe_delta
        )

        if not self.is_live:
            if last_candle_ts >= expected_last:
                self.is_live = True
                log.success("🟢 BOT EN MODO LIVE (trading habilitado)")
                self.store.save_loop_state("RUNNING")
            else:
                log.info("⏳ BOOTSTRAP: cargando histórico (no trading)")
                return  # ⛔ NO TRADING EN BOOTSTRAP

        # 4️⃣ LIVE: procesar última vela
        self.runner.on_new_candle(df_buffer=df, is_live=self.is_live)


        # 5️⃣ Persistir estado - Snapshot DESPUÉS del tick
        snapshot = self.broker.snapshot()

        self.store.save_broker_snapshot(snapshot)

        # 🟢 Equity curve (ESTO ES LO CLAVE)
        self.store.append_equity_point(
            ts=datetime.now(timezone.utc),
            equity=snapshot["equity"],
            cash=snapshot["cash"],
        )

