import itertools
from os.path import join

import numpy as np
import numpy.testing as npt
import pytest

from fury import actor, pick, ui, window
from fury.data import DATA_DIR
from fury.testing import assert_greater


def test_fake():
    pass


# @pytest.mark.skipif(skip_osx, reason="This test does not work on macOS + "
#                                      "Travis. It works on a local machine"
#                                      " with 3 different version of VTK. There"
#                                      " are 2 problems to check: Travis macOS"
#                                      " vs Azure macOS and an issue with"
#                                      " vtkAssembly + actor opacity.")


@pytest.mark.skipif(
    True,
    reason="Pytests triggers segfault here that "
    "cannot be replicated by individual"
    "tests",
)
def test_picking_manager():
    xyz = 10 * np.random.rand(100, 3)
    colors = np.random.rand(100, 4)
    radii = np.random.rand(100) + 0.5

    scene = window.Scene()

    sphere_actor = actor.sphere(centers=xyz, colors=colors, radii=radii)

    scene.add(sphere_actor)

    showm = window.ShowManager(
        scene, size=(900, 768), reset_camera=False, order_transparent=True
    )

    tb = ui.TextBlock2D(bold=True)

    # use itertools to avoid global variables
    counter = itertools.count()

    pickm = pick.PickingManager()

    record_indices = {"vertex_indices": [], "face_indices": [], "xyz": [], "actor": []}

    def timer_callback(_obj, _event):
        cnt = next(counter)
        tb.message = "Let's count up to 15 and exit :" + str(cnt)
        showm.scene.azimuth(0.05 * cnt)
        # sphere_actor.GetProperty().SetOpacity(cnt/100.)
        if cnt % 10 == 0:
            # pick at position
            info = pickm.pick((900 / 2, 768 / 2), scene)
            record_indices["vertex_indices"].append(info["vertex"])
            record_indices["face_indices"].append(info["face"])
            record_indices["xyz"].append(info["xyz"])
            record_indices["actor"].append(info["actor"])

        showm.render()
        if cnt == 15:
            showm.exit()

    scene.add(tb)

    # Run every 200 milliseconds
    showm.add_timer_callback(True, 200, timer_callback)
    showm.start()

    assert_greater(np.sum(np.array(record_indices["vertex_indices"])), 1)
    assert_greater(np.sum(np.array(record_indices["face_indices"])), 1)

    for ac in record_indices["actor"]:
        if ac is not None:
            npt.assert_equal(ac is sphere_actor, True)

    assert_greater(np.sum(np.abs(np.diff(np.array(record_indices["xyz"]), axis=0))), 0)


def _get_three_cubes():
    centers = 0.5 * np.array([[0, 0, 0], [100, 0, 0], [200, 0, 0.0]])
    colors = np.array([[0.8, 0, 0], [0, 0.8, 0], [0, 0, 0.8]])
    radii = 0.1 * np.array([50, 100, 150.0])
    return centers, colors, radii


