"""Flint-side for Flint XRPD plots"""

import logging
from typing import List

from silx.gui.plot import Plot1D
from silx.gui.plot import Plot2D
from silx.gui.plot.items import Item
from silx.gui.plot.items import ItemChangedType
from silx.gui.plot.items.curve import Curve

from ..flint import capture_errors
from .models import XrpdPlotInfo
from .plot_data import append_image_data
from .plot_data import get_2d_integration_data
from .plot_data import get_curve_data

logger = logging.getLogger(__name__)


class XrpdCurveWidget(Plot1D):

    _DEFAULT_XLABEL = "Radial bins"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setGraphGrid(True)
        self.setGraphXLabel(self._DEFAULT_XLABEL)
        self.setGraphYLabel("Scattered intensity")
        self.sigItemAdded.connect(self._item_added)
        self.sigItemRemoved.connect(self._item_removed)

    def _item_added(self, item: Item) -> None:
        if isinstance(item, Curve):
            item.sigItemChanged.connect(self._curve_changed)
            self._update_xlabel()

    def _item_removed(self, item: Item) -> None:
        if isinstance(item, Curve):
            item.sigItemChanged.disconnect(self._curve_changed)
            self._update_xlabel()

    def _curve_changed(self, change_type: ItemChangedType) -> None:
        if change_type == ItemChangedType.VISIBLE:
            self._update_xlabel()

    def _update_xlabel(self) -> None:
        unique_xlabels = set(curve.getXLabel() for curve in self.getAllCurves())
        unique_xlabels.discard(None)

        if len(unique_xlabels) == 1:
            self.setGraphXLabel(unique_xlabels.pop())
        else:
            self.setGraphXLabel(self._DEFAULT_XLABEL)

    @capture_errors
    def remove_plot(self, plot_key: str) -> None:
        try:
            plot_info = XrpdPlotInfo.get(plot_key)
        except KeyError as ex:
            logger.debug("%r already removed: %s", plot_key, ex)
            return

        legend = plot_info.legend
        logger.debug("remove %r", legend)
        self.remove(legend=plot_info.legend)

    @capture_errors
    def update_plot(self, plot_key: str, retry_options: dict) -> None:
        x, y, plot_info = get_curve_data(plot_key, **retry_options)
        legend = plot_info.legend

        if y is None:
            logger.debug("XRPD curve plot %r: no data to plot", legend)
            return

        if len(x) != len(y):
            logger.error("XRPD curve plot %r: Nx=%d, Ny=%d", legend, len(x), len(y))
        else:
            logger.debug("XRPD curve plot %r: Nx=%d, Ny=%d", legend, len(x), len(y))
            self.addCurve(
                x,
                y,
                legend=legend,
                xlabel=plot_info.radial_label,
                color=plot_info.color,
                linestyle="-",
            )

    @capture_errors
    def get_labels(self) -> List[str]:
        return [legend.getName() for legend in self.getItems()]


class XrpdImageWidget(Plot2D):
    @capture_errors
    def remove_plot(self, plot_key: str) -> None:
        self.clear()

    @capture_errors
    def update_plot(self, plot_key: str, retry_options: dict) -> None:
        img = self.getImage(legend=plot_key)
        if img is None:
            current_data = None
        else:
            current_data = img.getData(copy=False)
        x, y, plot_info = append_image_data(plot_key, current_data, **retry_options)
        title = plot_info.legend

        if y is None:
            logger.debug("XRPD image plot %s: no data to plot", title)
            return

        origin = x[0], 0
        scale = x[1] - x[0], 1
        self.clear()
        self.setGraphTitle(title)
        logger.debug("XRPD image plot %s: %s points", title, len(y))
        self.addImage(
            y,
            legend=title,
            xlabel=plot_info.radial_label,
            ylabel="Scan points",
            origin=origin,
            scale=scale,
        )

    @capture_errors
    def get_labels(self) -> List[str]:
        return [self.getGraphTitle()]


class Xrpd2dIntegrationWidget(Plot2D):
    @capture_errors
    def remove_plot(self, plot_key: str) -> None:
        self.clear()

    @capture_errors
    def update_plot(self, plot_key: str, retry_options: dict) -> None:
        x, y, intensity, plot_info = get_2d_integration_data(plot_key, **retry_options)
        if x is None or y is None or intensity is None:
            return
        origin = x[0], y[0]
        scale = x[1] - x[0], y[1] - y[0]
        self.clear()
        title = plot_info.legend
        self.setGraphTitle(title)
        logger.debug(
            "XRPD 2D integration plot %r: Nx=%d, Ny=%d, Shape=%s",
            title,
            len(x),
            len(y),
            intensity.shape,
        )
        self.addImage(
            intensity,
            legend=title,
            xlabel=plot_info.radial_label,
            ylabel=plot_info.azim_label,
            origin=origin,
            scale=scale,
        )

    @capture_errors
    def get_labels(self) -> List[str]:
        return [self.getGraphTitle()]
