from uuid import uuid4

from dash import html, dcc
from dash.dependencies import Output, Input, State

from everviz.plugins.plugin_abc import EvervizPluginABC
from everviz.data.load_csv.get_data import get_data
from everviz.util import parse_range, get_placeholder_text, base64encode
from everviz.plugins.summary_plot import summary_callback

from everviz.plugins.summary_plot.util import calculate_statistics
from everviz.plugins.utils.layout.sidebar_layout import get_sidebar_layout


class SummaryPlot(EvervizPluginABC):
    """
    The SummaryPlot class implements a plugin for Webviz, for plotting summary
    key values generated by the eclipse or flow simulators during an Everest
    optimization.

    Summary values can be plotted as a function of time, or as a function of the
    batch number. Generally there are multiple realizations at each batch or
    date. These can be plotted either all individually in the plot, or they are
    summarized by plotting the mean value together with a P10-P90 range.
    """

    def __init__(self, app, csv_file, xaxis="date"):
        super().__init__()

        self.graph_id = f"graph-{uuid4()}"
        self.key1_dropdown_id = f"dropdown-{uuid4()}"
        self.key2_dropdown_id = f"dropdown-{uuid4()}"
        self.xaxis_dropdown_id = f"dropdown-{uuid4()}"
        self.radio_id = f"radio-{uuid4()}"
        self.realization_filter_check_id = f"check-{uuid4()}"
        self.realization_filter_input_id = f"input-{uuid4()}"
        self.label_id = f"label-{uuid4()}"

        self.csv_file = csv_file
        self.xaxis = xaxis

        self.set_callbacks(app)

    def add_webvizstore(self):
        return [
            (get_data, [{"csv_file": self.csv_file}]),
        ]

    @property
    def layout(self):
        radio_options = ["Statistics", "Data"]
        data = get_data(self.csv_file).set_index(["batch", "date", "realization"])
        key_dropdown_options = list(data.columns.unique())
        data = data.reset_index()
        realizations = data["realization"].unique()
        placeholder_text = get_placeholder_text(realizations)
        xaxis_dropdown_options = list(
            data["batch" if self.xaxis == "date" else "date"].unique()
        )
        xaxis_dropdown_title = (
            "Batches to plot" if self.xaxis == "date" else "Dates to plot"
        )

        side_bar_config = [
            (
                "dropdown",
                {
                    "title": "Keywords to plot:",
                    "item_id": self.key1_dropdown_id,
                    "options": key_dropdown_options,
                    "multi": False,
                },
            ),
            (
                "dropdown",
                {
                    "item_id": self.key2_dropdown_id,
                    "options": key_dropdown_options,
                    "multi": False,
                    "set_initial_value": False,
                },
            ),
            (
                "dropdown",
                {
                    "title": xaxis_dropdown_title,
                    "item_id": self.xaxis_dropdown_id,
                    "options": xaxis_dropdown_options,
                    "multi": True,
                },
            ),
            (
                "label",
                {
                    "item_id": self.label_id,
                    "text": f"Statistics are calculated based on {len(realizations)} realizations",
                    "style": {},
                },
            ),
            (
                "radio",
                {"item_id": self.radio_id, "options": radio_options},
            ),
        ]

        realization_elements = [
            html.Div(
                [
                    dcc.Checklist(
                        id=self.realization_filter_check_id,
                        options=[{"label": "Filter realizations:", "value": "filter"}],
                        style={"display": "inline-block", "margin-right": 8},
                    ),
                    dcc.Input(
                        id=self.realization_filter_input_id,
                        type="text",
                        placeholder=placeholder_text,
                        pattern=r"\s*|([0-9]+(\s*-\s*[0-9]+)?)(\s*,\s*[0-9]+(\s*-\s*[0-9]+)?)*",
                        style={"display": "inline-block"},
                    ),
                ],
                style={"margin-top": 20},
            )
        ]

        return html.Div(
            [
                html.Div(
                    [
                        html.Div(
                            [get_sidebar_layout(side_bar_config)]
                            + realization_elements,
                            style={
                                "width": "29%",
                                "display": "inline-block",
                                "vertical-align": "top",
                            },
                        ),
                        html.Div(
                            [
                                dcc.Graph(
                                    id=self.graph_id,
                                    config={
                                        "displaylogo": False,
                                        "toImageButtonOptions": {
                                            "filename": f"summary_by_{self.xaxis}"
                                        },
                                    },
                                )
                            ],
                            style={"width": "69%", "display": "inline-block"},
                        ),
                    ]
                ),
            ]
        )

    def set_callbacks(self, app):
        @app.callback(
            self.plugin_data_output,
            [self.plugin_data_requested],
            [
                State(self.key1_dropdown_id, "value"),
                State(self.key2_dropdown_id, "value"),
                State(self.radio_id, "value"),
                State(self.realization_filter_check_id, "value"),
                State(self.realization_filter_input_id, "value"),
            ],
        )
        def user_download_data(
            data_requested,
            key1,
            key2,
            radio_value,
            realizations_check,
            realizations_input,
        ):
            key_list = []
            if key1:
                key_list.append(key1)
            if key2:
                key_list.append(key2)

            if data_requested and key_list is not None and len(key_list) > 0:
                content = get_data(self.csv_file)
                if realizations_check:
                    realizations = parse_range(realizations_input)
                    if realizations:
                        content = content[content["realization"].isin(realizations)]
                if radio_value == "Statistics":
                    filename = "summary_statistics.csv"
                    content = calculate_statistics(content, key_list)
                else:
                    filename = "summary_values.csv"
                return {
                    "filename": filename,
                    "content": base64encode(content.to_csv()),
                    "mime_type": "text/csv",
                }
            return None

        @app.callback(
            Output(self.label_id, "style"),
            [Input(self.radio_id, "value")],
        )
        def radio_group_click(option):
            if option == "Statistics":
                return {}
            return {"display": "none"}

        @app.callback(
            Output(self.realization_filter_input_id, "disabled"),
            [Input(self.realization_filter_check_id, "value")],
        )
        def set_button_enabled_state(filter_realizations):
            return not filter_realizations

        # pylint: disable=too-many-locals
        @app.callback(
            Output(self.graph_id, "figure"),
            [
                Input(self.key1_dropdown_id, "value"),
                Input(self.key2_dropdown_id, "value"),
                Input(self.xaxis_dropdown_id, "value"),
                Input(self.radio_id, "value"),
                Input(self.realization_filter_check_id, "value"),
                Input(self.realization_filter_input_id, "value"),
            ],
        )
        def update_graph(
            key1, key2, line_list, radio_value, realizations_check, realizations_input
        ):
            # The key_list arguments is the list of keys to plot. The line_list
            # argument is a list of batches, or a list of dates to plot for
            # those keys.
            key_list = []
            if key1:
                key_list.append(key1)
            if key2:
                key_list.append(key2)

            if not key_list or not line_list:
                return {}

            data = get_data(self.csv_file)
            if realizations_check:
                realizations = parse_range(realizations_input)
                if realizations:
                    data = data[data["realization"].isin(realizations)]

            if radio_value == "Statistics":
                data = calculate_statistics(data, key_list).set_index(
                    ["summary_key", "batch", "date"]
                )
            else:
                data = data.set_index(["batch", "date"])

            callback = summary_callback.get_callback_func(radio_value)

            line_key = "batch" if self.xaxis == "date" else "date"
            line_filter = "batch" if line_key == "date" else "date"
            traces = callback(data, key_list, line_list, line_key, line_filter)
            return {
                "data": traces,
                "layout": summary_callback.get_layout(
                    summary_key_list=key_list, xaxis_title=self.xaxis.capitalize()
                ),
            }
