import pandas as pd
import numpy as np
from typing import Tuple

def timeframe_reduce(df, times):
    new_df = pd.DataFrame()
    rolling = df.shift().rolling(window=times, step=times)
    indexes_of_first = df[(df.index+1) % times == 0].index - (times - 1)
    indexes_of_last = df[(df.index+1) % times == 0].index

    if 'High' in df.columns:
        new_df['High'] = rolling.High.max().reset_index(drop=True)
    if 'Low' in df.columns:
        new_df['Low'] = rolling.Low.min().reset_index(drop=True)
    if 'Open' in df.columns:
        new_df['Open'] = df.iloc[indexes_of_first].Open.reset_index(drop=True).shift(1)
    if 'Close' in df.columns:
        new_df['Close'] = df.iloc[indexes_of_last].Close.reset_index(drop=True).shift(1)
    if 'Time' in df.columns:
        new_df['Time'] = df.iloc[indexes_of_first].Time.reset_index(drop=True).shift(1)
    if 'CloseTime' in df.columns:
        new_df['CloseTime'] = df.iloc[indexes_of_last].CloseTime.reset_index(drop=True).shift(1)
    if 'Ask' in df.columns:
        new_df['Ask'] = rolling.Ask.sum().reset_index(drop=True)
    if 'Bid' in df.columns:
        new_df['Bid'] = rolling.Bid.sum().reset_index(drop=True)
    if 'AskTrades' in df.columns:
        new_df['AskTrades'] = rolling.AskTrades.sum().reset_index(drop=True)
    if 'BidTrades' in df.columns:
        new_df['BidTrades'] = rolling.BidTrades.sum().reset_index(drop=True)
    if 'DeltaHigh' in df.columns:
        new_df['DeltaHigh'] = rolling.DeltaHigh.sum().reset_index(drop=True)
    if 'DeltaLow' in df.columns:
        new_df['DeltaLow'] = rolling.DeltaLow.sum().reset_index(drop=True)
    if 'OpenPos' in df.columns:
        new_df['OpenPos'] = rolling.OpenPos.sum().reset_index(drop=True)
    if 'Volume' in df.columns:
        new_df['Volume'] = rolling.Volume.sum().reset_index(drop=True)
    if 'Delta' in df.columns:
        new_df['Delta'] = rolling.Delta.sum().reset_index(drop=True)

    if not new_df.empty:
        new_df.drop(index=new_df.index[0], axis=0, inplace=True)
    new_df.drop(index=new_df.index[0],
        axis=0,
        inplace=True)

    return new_df



RANDOM_SEED = 42
fibos = [ 0, 1, 2, 3, 5, 8, 10, 13, 17, 21, 28, 34, 45, 55, 89, 144, 233, 377, 610, 987, 1597]

# def figsize():
#     plt.figure(figsize=(12,6))


def untrend(data, window):
    return data - data.rolling(window, center=True).mean()

def untrend_center_false(data, window):
    return data - data.rolling(window, center=False).mean()

def GetScoreTable(y_true, y_pred):
    score_table = []
    tresholds = [0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95]
    total = []
    wins = []
    for th in tresholds:
        t = (y_pred > th).sum()
        w = ((y_pred > th) & (y_true.reset_index(drop=True) == True)).sum()
        score_table.append(w / t)
        total.append(t)
        wins.append(w)

    return pd.DataFrame({'limit':tresholds, 'predicts_num':total, 'wins':wins, 'winrate':score_table})

def will_frac(df: pd.DataFrame, period: int = 2) -> Tuple[pd.Series, pd.Series]:
    """Indicate bearish and bullish fractal patterns using shifted Series.

    :param df: OHLC data
    :param period: number of lower (or higher) points on each side of a high (or low)
    :return: tuple of boolean Series (bearish, bullish) where True marks a fractal pattern
    """

    periods = [p for p in range(-period, period + 1) if p != 0] # default [-2, -1, 1, 2]

    highs = [df['High'] > df['High'].shift(p) for p in periods]
    bears = pd.Series(np.logical_and.reduce(highs), index=df.index)

    lows = [df['Low'] < df['Low'].shift(p) for p in periods]
    bulls = pd.Series(np.logical_and.reduce(lows), index=df.index)

    return bears, bulls