import numpy as np

from napari.components import Dims
from napari.layers import Shapes
from napari.layers.shapes import _shapes_key_bindings as key_bindings


def test_lock_aspect_ratio():
    # Test a single four corner rectangle
    layer = Shapes(20 * np.random.random((1, 4, 2)))
    layer._moving_coordinates = (0, 0, 0)
    layer._is_moving = True
    # need to go through the generator
    _ = list(key_bindings.hold_to_lock_aspect_ratio(layer))


def test_lock_aspect_ratio_selected_box():
    # Test a single four corner rectangle
    layer = Shapes(20 * np.random.random((1, 4, 2)))
    # select a shape
    layer._selected_box = layer.interaction_box(0)
    layer._moving_coordinates = (0, 0, 0)
    layer._is_moving = True
    # need to go through the generator
    _ = list(key_bindings.hold_to_lock_aspect_ratio(layer))


def test_lock_aspect_ratio_selected_box_zeros():
    # Test a single four corner rectangle that has zero size
    layer = Shapes(20 * np.zeros((1, 4, 2)))
    # select a shape
    layer._selected_box = layer.interaction_box(0)
    layer._moving_coordinates = (0, 0, 0)
    layer._is_moving = True
    # need to go through the generator
    _ = list(key_bindings.hold_to_lock_aspect_ratio(layer))


def test_activate_modes():
    # Test a single four corner rectangle
    layer = Shapes(20 * np.random.random((1, 4, 2)))
    # need to go through the generator
    key_bindings.activate_add_rectangle_mode(layer)
    assert layer.mode == 'add_rectangle'
    key_bindings.activate_add_ellipse_mode(layer)
    assert layer.mode == 'add_ellipse'
    key_bindings.activate_add_line_mode(layer)
    assert layer.mode == 'add_line'
    key_bindings.activate_add_polyline_mode(layer)
    assert layer.mode == 'add_polyline'
    key_bindings.activate_add_path_mode(layer)
    assert layer.mode == 'add_path'
    key_bindings.activate_add_polygon_mode(layer)
    assert layer.mode == 'add_polygon'
    key_bindings.activate_direct_mode(layer)
    assert layer.mode == 'direct'
    key_bindings.activate_select_mode(layer)
    assert layer.mode == 'select'
    key_bindings.activate_shapes_pan_zoom_mode(layer)
    assert layer.mode == 'pan_zoom'
    key_bindings.activate_vertex_insert_mode(layer)
    assert layer.mode == 'vertex_insert'
    key_bindings.activate_vertex_remove_mode(layer)
    assert layer.mode == 'vertex_remove'


def test_copy_paste():
    # Test on three four corner rectangle
    layer = Shapes(20 * np.random.random((3, 4, 2)))
    layer.mode = 'direct'

    assert len(layer.data) == 3
    assert layer._clipboard == {}
    layer.selected_data = {0, 1}

    key_bindings.copy_selected_shapes(layer)
    assert len(layer.data) == 3
    assert len(layer._clipboard) > 0

    key_bindings.paste_shape(layer)
    assert len(layer.data) == 5
    assert len(layer._clipboard) > 0


def test_select_shapes_in_slice():
    # Test on three four corner rectangle
    data = np.array(
        [
            [[0, 0], [0, 10], [10, 10], [10, 0]],
            [[20, 20], [20, 30], [30, 30], [30, 20]],
            [[40, 40], [40, 50], [50, 50], [50, 40]],
        ]
    )
    layer = Shapes(data)
    layer.mode = 'direct'

    assert len(layer.data) == 3
    assert len(layer.selected_data) == 0

    key_bindings.select_shapes_in_slice(layer)
    assert len(layer.selected_data) == 3

    # Calling it again should deselect all
    key_bindings.select_shapes_in_slice(layer)
    assert len(layer.selected_data) == 0


def test_select_shapes_in_slice_3d():
    """Test select all shapes in a 3D slice."""
    data = [
        np.array([[0, 0, 0], [0, 10, 10]]),  # shape 0 on slice 0
        np.array([[1, 5, 5], [1, 15, 15]]),  # shape 1 on slice 1
        np.array([[0, 20, 20], [0, 30, 30]]),  # shape 2 on slice 0
    ]
    layer = Shapes(data, shape_type='line')
    layer.mode = 'select'

    # view slice 0
    layer._slice_dims(
        Dims(
            ndim=3,
            ndisplay=2,
            range=((0, 2, 1), (0, 40, 1), (0, 40, 1)),
            point=(0, 0, 0),
        )
    )

    # select all shapes on slice 0
    key_bindings.select_shapes_in_slice(layer)

    # Check that shapes 0 and 2 are selected
    assert layer.selected_data == {0, 2}

    # Check that an interaction box is created
    assert layer._selected_box is not None

    # Check that get_status doesn't crash
    status = layer.get_status(position=(0, 10, 10))
    assert isinstance(status, dict)


def test_delete():
    # Test on three four corner rectangle
    layer = Shapes(20 * np.random.random((3, 4, 2)))
    layer.mode = 'direct'

    assert len(layer.data) == 3
    layer.selected_data = {0, 1}

    key_bindings.delete_selected_shapes(layer)
    assert len(layer.data) == 1


def test_finish():
    # Test on three four corner rectangle
    layer = Shapes(20 * np.random.random((3, 4, 2)))
    key_bindings.finish_drawing_shape(layer)