@pytest.mark.skipif(
    True,
    reason="Pytests triggers segfault here that "
    "cannot be replicated by individual"
    "tests",
)
def test_selector_manager():
    centers, colors, radii = _get_three_cubes()

    scene = window.Scene()

    cube_actor = actor.cube(centers, directions=(1, 0, 2), colors=colors, scales=radii)

    pts = 100 * (np.random.rand(100, 3) - 0.5) + np.array([20, 0, 0.0])
    pts_actor = actor.dots(pts, dot_size=10)

    rgb = 255 * np.ones((400, 400, 3), dtype=np.uint8)
    tex_actor = actor.texture(rgb)

    scene.add(cube_actor)
    scene.add(pts_actor)
    scene.add(tex_actor)

    showm = window.ShowManager(
        scene, size=(900, 768), reset_camera=False, order_transparent=True
    )

    tb = ui.TextBlock2D(bold=True)

    # use itertools to avoid global variables
    counter = itertools.count()

    selm = pick.SelectionManager(select="faces")

    selm.selectable_off([tex_actor])
    selm.selectable_on([tex_actor])
    selm.selectable_off([tex_actor])

    def timer_callback(_obj, _event):
        cnt = next(counter)
        tb.message = "Let's count up to 15 and exit :" + str(cnt)
        if cnt % 10 == 0:
            # select large area
            info_plus = selm.select((900 // 2, 768 // 2), scene, (30, 30))
            for info in info_plus.keys():
                if info_plus[info]["actor"] in [cube_actor, pts_actor]:
                    npt.assert_(True)
                else:
                    npt.assert_(False)
            # select single pixel
            info_ = selm.pick((900 // 2, 768 // 2), scene)
            if info_["actor"] in [cube_actor, pts_actor]:
                npt.assert_(True)
            else:
                npt.assert_(False)

        showm.render()
        if cnt == 15:
            showm.exit()
            pass

    scene.add(tb)

    # Run every 200 milliseconds
    showm.add_timer_callback(True, 200, timer_callback)
    showm.start()


@pytest.mark.skipif(
    True,
    reason="Pytests triggers segfault here that "
    "cannot be replicated by individual"
    "tests",
)
def test_hover_selection_faces(recording=False):
    # simply hover going through blue, green, red

    recording_filename = join(DATA_DIR, "selector_faces.log.gz")

    centers, colors, radii = _get_three_cubes()

    scene = window.Scene()

    cube_actor = actor.cube(centers, directions=(1, 0, 0), colors=colors, scales=radii)

    scene.add(cube_actor)

    selm = pick.SelectionManager(select="faces")

    showm = window.ShowManager(
        scene, size=(900, 768), reset_camera=False, order_transparent=True
    )

    global track_objects
    track_objects = []

    def hover_callback(_obj, _event):
        global track_objects
        event_pos = selm.event_position(showm.iren)
        info = selm.select(event_pos, showm.scene, (10, 10))
        selected_faces = info[0]["face"]
        if selected_faces is not None:
            track_objects.append(selected_faces[0] // 12)
        showm.render()

    showm.add_iren_callback(hover_callback)

    if recording:
        showm.record_events_to_file(recording_filename)

    else:
        showm.play_events_from_file(recording_filename)

    track_objects = set(track_objects)

    npt.assert_({0, 1, 2}.issubset(track_objects))
    del track_objects


@pytest.mark.skipif(
    True,
    reason="Pytests triggers segfault here that "
    "cannot be replicated by individual"
    "tests",
)
def test_hover_selection_vertices(recording=False):
    # simply hover through blue, green, red cubes
    # close to any vertices of each of the cubes

    recording_filename = join(DATA_DIR, "selector_vertices.log.gz")

    centers, colors, radii = _get_three_cubes()

    scene = window.Scene()

    cube_actor = actor.cube(centers, directions=(1, 0, 0), colors=colors, scales=radii)

    scene.add(cube_actor)

    selm = pick.SelectionManager(select="vertices")

    showm = window.ShowManager(
        scene, size=(900, 768), reset_camera=False, order_transparent=True
    )

    global track_objects2
    track_objects2 = []

    def hover_callback(_obj, _event):
        global track_objects2
        event_pos = selm.event_position(showm.iren)
        info = selm.select(event_pos, showm.scene, (100, 100))
        selected_triangles = info[0]["vertex"]
        if selected_triangles is not None:
            track_objects2.append(selected_triangles[0] // 8)
        showm.render()

    showm.add_iren_callback(hover_callback)

    if recording:
        showm.record_events_to_file(recording_filename)

    else:
        showm.play_events_from_file(recording_filename)

    track_obj = set(track_objects2)

    npt.assert_(track_obj.issubset({0, 1, 2}))
    del track_objects2


@pytest.mark.skipif(
    True,
    reason="Pytests triggers segfault here that "
    "cannot be replicated by individual"
    "tests",
)
def test_hover_selection_actors_only(recording=False):
    # simply hover going through blue, green, red cubes

    recording_filename = join(DATA_DIR, "selector_actors.log.gz")

    centers, colors, radii = _get_three_cubes()

    scene = window.Scene()

    cube_actor = actor.cube(centers, directions=(1, 0, 0), colors=colors, scales=radii)

    scene.add(cube_actor)

    selm = pick.SelectionManager(select="actors")

    showm = window.ShowManager(
        scene, size=(900, 768), reset_camera=False, order_transparent=True
    )

    def hover_callback(_obj, _event):
        event_pos = selm.event_position(showm.iren)
        info = selm.pick(event_pos, showm.scene)
        selected_actor = info["actor"]
        # print(id(selected_actor), id(cube_actor))
        if selected_actor is not None:
            npt.assert_equal(id(cube_actor), id(selected_actor))
        showm.render()

    showm.add_iren_callback(hover_callback)

    if recording:
        showm.record_events_to_file(recording_filename)

    else:
        showm.play_events_from_file(recording_filename)


if __name__ == "__main__":
    npt.run_module_suite()
