import pandas as pd
import numpy as np
from utils.helpers import zscore

def backtest(df, window, threshold, time_factor, commission, mode):
    df = df.copy()
    df['O2C_chg'] = df['Close'] / df['Open'] - 1
    factor = df.active_addresses
    df['indicator'] = zscore(factor, window)

    longCondition = df['indicator'].shift() > threshold
    shortCondition = df['indicator'].shift() < -threshold

    df['pos'] = np.where(longCondition, 1, np.where(shortCondition, -1, 0))
    df['pnl'] = df['pos'] * df['O2C_chg'] - commission * abs(df['pos'].diff())
    sharpe = df['pnl'].mean() / df['pnl'].std() * np.sqrt(time_factor)

    if mode == 'heatmap':
        return pd.Series([window, threshold, sharpe], index=['window', 'threshold', 'sharpe'])

    elif mode == 'full_report':
        ar = df.pnl.mean() * time_factor * 100
        mdd = (df.pnl.cumsum() - df.pnl.cumsum().cummax()).min() * 100
        calmar = ar / abs(mdd)

        beta, _ = np.polyfit(df.Close.pct_change()[1:], df.pnl.dropna(), 1)
        num_trades = int(
            pd.concat([abs(df.pos.diff()), pd.Series(abs(df.pos).iloc[-1])]).fillna(df.pos.iloc[0]).cumsum().iloc[
                -1] / 2)
        long_duration = (len(df.pos[df.pos == 1]) / len(df.pos)) * 100
        short_duration = (len(df.pos[df.pos == -1]) / len(df.pos)) * 100

        win_rate = len(df.pnl[df.pnl > 0]) / len(df.pnl[df.pnl > 0] + df.pnl[df.pnl < 0]) * 100
        avg_win = df.pnl[df.pnl > 0].mean() * 100
        avg_loss = df.pnl[df.pnl < 0].mean() * 100

        turnover_pct = (long_duration + short_duration) / num_trades
        turnover = turnover_pct * len(df) * 0.01

        result_dict = {
            'Return (Ann.) [%]': ar,
            'Sharpe Ratio': sharpe,
            'Calmar Ratio': calmar,
            'Max. Drawdown [%]': mdd,
            'Beta': beta,
            'Win Rate [%]': win_rate,
            'Avg Win [%]': avg_win,
            'Avg Loss [%]': avg_loss,
            'Number of Trades': num_trades,
            'Long Duration [%]': long_duration,
            'Short Duration [%]': short_duration,
            'Turnover [%]': turnover_pct,
            'Turnover Period': turnover,
            'Equity Curve': df.pnl.cumsum().tolist(),
            'Benchmark': df.O2C_chg.cumsum().tolist(),
            'Dates': df.index.tolist(),
            'Returns': df.pnl.tolist(),  # Added daily PnL
            'Benchmark Returns': df.O2C_chg.tolist()  # Added benchmark returns
        }

        return result_dict

def combine_strategies(df, strategies, time_factor, commission):
    """
    Combine multiple strategies and calculate aggregate metrics.

    Parameters:
    -----------
    df : pandas.DataFrame
        Input data with OHLCV columns
    strategies : list of dict
        List of strategies with 'window' and 'threshold' parameters
    time_factor : int
        Time factor for annualization
    commission : float
        Commission rate

    Returns:
    --------
    dict
        Dictionary containing combined backtest results
    """
    combined_pnl = pd.Series(0.0, index=df.index)
    combined_benchmark = pd.Series(0.0, index=df.index)

    # Combine strategies
    for strategy in strategies:
        result = backtest(df, strategy['window'], strategy['threshold'],
                          time_factor, commission, 'full_report')
        combined_pnl += pd.Series(result['Returns'], index=pd.to_datetime(result['Dates']))
        combined_benchmark += pd.Series(result['Benchmark Returns'], index=pd.to_datetime(result['Dates']))

    # Average the returns
    n_strategies = len(strategies)
    combined_pnl = combined_pnl / n_strategies
    combined_benchmark = combined_benchmark / n_strategies

    # Calculate metrics
    ar = combined_pnl.mean() * time_factor * 100
    mdd = (combined_pnl.cumsum() - combined_pnl.cumsum().cummax()).min() * 100
    calmar = ar / abs(mdd)
    sharpe = combined_pnl.mean() / combined_pnl.std() * np.sqrt(time_factor)
    beta, _ = np.polyfit(df.Close.pct_change()[1:], combined_pnl.dropna(), 1)

    return {
        'Returns': combined_pnl.values,
        'Benchmark Returns': combined_benchmark.values,
        'Dates': df.index,
        'Equity Curve': combined_pnl.cumsum().values,
        'Benchmark': combined_benchmark.cumsum().values,
        'Return (Ann.) [%]': ar,
        'Sharpe Ratio': sharpe,
        'Calmar Ratio': calmar,
        'Max. Drawdown [%]': mdd,
        'Beta': beta
    }