from __future__ import annotations

import functools
import logging

from ..flint.plotter import BasePlotter
from ..utils.serialization import ensure_numpy_pickle_compat
from .xrr_plots import Bm32XrrAnalysisPlot

logger = logging.getLogger(__name__)


def _background_task(method):
    @functools.wraps(method)
    def wrapper(*args, **kw):
        try:
            return method(*args, **kw)
        except Exception as ex:
            logger.error("BM32 XRR plotter task failed (%s)", ex, exc_info=True)
            raise

    return wrapper


class Bm32XrrPlotter(BasePlotter):
    def __init__(self) -> None:
        super().__init__(max_plots=1)
        self._last_plot_name = "XRR analysis"

    def handle_workflow_result(
        self,
        future,
        sample_name: str,
        plot_name: str = "XRR analysis",
    ) -> None:
        if not self._HAS_BLISS:
            return
        self._spawn(self._handle_workflow_result, future, sample_name, plot_name)

    def handle_result(
        self,
        result: dict,
        sample_name: str,
        plot_name: str = "XRR analysis",
    ) -> None:
        self._last_plot_name = plot_name
        result = result if isinstance(result, dict) else {}
        try:
            plot = self._get_plot(plot_name, Bm32XrrAnalysisPlot)
            plot.set_result_data(result, sample_name=sample_name)
        except Exception as ex:
            logger.warning("Could not update BM32 XRR Flint plot: %s", ex)

    @_background_task
    def _handle_workflow_result(
        self,
        future,
        sample_name: str,
        plot_name: str,
    ) -> None:
        ensure_numpy_pickle_compat()
        self.handle_result(
            result=future.result(), sample_name=sample_name, plot_name=plot_name
        )

    def clear(self) -> None:
        try:
            plot = self._get_plot(self._last_plot_name, Bm32XrrAnalysisPlot)
            plot.clear_data()
        except Exception as ex:
            logger.warning("Could not clear BM32 XRR Flint plot: %s", ex)

    def replot(self, **_retry_options) -> None:
        pass
