#!/usr/bin/env python3
"""Standalone backtest of MACD+RSI Confluence strategy on MOEX data.

Tests IS (2023-2024) and OOS (2024-2025) periods for key tickers.
"""

from __future__ import annotations

import sys
import os
import json
from datetime import datetime

import pandas as pd
import numpy as np
from loguru import logger

# Add project root to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from core.data_loader import DataPreparator
from ai.strategy_signals import get_strategy_signals, backtest_strategy, StrategyConfig


def ts_from_date(date_str: str) -> int:
    """Convert 'YYYY-MM-DD' to unix timestamp."""
    return int(datetime.strptime(date_str, "%Y-%m-%d").timestamp())


def run_backtest(ticker: str, start: str, end: str, label: str) -> dict:
    """Run MACD+RSI backtest for a ticker and period."""
    logger.info(f"\n{'='*60}")
    logger.info(f"{label}: {ticker} {start} → {end}")
    logger.info(f"{'='*60}")
    
    dp = DataPreparator([ticker])
    df = dp.load_h1(ticker, ts_from_date(start), ts_from_date(end))
    
    if df.empty:
        logger.warning(f"  {ticker}: No data loaded")
        return {"ticker": ticker, "label": label, "error": "No data", "total_trades": 0}
    
    logger.info(f"  {ticker}: loaded {len(df)} bars ({df['timestamp'].min()} → {df['timestamp'].max()})")
    
    # Generate signals
    config = StrategyConfig()
    signals_df = get_strategy_signals(df, config)
    
    if signals_df.empty:
        logger.warning(f"  {ticker}: No signals generated")
        return {"ticker": ticker, "label": label, "error": "No signals", "total_trades": 0}
    
    n_signals = int(signals_df["strategy_signal"].sum())
    logger.info(f"  {ticker}: {n_signals} signals ({n_signals/len(df)*100:.1f}% of bars)")
    
    # Run backtest (pass ticker for per-ticker TP)
    results = backtest_strategy(df, signals_df, config, ticker=ticker)
    
    if "error" in results:
        logger.warning(f"  {ticker}: {results['error']}")
    else:
        logger.info(f"  {ticker}: Trades={results['total_trades']}, "
                    f"WR={results['win_rate']}%, PF={results['profit_factor']}, "
                    f"PnL={results['total_pnl']:.0f}, Sharpe={results['sharpe']}")
    
    results["ticker"] = ticker
    results["label"] = label
    results["period"] = f"{start}_{end}"
    return results


def main():
    # Tickers to test (key MOEX tickers)
    tickers = ["SBER", "GAZP", "PLZL", "VTBR", "LKOH", "ROSN", "NVTK", 
               "MTSS", "PHOR", "SNGSP", "ASTR", "X5", "MOEX", "BITCOIN", "EURUSD"]
    
    # Periods
    is_period = ("2023-01-01", "2024-01-01")
    oos_period = ("2024-01-01", "2025-01-01")
    
    all_results = []
    
    # Run IS backtests
    logger.info(f"\n{'#'*60}")
    logger.info(f"IN-SAMPLE: {is_period[0]} → {is_period[1]}")
    logger.info(f"{'#'*60}")
    
    for ticker in tickers:
        result = run_backtest(ticker, is_period[0], is_period[1], "IS")
        all_results.append(result)
    
    # Run OOS backtests
    logger.info(f"\n{'#'*60}")
    logger.info(f"OUT-OF-SAMPLE: {oos_period[0]} → {oos_period[1]}")
    logger.info(f"{'#'*60}")
    
    for ticker in tickers:
        result = run_backtest(ticker, oos_period[0], oos_period[1], "OOS")
        all_results.append(result)
    
    # Print summary table
    print(f"\n{'='*80}")
    print(f"MACD+RSI STRATEGY BACKTEST SUMMARY")
    print(f"{'='*80}")
    print(f"{'Ticker':<8} {'Period':<6} {'Trades':<8} {'WR%':<8} {'PF':<8} {'PnL':<12} {'Sharpe':<8}")
    print(f"{'-'*8} {'-'*6} {'-'*8} {'-'*8} {'-'*8} {'-'*12} {'-'*8}")
    
    is_totals = {"trades": 0, "pnl": 0, "positive": 0}
    oos_totals = {"trades": 0, "pnl": 0, "positive": 0}
    
    for r in all_results:
        ticker = r["ticker"]
        label = r["label"]
        trades = r.get("total_trades", 0)
        wr = r.get("win_rate", 0)
        pf = r.get("profit_factor", 0)
        pnl = r.get("total_pnl", 0)
        sharpe = r.get("sharpe", 0)
        
        if isinstance(trades, int) and trades > 0:
            print(f"{ticker:<8} {label:<6} {trades:<8} {wr:<8} {pf:<8} {pnl:<12,.0f} {sharpe:<8}")
            
            if label == "IS":
                is_totals["trades"] += trades
                is_totals["pnl"] += pnl
                if pnl > 0:
                    is_totals["positive"] += 1
            else:
                oos_totals["trades"] += trades
                oos_totals["pnl"] += pnl
                if pnl > 0:
                    oos_totals["positive"] += 1
        else:
            err = r.get("error", "No trades")
            print(f"{ticker:<8} {label:<6} {'0':<8} {'-':<8} {'-':<8} {f'ERR: {err}':<12} {'-':<8}")
    
    print(f"{'-'*8} {'-'*6} {'-'*8} {'-'*8} {'-'*8} {'-'*12} {'-'*8}")
    is_pos_str = f"{is_totals['positive']}/positive"
    oos_pos_str = f"{oos_totals['positive']}/positive"
    print(f"{'TOTAL':<8} {'IS':<6} {is_totals['trades']:<8} {'-':<8} {'-':<8} {is_totals['pnl']:<12,.0f} {is_pos_str:<8}")
    print(f"{'TOTAL':<8} {'OOS':<6} {oos_totals['trades']:<8} {'-':<8} {'-':<8} {oos_totals['pnl']:<12,.0f} {oos_pos_str:<8}")
    
    # Save results
    output_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 
                               "reports", "macd_rsi_backtest_results.json")
    os.makedirs(os.path.dirname(output_path), exist_ok=True)
    with open(output_path, "w") as f:
        json.dump(all_results, f, indent=2, default=str)
    logger.info(f"\nResults saved to {output_path}")


if __name__ == "__main__":
    main()
