from unittest.mock import MagicMock, patch

import pyqtgraph as pg
import pytest

from bec_widgets.widgets.image.image_widget import BECImageWidget

from .client_mocks import mocked_client


@pytest.fixture
def image_widget(qtbot, mocked_client):
    widget = BECImageWidget(client=mocked_client())
    widget.toolbar.widgets["monitor"].device_combobox.set_device_filter("FakeDevice")
    qtbot.addWidget(widget)
    qtbot.waitExposed(widget)
    yield widget


@pytest.fixture
def mock_image(image_widget):
    image_mock = MagicMock()
    image_widget._image = image_mock
    return image_mock


def test_image_widget_init(image_widget):
    assert image_widget is not None
    assert image_widget.client is not None
    assert isinstance(image_widget, BECImageWidget)
    assert image_widget.config.widget_class == "BECImageWidget"
    assert image_widget._image is not None

    assert (
        image_widget.toolbar.widgets["monitor"].device_combobox.config.device_filter == "FakeDevice"
    )
    assert image_widget.toolbar.widgets["drag_mode"].action.isChecked() == True
    assert image_widget.toolbar.widgets["rectangle_mode"].action.isChecked() == False
    assert image_widget.toolbar.widgets["auto_range"].action.isChecked() == False
    assert image_widget.toolbar.widgets["auto_range_image"].action.isChecked() == True
    assert image_widget.toolbar.widgets["FFT"].action.isChecked() == False
    assert image_widget.toolbar.widgets["transpose"].action.isChecked() == False
    assert image_widget.toolbar.widgets["log"].action.isChecked() == False


###################################
# Toolbar Actions
###################################
def test_toolbar_connect_action(image_widget, mock_image, qtbot):
    combo = image_widget.toolbar.widgets["monitor"].device_combobox
    combo.setCurrentText("eiger")
    qtbot.wait(200)
    assert combo.currentText() == "eiger"
    action = image_widget.toolbar.widgets["connect"].action
    action.trigger()
    image_widget._image.image.assert_called_once_with(
        monitor="eiger",
        color_map="magma",
        color_bar="full",
        downsample=True,
        opacity=1.0,
        vrange=None,
    )


def test_image_toolbar_drag_mode_action_triggered(image_widget, qtbot):
    action_drag = image_widget.toolbar.widgets["drag_mode"].action
    action_rectangle = image_widget.toolbar.widgets["rectangle_mode"].action
    action_drag.trigger()
    assert action_drag.isChecked() == True
    assert action_rectangle.isChecked() == False


def test_image_toolbar_rectangle_mode_action_triggered(image_widget, qtbot):
    action_drag = image_widget.toolbar.widgets["drag_mode"].action
    action_rectangle = image_widget.toolbar.widgets["rectangle_mode"].action
    action_rectangle.trigger()
    assert action_drag.isChecked() == False
    assert action_rectangle.isChecked() == True


def test_image_toolbar_auto_range(image_widget, mock_image):
    action = image_widget.toolbar.widgets["auto_range"].action
    action.trigger()
    image_widget._image.set_auto_range.assert_called_once_with(True, "xy")


def test_image_toolbar_enable_mouse_pan_mode(qtbot, image_widget):
    action_drag = image_widget.toolbar.widgets["drag_mode"].action
    action_rectangle = image_widget.toolbar.widgets["rectangle_mode"].action

    mock_view_box = MagicMock()
    image_widget._image.plot_item.getViewBox = MagicMock(return_value=mock_view_box)

    image_widget.enable_mouse_pan_mode()

    assert action_drag.isChecked() == True
    assert action_rectangle.isChecked() == False
    mock_view_box.setMouseMode.assert_called_once_with(pg.ViewBox.PanMode)


def test_image_toolbar_auto_range_image(image_widget, mock_image):
    action = image_widget.toolbar.widgets["auto_range_image"].action
    action.trigger()
    assert action.isChecked() == False
    image_widget._image.set_autorange.assert_called_once_with(False)


def test_image_toolbar_FFT(image_widget, mock_image):
    action = image_widget.toolbar.widgets["FFT"].action
    action.trigger()
    assert action.isChecked() == True
    image_widget._image.set_fft.assert_called_once_with(True, None)


def test_image_toolbar_log(image_widget, mock_image):
    action = image_widget.toolbar.widgets["log"].action
    action.trigger()
    assert action.isChecked() == True
    image_widget._image.set_log.assert_called_once_with(True, None)


def test_image_toggle_transpose(image_widget, mock_image):
    action = image_widget.toolbar.widgets["transpose"].action
    action.trigger()
    assert action.isChecked() == True
    image_widget._image.set_transpose.assert_called_once_with(True, None)


def test_image_toolbar_rotation(image_widget, mock_image):
    action_left = image_widget.toolbar.widgets["rotate_left"].action
    action_right = image_widget.toolbar.widgets["rotate_right"].action

    action_left.trigger()
    image_widget._image.set_rotation(1, None)
    action_right.trigger()
    image_widget._image.set_rotation(2, None)

    action_right.trigger()
    image_widget._image.set_rotation(1, None)


###################################
# Wrapper methods for ImageShow
###################################


def test_image_set_image(image_widget, mock_image):
    image_widget.image(monitor="image")
    image_widget._image.image.assert_called_once_with(
        monitor="image",
        color_map="magma",
        color_bar="full",
        downsample=True,
        opacity=1.0,
        vrange=None,
    )


def test_image_vrange(image_widget, mock_image):
    image_widget.set_vrange(0, 1)
    image_widget._image.set_vrange.assert_called_once_with(0, 1, None)


def test_image_set_color_map(image_widget, mock_image):
    image_widget.set_color_map("viridis")
    image_widget._image.set_color_map.assert_called_once_with("viridis", None)


def test_image_widget_set_title(image_widget, mock_image):
    image_widget.set_title("Title Label")
    image_widget._image.set_title.assert_called_once_with("Title Label")


def test_image_widget_set_x_label(image_widget, mock_image):
    image_widget.set_x_label("X Label")
    image_widget._image.set_x_label.assert_called_once_with("X Label")


def test_image_widget_set_y_label(image_widget, mock_image):
    image_widget.set_y_label("Y Label")
    image_widget._image.set_y_label.assert_called_once_with("Y Label")


def test_image_widget_set_x_scale(image_widget, mock_image):
    image_widget.set_x_scale("linear")
    image_widget._image.set_x_scale.assert_called_once_with("linear")


def test_image_widget_set_y_scale(image_widget, mock_image):
    image_widget.set_y_scale("log")
    image_widget._image.set_y_scale.assert_called_once_with("log")


def test_image_widget_set_x_lim(image_widget, mock_image):
    image_widget.set_x_lim((0, 10))
    image_widget._image.set_x_lim.assert_called_once_with((0, 10))


def test_image_widget_set_y_lim(image_widget, mock_image):
    image_widget.set_y_lim((0, 10))
    image_widget._image.set_y_lim.assert_called_once_with((0, 10))


def test_image_widget_set_grid(image_widget, mock_image):
    image_widget.set_grid(True, False)
    image_widget._image.set_grid.assert_called_once_with(True, False)


def test_image_widget_lock_aspect_ratio(image_widget, mock_image):
    image_widget.lock_aspect_ratio(True)
    image_widget._image.lock_aspect_ratio.assert_called_once_with(True)


def test_image_widget_export(image_widget, mock_image):
    image_widget.export()
    image_widget._image.export.assert_called_once()
