"""
report for PortfolioData.strategy_signal_data
"""
import numpy as np
# packages
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from typing import Tuple, List
import qis as qis
from qis import TimePeriod, BenchmarkReturnsQuantileRegimeSpecs
from qis.portfolio.portfolio_data import PortfolioData, StrategySignalData


def generate_weight_change_report(portfolio_data: PortfolioData,
                                  time_period: TimePeriod,
                                  is_grouped: bool = True,
                                  sample_size: int = 20,
                                  figsize: Tuple[float, float] = (8.3, 11.7),
                                  verbose: bool = False,
                                  **kwargs
                                  ) -> plt.Figure:
    strategy_signal_data = portfolio_data.strategy_signal_data
    if strategy_signal_data is None:
        raise ValueError(f"portfolio_data.strategy_signal_data must be provided")

    if is_grouped:
        predictions_g, fitted_models_g = strategy_signal_data.estimate_signal_changes_by_groups(
            group_data=portfolio_data.group_data,
            group_order=portfolio_data.group_order,
            time_period=time_period,
            sample_size=sample_size)

        with sns.axes_style('darkgrid'):
            fig, axs = plt.subplots(len(predictions_g.keys())//2+1, 2, figsize=figsize, tight_layout=True)
            axs = qis.to_flat_list(axs)
            qis.set_suptitle(fig, title=f"{portfolio_data.ticker} weights change report")

        for idx, (group, df) in enumerate(predictions_g.items()):
            if verbose:
                print(f"{group}")
                print(df)
                print(f"{fitted_models_g[group].summary()}")
            df_ac = df[['momentum_change', 'carry_change', 'target_vol_change', 'port_leverage_change', 'resid']]
            qis.plot_bars(df=df_ac, stacked=True,
                          totals=df_ac.sum(1).to_list(),
                          annotate_totals=False,
                          title=f"{group}",
                          ncols=len(df_ac.columns)//2,
                          yvar_format='{:,.2%}',
                          ax=axs[idx],
                          **kwargs)
    else:
        raise NotImplementedError
    return fig


def generate_strategy_signal_factsheet_by_instrument(strategy_signal_data: StrategySignalData,
                                                     time_period: TimePeriod,
                                                     figsize: Tuple[float, float] = (8.3, 11.7),  # A4 for portrait
                                                     fontsize: int = 4,
                                                     regime_params: BenchmarkReturnsQuantileRegimeSpecs = None,
                                                     **kwargs
                                                     ) -> List[plt.Figure]:

    if strategy_signal_data is None:
        raise ValueError(f"portfolio_data.strategy_signal_data must be provided")

    navs = qis.returns_to_nav(returns=np.expm1(strategy_signal_data.log_returns))
    if time_period is not None:
        strategy_signal_data = strategy_signal_data.locate_period(time_period=time_period)
        navs = time_period.locate(navs)

    plot_kwargs = dict(fontsize=fontsize,
                       linewidth=0.5,
                       digits_to_show=1, sharpe_digits=2,
                       weight='normal',
                       markersize=1,
                       framealpha=0.75)
    kwargs = qis.update_kwargs(kwargs, plot_kwargs)
    figs = []
    for instrument in strategy_signal_data.signal:
        with sns.axes_style('darkgrid'):
            fig, axs = plt.subplots(7, 2, figsize=figsize, tight_layout=True)
            qis.set_suptitle(fig, title=f"{instrument}")
            figs.append(fig)

        datas = dict(nav=navs[instrument],
                     signal=strategy_signal_data.signal[instrument],
                     vol=strategy_signal_data.instrument_vols[instrument],
                     target_vol=strategy_signal_data.instrument_target_vols[instrument],
                     target_signal_vol_weight=strategy_signal_data.instrument_target_signal_vol_weights[instrument],
                     portfolio_leverages=strategy_signal_data.instrument_portfolio_leverages[instrument],
                     weights=strategy_signal_data.weights[instrument])
        var_formats = ['{:.2%}', '{:.2f}', '{:.2%}', '{:.2%}', '{:.2%}', '{:.2f}', '{:.2%}']

        for idx, (key, df) in enumerate(datas.items()):

            if idx == 0:
                df0 = df / df.iloc[0]
                df1 = df.pct_change()
                title1 = 'Log-returns'
                qis.plot_prices(prices=df0,
                                title='Performance',
                                var_format='{:,.2f}',
                                ax=axs[idx][0],
                                **kwargs)
            else:
                df1 = df
                title1 = key
                qis.plot_time_series(df=df,
                                     # trend_line=qis.TrendLine.ZERO_SHADOWS,
                                     var_format=var_formats[idx],
                                     title=key,
                                     legend_stats=qis.LegendStats.AVG_MIN_MAX_LAST,
                                     ax=axs[idx][0],
                                     **kwargs)
            qis.add_bnb_regime_shadows(ax=axs[idx][0],
                                       pivot_prices=navs[instrument].reindex(index=df.index, method='ffill'),
                                       regime_params=regime_params)

            qis.plot_histogram(df=df1,
                               # trend_line=qis.TrendLine.ZERO_SHADOWS,
                               var_format=var_formats[idx],
                               title=title1,
                               legend_stats=qis.LegendStats.AVG_MIN_MAX_LAST,
                               desc_table_type=None,
                               ax=axs[idx][1],
                               **kwargs)
            plt.close('all')
    return figs
