# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

import copy
from typing import Iterable

import pandas as pd
import plotly.graph_objs as go

from ..graph import ScatterGraph
from ..analysis_position.parse_position import get_position_data


def _get_figure_with_position(
    position: dict, label_data: pd.DataFrame, start_date=None, end_date=None
) -> Iterable[go.Figure]:
    """Get average analysis figures

    :param position: position
    :param label_data:
    :param start_date:
    :param end_date:
    :return:
    """
    _position_df = get_position_data(
        position,
        label_data,
        calculate_label_rank=True,
        start_date=start_date,
        end_date=end_date,
    )

    res_dict = dict()
    _pos_gp = _position_df.groupby(level=1)
    for _item in _pos_gp:
        _date = _item[0]
        _day_df = _item[1]

        _day_value = res_dict.setdefault(_date, {})
        for _i, _name in {0: "Hold", 1: "Buy", -1: "Sell"}.items():
            _temp_df = _day_df[_day_df["status"] == _i]
            if _temp_df.empty:
                _day_value[_name] = 0
            else:
                _day_value[_name] = _temp_df["rank_label_mean"].values[0]

    _res_df = pd.DataFrame.from_dict(res_dict, orient="index")
    # FIXME: support HIGH-FREQ
    _res_df.index = _res_df.index.strftime("%Y-%m-%d")
    for _col in _res_df.columns:
        yield ScatterGraph(
            _res_df.loc[:, [_col]],
            layout=dict(
                title=_col,
                xaxis=dict(type="category", tickangle=45),
                yaxis=dict(title="lable-rank-ratio: %"),
            ),
            graph_kwargs=dict(mode="lines+markers"),
        ).figure


def rank_label_graph(
    position: dict,
    label_data: pd.DataFrame,
    start_date=None,
    end_date=None,
    show_notebook=True,
) -> Iterable[go.Figure]:
    """Ranking percentage of stocks buy, sell, and holding on the trading day.
    Average rank-ratio(similar to **sell_df['label'].rank(ascending=False) / len(sell_df)**) of daily trading

        Example:


            .. code-block:: python

                from qlib.data import D
                from qlib.contrib.evaluate import backtest
                from qlib.contrib.strategy import TopkDropoutStrategy

                # backtest parameters
                bparas = {}
                bparas['limit_threshold'] = 0.095
                bparas['account'] = 1000000000

                sparas = {}
                sparas['topk'] = 50
                sparas['n_drop'] = 230
                strategy = TopkDropoutStrategy(**sparas)

                _, positions = backtest(pred_df, strategy, **bparas)

                pred_df_dates = pred_df.index.get_level_values(level='datetime')
                features_df = D.features(D.instruments('csi500'), ['Ref($close, -1)/$close-1'], pred_df_dates.min(), pred_df_dates.max())
                features_df.columns = ['label']

                qcr.analysis_position.rank_label_graph(positions, features_df, pred_df_dates.min(), pred_df_dates.max())


    :param position: position data; **qlib.backtest.backtest** result.
    :param label_data: **D.features** result; index is **pd.MultiIndex**, index name is **[instrument, datetime]**; columns names is **[label]**.

        **The label T is the change from T to T+1**, it is recommended to use ``close``, example: `D.features(D.instruments('csi500'), ['Ref($close, -1)/$close-1'])`.


            .. code-block:: python

                                                label
                instrument  datetime
                SH600004        2017-12-11  -0.013502
                                2017-12-12  -0.072367
                                2017-12-13  -0.068605
                                2017-12-14  0.012440
                                2017-12-15  -0.102778


    :param start_date: start date
    :param end_date: end_date
    :param show_notebook: **True** or **False**. If True, show graph in notebook, else return figures.
    :return:
    """
    position = copy.deepcopy(position)
    label_data.columns = ["label"]
    _figures = _get_figure_with_position(position, label_data, start_date, end_date)
    if show_notebook:
        ScatterGraph.show_graph_in_notebook(_figures)
    else:
        return _figures
