import os
import sys
from pathlib import Path
from datetime import datetime, timedelta
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from dotenv import load_dotenv

# --------------------------------------------------
# Path setup
# --------------------------------------------------
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from src.utils.logger import log
from src.data.storage import StorageManager
from src.core.engine import Engine
from src.strategies import MovingAverageCrossover
from src.risk.sizing.percent_risk import PercentRiskSizer
from src.risk.stops.fixed_stop import FixedStop
from src.risk.stops.trailing_stop import TrailingStop
from src.risk.stops.atr_stop import ATRStop

# --------------------------------------------------
# CONFIG
# --------------------------------------------------
SYMBOL = "BTC/USDT"
TIMEFRAME = "1h"

TRAIN_DAYS = 120
TEST_DAYS = 30
STEP_DAYS = 30

INITIAL_CAPITAL = 10_000
COMMISSION = 0.001
SLIPPAGE = 0.0005

RISK_FRACTION = 0.01

OUT_DIR = Path("scripts/research/output/wf_stops") / f"{SYMBOL.replace('/', '_')}_{TIMEFRAME}"
OUT_DIR.mkdir(parents=True, exist_ok=True)

STOPS = {
    "Fixed 2%": FixedStop(0.02),
    "Trailing 2%": TrailingStop(0.02),
    "ATR 14 x 2.0": ATRStop(14, 2.0),
}

# --------------------------------------------------
# Helpers
# --------------------------------------------------
def make_strategy():
    return MovingAverageCrossover(
        fast_period=10,
        slow_period=30,
        ma_type="ema",
        use_adx=False,
        adx_threshold=20.0,
    )


def setup_env():
    env_path = Path(__file__).parent.parent.parent / "config" / "secrets.env"
    load_dotenv(env_path)


def load_data():
    setup_env()

    storage = StorageManager(
        db_host=os.getenv("DB_HOST"),
        db_port=int(os.getenv("DB_PORT", 5432)),
        db_name=os.getenv("DB_NAME"),
        db_user=os.getenv("DB_USER"),
        db_password=os.getenv("DB_PASSWORD"),
    )

    data = storage.load_ohlcv(
        symbol=SYMBOL,
        timeframe=TIMEFRAME,
        use_cache=True,
    )

    storage.close()

    if data.empty:
        raise RuntimeError("No data loaded")

    return data


# --------------------------------------------------
# Walk Forward
# --------------------------------------------------
def run():
    log.info("=" * 80)
    log.info("🔁 WALK-FORWARD – STOP COMPARISON (120/30/30, 1h)")
    log.info("=" * 80)

    data = load_data()

    wf_results = []
    equity_curves = {name: [] for name in STOPS.keys()}

    start_time = data.index[0]
    end_time = data.index[-1]

    window_id = 0
    current_train_start = start_time

    while True:
        train_end = current_train_start + timedelta(days=TRAIN_DAYS)
        test_start = train_end
        test_end = test_start + timedelta(days=TEST_DAYS)

        if test_end > end_time:
            break

        train_df = data.loc[current_train_start:train_end]
        test_df = data.loc[test_start:test_end]

        if len(test_df) < 50:
            break

        window_id += 1

        print()
        print(
            f"WF Window {window_id:02d} | "
            f"TRAIN {train_df.index[0].date()} → {train_df.index[-1].date()} | "
            f"TEST {test_df.index[0].date()} → {test_df.index[-1].date()} | "
            f"bars_test={len(test_df)}"
        )

        for stop_name, stop in STOPS.items():
            engine = Engine(
                strategy=make_strategy(),
                initial_capital=INITIAL_CAPITAL,
                commission=COMMISSION,
                slippage=SLIPPAGE,
                position_sizer=PercentRiskSizer(RISK_FRACTION),
                stop_loss=stop,
            )

            res = engine.run(test_df)

            wf_results.append({
                "window": window_id,
                "stop": stop_name,
                "train_start": train_df.index[0],
                "train_end": train_df.index[-1],
                "test_start": test_df.index[0],
                "test_end": test_df.index[-1],
                "trades": res["total_trades"],
                "max_dd_pct": res["max_drawdown_pct"],
                "return_pct": res["total_return_pct"],
                "final_equity": res["final_equity"],
            })

            equity_curves[stop_name].append(
                pd.Series(res["equity_curve"], index=res["timestamps"])
            )

            print(
                f"  {stop_name:<13} | "
                f"Trades: {res['total_trades']:>3} | "
                f"MaxDD: {res['max_drawdown_pct']:>7.2f}% | "
                f"Return: {res['total_return_pct']:>7.2f}%"
            )

        current_train_start += timedelta(days=STEP_DAYS)

    # --------------------------------------------------
    # Save results
    # --------------------------------------------------
    df = pd.DataFrame(wf_results)
    df.to_csv(OUT_DIR / "wf_results.csv", index=False)

    print()
    print("=" * 80)
    print("📊 WF SUMMARY (aggregated)")
    print("=" * 80)

    summary = (
        df.groupby("stop")
        .agg(
            windows=("window", "nunique"),
            trades_avg=("trades", "mean"),
            max_dd_worst=("max_dd_pct", "min"),
            return_mean=("return_pct", "mean"),
            return_median=("return_pct", "median"),
        )
        .round(2)
    )

    print(summary)
    print("=" * 80)

    # --------------------------------------------------
    # Plot equity curves (visual comparison)
    # --------------------------------------------------
    plt.figure(figsize=(14, 7))

    for stop_name, curves in equity_curves.items():
        if not curves:
            continue
        concat_curve = pd.concat(curves)
        plt.plot(concat_curve.index, concat_curve.values, label=stop_name)

    plt.title(f"WF Equity Comparison – {SYMBOL} {TIMEFRAME}")
    plt.xlabel("Time")
    plt.ylabel("Equity (per-window)")
    plt.legend()
    plt.grid(alpha=0.3)
    plt.tight_layout()

    plt.savefig(OUT_DIR / "wf_equity_comparison.png")
    plt.close()


if __name__ == "__main__":
    run()
