from __future__ import annotations

import numpy as np
from silx.gui import qt
from silx.gui.colors import Colormap
from silx.gui.colors import rgba as qt_to_rgba
from silx.io.utils import DataUrl

from ewoks3dxrd.nexus.peaks import read_peaks_attributes
from ewoks3dxrd.tasks.filter_by_intensity import FilterByIntensity
from ewoks3dxrd.tasks.filter_by_intensity import Inputs

from .common.ewoks3dxrd_widget import Ewoks3DXRDWidget
from .common.execution_control_group_box import ExecutionControlGroupBoxWithProcessName
from .common.intensity_filter_control_box import IntensityControlBox
from .common.peak_filter_plot2d import PeakFilterPlot2D


class OWIntensityFilter(Ewoks3DXRDWidget, ewokstaskclass=FilterByIntensity):
    name = "Intensity Filter"
    description = "Filter peaks based on the Intensity."
    icon = "icons/filter-invert.svg"

    _ewoks_inputs_to_hide_from_orange = (
        "overwrite",
        "intensity_frac",
        "thermal_factor",
        "process_group_name",
    )

    def __init__(self):
        super().__init__()

        settingsWidget = qt.QWidget(self)
        settingLayout = qt.QVBoxLayout(settingsWidget)
        self._inputParametersBox = IntensityControlBox(self)
        self._executeBox = ExecutionControlGroupBoxWithProcessName(
            buttonText="Filter Peaks"
        )
        self._executeBox.sigExecuteRequested.connect(self.execute_with_validation)
        self._executeBox.sigUrlChanged.connect(self._onDataURLEditFinished)
        self._executeBox.setProcessName(
            Inputs.model_fields["process_group_name"].default
        )
        settingLayout.addWidget(self._inputParametersBox)
        settingLayout.addWidget(self._executeBox)
        self.addControlWidget(settingsWidget)

        self._plot = PeakFilterPlot2D(self)
        self.addMainWidget(self._plot)
        self.registerInput(
            "lattice_filtered_data_url",
            self._executeBox.getInputURL,
            self._executeBox.setInputURL,
        )
        self.registerInput(
            "intensity_frac",
            self._inputParametersBox.intensityFrac.value,
            self._inputParametersBox.intensityFrac.setValue,
        )
        self.registerInput(
            "thermal_factor",
            self._inputParametersBox.thermalFactor.value,
            self._inputParametersBox.thermalFactor.setValue,
        )
        self.registerInput(
            "process_group_name",
            self._executeBox.getProcessName,
            self._executeBox.setProcessName,
        )
        self.registerInput(
            "overwrite",
            self._executeBox.isOverwriteChecked,
            self._executeBox.setOverwrite,
        )

    def validateInputs(self):
        self._inputParametersBox.validate()
        self._executeBox.validate()

    def handleNewSignals(self):
        input_url = self.get_task_input_value("lattice_filtered_data_url", None)
        if input_url:
            self._executeBox.setInputURL(input_url)
            self._executeBox.validate()
            self._plotIncomingPeaks()

    def _plotIncomingPeaks(self):
        inputUrl = self._executeBox.getInputURL()
        if not inputUrl:
            return
        data_url = DataUrl(inputUrl)
        nexus_file_path, lattice_data_group_path = (
            data_url.file_path(),
            data_url.data_path(),
        )
        lattice_3d_peaks = read_peaks_attributes(
            filename=nexus_file_path,
            process_name=lattice_data_group_path,
        )
        self._plot.addUnfilteredScatter(
            x=lattice_3d_peaks["ds"],
            y=lattice_3d_peaks["sum_intensity"],
            value=len(lattice_3d_peaks["ds"]) * [1],
            colormap=Colormap(
                colors=np.array(qt_to_rgba(qt.QColor(qt.Qt.blue))).reshape(1, 4)
            ),
        )
        self._plot.setGraphXLabel("Reciprocal distance (ds)")
        self._plot.setGraphYLabel("Sum Intensity")
        self._plot.setYAxisLogarithmic(True)
        self._plot.resetZoomOnce()

    def handleSuccessfulExecution(self):
        if self.get_task_output_value("intensity_filtered_data_url", None) is None:
            return
        self.setOutputDataUrl(self.get_task_output_value("intensity_filtered_data_url"))
        self.displayOutputDataUrl()

    def displayOutputDataUrl(self):
        data_url = DataUrl(self.getOutputDataUrl())
        nexus_file_path, lattice_data_group_path = (
            data_url.file_path(),
            data_url.data_path(),
        )
        intensity_3d_peaks = read_peaks_attributes(
            filename=nexus_file_path,
            process_name=lattice_data_group_path,
        )
        self._plot.addFilteredScatter(
            x=intensity_3d_peaks["ds"],
            y=intensity_3d_peaks["sum_intensity"],
            value=len(intensity_3d_peaks["ds"]) * [0.5],
            colormap=Colormap(
                colors=np.array(qt_to_rgba(qt.QColor(qt.Qt.red))).reshape(1, 4)
            ),
        )
        self._plot.setGraphXLabel("Reciprocal distance (ds)")
        self._plot.setGraphYLabel("Sum Intensity")
        self._plot.resetZoomOnce()

    def _onDataURLEditFinished(self) -> None:
        self._handlePeaksInputURL(
            urlWidget=self._executeBox.inputUrlWidget,
            defaultInputKey="lattice_filtered_data_url",
            errorTitle="Invalid Incoming Peaks Data group path",
        )
