from __future__ import annotations

import logging
import traceback

from AnyQt.QtCore import QCoreApplication
from AnyQt.QtCore import QThread
from ImageD11.unitcell import unitcell as UnitCell
from silx.gui import qt
from silx.gui.plot import PlotWidget

MAX_INT_32 = 2147483647

_logger = logging.getLogger(__name__)


def format_exception(error: Exception) -> str:
    return "\n".join(traceback.format_exception(error))


def getFileNameFromUser(fileType: str, extension: str):
    options = qt.QFileDialog.Options(qt.QFileDialog.DontUseNativeDialog)
    filePath, _ = qt.QFileDialog.getSaveFileName(
        None,
        f"Save {fileType}",
        "",
        f"File extensions (*.{extension})",
        options=options,
    )
    return filePath


def isPlotOnMainThread():
    app = QCoreApplication.instance()
    currentThreadId = QThread.currentThreadId()
    if app is None:
        return False, currentThreadId
    return (currentThreadId == app.thread()), currentThreadId


class NoWheelMixin:
    """A mixin to disable mouse wheel events for a widget."""

    def wheelEvent(self, event: qt.QWheelEvent) -> None:
        event.ignore()


class NoWheelSpinBox(NoWheelMixin, qt.QSpinBox):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setRange(0, MAX_INT_32)


class NoWheelDoubleSpinBox(NoWheelMixin, qt.QDoubleSpinBox):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setRange(float("-inf"), float("inf"))
        self.setDecimals(15)
        self.setStepType(qt.QAbstractSpinBox.StepType.AdaptiveDecimalStepType)
        self.setSingleStep(1e-9)


def plotRings(plotWidget: PlotWidget, unitCell: UnitCell, limit: float):
    try:
        unitCell.makerings(limit=limit)
    except IndexError:  # https://github.com/FABLE-3DXRD/ImageD11/issues/538
        _logger.warning(
            f"Cannot plot rings: there are no rings for this lattice under {limit:.2f}A^-1."
        )
        # Clear previous plotted rings
        plotWidget.clearMarkers()
        return
    unitCell.makerings(limit=limit)

    for i, ring_ds in enumerate(unitCell.ringds):
        marker = plotWidget.addXMarker(ring_ds, legend=f"Ring {i}", text=f"{i}")
        color, _ = plotWidget._getColorAndStyle()
        marker.setColor(color)
        marker.setLineStyle("-")
        marker.setLineWidth(2)
