import pathlib
from typing import Optional

import dash_core_components as dcc
from webviz_config import WebvizPluginABC
from webviz_config.webviz_assets import WEBVIZ_ASSETS

import webviz_subsurface
from webviz_subsurface._models import EnsembleSetModel
from .views import main_view
from .models import ParametersModel, SimulationTimeSeriesModel
from .controllers import (
    parameter_qc_controller,
    parameter_response_controller,
)
from .data_loaders import read_csv


class ParameterAnalysis(WebvizPluginABC):
    """This plugin visualizes parameter distributions and statistics. /
    for FMU ensembles, and can be used to investigate parameter correlations /
    on reservoir simulation time series data.

---

**Input data can be provided in two ways: Aggregated or read from ensembles stored on scratch.**

**Using aggregated data**
* **`csvfile_parameters`:** Aggregated `csv` file with `REAL`, `ENSEMBLE` and parameter columns. \
    (absolute path or relative to config file).
* **`csvfile_smry`:** (Optional) Aggregated `csv` file for volumes with `REAL`, `ENSEMBLE`, `DATE` \
    and vector columns (absolute path or relative to config file).

**Using raw ensemble data stored in realization folders**
* **`ensembles`:** Which ensembles in `shared_settings` to visualize.
* **`column_keys`:** List of vectors to extract. If not given, all vectors \
    from the simulations will be extracted. Wild card asterisk `*` can be used.
* **`time_index`:** Time separation between extracted values. Can be e.g. `monthly` (default) or \
    `yearly`.

**Common settings for all input options**
* **`drop_constants`:** Bool used to determine if constant parameters should be dropped. \
    Default is True.

---

!> For smry data it is **strongly recommended** to keep the data frequency to a regular frequency \
(like `monthly` or `yearly`). This applies to both csv input and when reading from `UNSMRY` \
(controlled by the `sampling` key). This is because the statistics and fancharts are calculated \
per DATE over all realizations in an ensemble, and the available dates should therefore not \
differ between individual realizations of an ensemble.

?> Vectors that are identified as historical vectors (e.g. FOPTH is the history of FOPT) will \
be plotted together with their non-historical counterparts as reference lines.

**Using simulation time series data directly from `.UNSMRY` files**

!> Parameter values are extracted automatically from the `parameters.txt` files in the individual
realizations if you have defined `ensembles`, using the `fmu-ensemble` library.

!> The `UNSMRY` files are auto-detected by `fmu-ensemble` in the `eclipse/model` folder of the \
individual realizations. You should therefore not have more than one `UNSMRY` file in this \
folder, to avoid risk of not extracting the right data.

**Using aggregated data**

?> Aggregated data may speed up the build of the app, as processing of `UNSMRY` files can be \
slow for large models.

"""

    # pylint: disable=too-many-arguments
    def __init__(
        self,
        app,
        ensembles: Optional[list] = None,
        csvfile_parameters: pathlib.Path = None,
        csvfile_smry: pathlib.Path = None,
        time_index: str = "monthly",
        column_keys: Optional[list] = None,
        drop_constants: bool = True,
    ):
        super().__init__()
        WEBVIZ_ASSETS.add(
            pathlib.Path(webviz_subsurface.__file__).parent
            / "_assets"
            / "css"
            / "container.css"
        )
        self.theme = app.webviz_settings["theme"]
        self.time_index = time_index
        self.column_keys = column_keys
        self.ensembles = ensembles
        self.csvfile_parameters = csvfile_parameters
        self.csvfile_smry = csvfile_smry

        if ensembles is not None:
            self.emodel = EnsembleSetModel(
                ensemble_paths={
                    ens: app.webviz_settings["shared_settings"]["scratch_ensembles"][
                        ens
                    ]
                    for ens in ensembles
                }
            )
            self.pmodel = ParametersModel(
                dataframe=self.emodel.load_parameters(),
                theme=self.theme,
                drop_constants=drop_constants,
            )
            self.vmodel = SimulationTimeSeriesModel(
                dataframe=self.emodel.load_smry(
                    time_index=self.time_index, column_keys=self.column_keys
                ),
                theme=self.theme,
            )

        elif self.csvfile_parameters is None:
            raise ValueError("Either ensembles or csvfile_parameters must be specified")
        else:
            self.pmodel = ParametersModel(
                dataframe=read_csv(csvfile_parameters),
                theme=self.theme,
                drop_constants=drop_constants,
            )
            if self.csvfile_smry is not None:
                self.vmodel = SimulationTimeSeriesModel(
                    dataframe=read_csv(csvfile_smry), theme=self.theme.plotly_theme
                )
            else:
                self.vmodel = None

        self.set_callbacks(app)

    @property
    def layout(self) -> dcc.Tabs:
        return main_view(parent=self)

    def set_callbacks(self, app) -> None:
        parameter_qc_controller(self, app)
        if self.vmodel is not None:
            parameter_response_controller(self, app)

    def add_webvizstore(self):
        store = []
        if self.ensembles is not None:
            store.extend(self.emodel.webvizstore)
        else:
            store.extend(
                (
                    read_csv,
                    [
                        {"csv_file": self.csvfile_parameters},
                    ],
                )
            )
            if self.csvfile_smry is not None:
                store.extend(
                    (
                        read_csv,
                        [
                            {"csv_file": self.csvfile_smry},
                        ],
                    )
                )

        return store
