# pylint: disable=invalid-unary-operand-type
import numpy as np
from .test_composite import create_cube_verts
from .coordinate_manager import CoordinateManager


def test_coordinate_manager_forward():
    cube_v = create_cube_verts([1.0, 0.0, 0.0], 4.0)
    cube_floor_point = np.array([3.0, 0.0, 2.0])  # as lace.mesh.floor_point

    coordinate_manager = CoordinateManager()
    coordinate_manager.tag_as("source")
    coordinate_manager.translate(-cube_floor_point)
    coordinate_manager.scale(2)
    coordinate_manager.tag_as("floored_and_scaled")
    coordinate_manager.translate(np.array([0.0, -4.0, 0.0]))
    coordinate_manager.tag_as("centered_at_origin")

    coordinate_manager.source = cube_v

    floored_and_scaled_v = coordinate_manager.do_transform(
        cube_v, from_tag="source", to_tag="floored_and_scaled"
    )

    # Sanity check
    np.testing.assert_array_almost_equal(cube_v[0], [1.0, 0.0, 0.0])
    np.testing.assert_array_almost_equal(cube_v[6], [5.0, 4.0, 4.0])

    np.testing.assert_array_almost_equal(floored_and_scaled_v[0], [-4.0, 0.0, -4.0])
    np.testing.assert_array_almost_equal(floored_and_scaled_v[6], [4.0, 8.0, 4.0])

    centered_at_origin_v_1 = coordinate_manager.do_transform(
        cube_v, from_tag="source", to_tag="centered_at_origin"
    )
    centered_at_origin_v_2 = coordinate_manager.do_transform(
        floored_and_scaled_v, from_tag="floored_and_scaled", to_tag="centered_at_origin"
    )

    np.testing.assert_array_almost_equal(centered_at_origin_v_1[0], [-4.0, -4.0, -4.0])
    np.testing.assert_array_almost_equal(centered_at_origin_v_1[6], [4.0, 4.0, 4.0])

    np.testing.assert_array_almost_equal(centered_at_origin_v_2[0], [-4.0, -4.0, -4.0])
    np.testing.assert_array_almost_equal(centered_at_origin_v_2[6], [4.0, 4.0, 4.0])

    source_v_1 = coordinate_manager.do_transform(
        floored_and_scaled_v, from_tag="floored_and_scaled", to_tag="source"
    )
    source_v_2 = coordinate_manager.do_transform(
        centered_at_origin_v_1, from_tag="centered_at_origin", to_tag="source"
    )
    np.testing.assert_array_almost_equal(source_v_1, cube_v)
    np.testing.assert_array_almost_equal(source_v_2, cube_v)


def test_coordinate_manager_forward_with_attrs():
    cube_v = create_cube_verts([1.0, 0.0, 0.0], 4.0)
    cube_floor_point = np.array([3.0, 0.0, 2.0])  # as lace.mesh.floor_point

    coordinate_manager = CoordinateManager()
    coordinate_manager.tag_as("source")
    coordinate_manager.translate(-cube_floor_point)
    coordinate_manager.scale(2)
    coordinate_manager.tag_as("floored_and_scaled")
    coordinate_manager.translate(np.array([0.0, -4.0, 0.0]))
    coordinate_manager.tag_as("centered_at_origin")

    coordinate_manager.source = cube_v

    # Sanity check
    np.testing.assert_array_almost_equal(cube_v[0], [1.0, 0.0, 0.0])
    np.testing.assert_array_almost_equal(cube_v[6], [5.0, 4.0, 4.0])

    floored_and_scaled_v = coordinate_manager.floored_and_scaled
    np.testing.assert_array_almost_equal(floored_and_scaled_v[0], [-4.0, 0.0, -4.0])
    np.testing.assert_array_almost_equal(floored_and_scaled_v[6], [4.0, 8.0, 4.0])

    centered_at_origin_v = coordinate_manager.centered_at_origin
    np.testing.assert_array_almost_equal(centered_at_origin_v[0], [-4.0, -4.0, -4.0])
    np.testing.assert_array_almost_equal(centered_at_origin_v[6], [4.0, 4.0, 4.0])

    source_v = coordinate_manager.source
    np.testing.assert_array_almost_equal(source_v, cube_v)


def test_coordinate_manager_forward_on_mesh():
    import sys

    if sys.version_info >= (3, 3):
        from unittest.mock import MagicMock
    else:
        from mock import MagicMock

    cube_v = create_cube_verts([1.0, 0.0, 0.0], 4.0)
    cube_floor_point = np.array([3.0, 0.0, 2.0])  # as lace.mesh.floor_point

    # By default a magic mock will always have any attribute it's asked for;
    # here we set the spec property so that it will not respond to having a copy method
    # when the CoodinateManager looks for it.
    cube = MagicMock(spec=["v", "other_thing"], v=cube_v, other_thing=np.array([-9.0]))

    coordinate_manager = CoordinateManager()
    coordinate_manager.tag_as("source")
    coordinate_manager.translate(-cube_floor_point)
    coordinate_manager.scale(2)
    coordinate_manager.tag_as("floored_and_scaled")
    coordinate_manager.translate(np.array([0.0, -4.0, 0.0]))
    coordinate_manager.tag_as("centered_at_origin")

    coordinate_manager.source = cube

    # Sanity check
    np.testing.assert_array_almost_equal(cube.v[0], [1.0, 0.0, 0.0])
    np.testing.assert_array_almost_equal(cube.v[6], [5.0, 4.0, 4.0])
    np.testing.assert_array_equal(cube.other_thing, [-9.0])

    floored_and_scaled = coordinate_manager.floored_and_scaled
    np.testing.assert_array_almost_equal(floored_and_scaled.v[0], [-4.0, 0.0, -4.0])
    np.testing.assert_array_almost_equal(floored_and_scaled.v[6], [4.0, 8.0, 4.0])
    np.testing.assert_array_equal(floored_and_scaled.other_thing, [-9.0])
