# Copyright (c) 2018-2020, Manfred Moitzi
# License: MIT License
import pytest
from math import radians
from ezdxf.math import Vec3, BoundingBox
from ezdxf.render.forms import cube
from ezdxf.render.mesh import (
    MeshVertexMerger,
    MeshBuilder,
    MeshTransformer,
    MeshAverageVertexMerger,
)
from ezdxf.addons import SierpinskyPyramid
from ezdxf.layouts import VirtualLayout


def test_vertex_merger_indices():
    merger = MeshVertexMerger()
    indices = merger.add_vertices([(1, 2, 3), (4, 5, 6)])
    indices2 = merger.add_vertices([(1, 2, 3), (4, 5, 6)])
    assert indices == indices2


def test_vertex_merger_vertices():
    merger = MeshVertexMerger()
    merger.add_vertices([(1, 2, 3), (4, 5, 6)])
    merger.add_vertices([(1, 2, 3), (4, 5, 6)])
    assert merger.vertices == [(1, 2, 3), (4, 5, 6)]


def test_vertex_merger_index_of():
    merger = MeshVertexMerger()
    merger.add_vertices([(1, 2, 3), (4, 5, 6)])
    assert merger.index((1, 2, 3)) == 0
    assert merger.index((4, 5, 6)) == 1
    with pytest.raises(IndexError):
        merger.index((7, 8, 9))


def test_average_vertex_merger_indices():
    merger = MeshAverageVertexMerger()
    indices = merger.add_vertices([(1, 2, 3), (4, 5, 6)])
    indices2 = merger.add_vertices([(1, 2, 3), (4, 5, 6)])
    assert indices == indices2


def test_average_vertex_merger_vertices():
    merger = MeshAverageVertexMerger()
    merger.add_vertices([(1, 2, 3), (4, 5, 6)])
    merger.add_vertices([(1, 2, 3), (4, 5, 6)])
    assert merger.vertices == [(1, 2, 3), (4, 5, 6)]


def test_average_vertex_merger_index_of():
    merger = MeshAverageVertexMerger()
    merger.add_vertices([(1, 2, 3), (4, 5, 6)])
    assert merger.index((1, 2, 3)) == 0
    assert merger.index((4, 5, 6)) == 1
    with pytest.raises(IndexError):
        merger.index((7, 8, 9))


def test_mesh_builder(msp):
    pyramid = SierpinskyPyramid(level=4, sides=3)
    pyramid.render(msp, merge=False)
    meshes = msp.query("MESH")
    assert len(meshes) == 256


def test_vertex_merger():
    pyramid = SierpinskyPyramid(level=4, sides=3)
    faces = pyramid.faces()
    mesh = MeshVertexMerger()
    for vertices in pyramid:
        mesh.add_mesh(vertices=vertices, faces=faces)
    assert len(mesh.vertices) == 514
    assert len(mesh.faces) == 1024


def test_average_vertex_merger():
    pyramid = SierpinskyPyramid(level=4, sides=3)
    faces = pyramid.faces()
    mesh = MeshAverageVertexMerger()
    for vertices in pyramid:
        mesh.add_mesh(vertices=vertices, faces=faces)
    assert len(mesh.vertices) == 514
    assert len(mesh.faces) == 1024


REGULAR_FACE = Vec3.list([(0, 0, 0), (1, 0, 1), (1, 1, 1), (0, 1, 0)])
IRREGULAR_FACE = Vec3.list([(0, 0, 0), (1, 0, 1), (1, 1, 0), (0, 1, 0)])


def test_has_none_planar_faces():
    mesh = MeshBuilder()
    mesh.add_face(REGULAR_FACE)
    assert mesh.has_none_planar_faces() is False
    mesh.add_face(IRREGULAR_FACE)
    assert mesh.has_none_planar_faces() is True


def test_scale_mesh():
    mesh = cube(center=False)
    mesh.scale(2, 3, 4)
    bbox = BoundingBox(mesh.vertices)
    assert bbox.extmin.isclose((0, 0, 0))
    assert bbox.extmax.isclose((2, 3, 4))


def test_rotate_x():
    mesh = cube(center=False)
    mesh.rotate_x(radians(90))
    bbox = BoundingBox(mesh.vertices)
    assert bbox.extmin.isclose((0, -1, 0))
    assert bbox.extmax.isclose((1, 0, 1))


@pytest.fixture
def msp():
    return VirtualLayout()


@pytest.fixture(scope="module")
def cube_polyface():
    layout = VirtualLayout()
    p = layout.add_polyface()
    p.append_faces(cube().faces_as_vertices())
    return p


def test_from_empty_polyface(msp):
    empty_polyface = msp.add_polyface()
    b = MeshBuilder.from_polyface(empty_polyface)
    assert len(b.vertices) == 0
    assert len(b.faces) == 0


def test_from_cube_polyface(cube_polyface):
    b = MeshBuilder.from_polyface(cube_polyface)
    assert len(b.vertices) == 24  # unoptimized mesh builder
    assert len(b.faces) == 6


def test_render_polyface(cube_polyface, msp):
    t = MeshTransformer.from_polyface(cube_polyface)
    assert len(t.vertices) == 24  # unoptimized mesh builder
    assert len(t.faces) == 6
    t.render_polyface(msp)
    new_polyface = msp[-1]
    assert new_polyface.dxftype() == "POLYLINE"
    assert new_polyface.is_poly_face_mesh is True
    assert len(new_polyface.vertices) == 8 + 6
    assert new_polyface.vertices[0] is not cube_polyface.vertices[0]


def test_from_polymesh(msp):
    polymesh = msp.add_polymesh(size=(4, 4))
    b = MeshBuilder.from_polyface(polymesh)
    n = polymesh.dxf.n_count
    m = polymesh.dxf.m_count
    nfaces = (n - 1) * (m - 1)
    assert len(b.vertices) == nfaces * 4  # unoptimized mesh builder
    assert len(b.faces) == nfaces


def test_from_polyface_type_error(msp):
    polyline = msp.add_polyline3d([(0, 0, 0), (1, 0, 0)])
    with pytest.raises(TypeError):
        MeshBuilder.from_polyface(polyline)

    line = msp.add_line(start=(0, 0, 0), end=(1, 0, 0))
    with pytest.raises(TypeError):
        MeshBuilder.from_polyface(line)


@pytest.fixture
def polyface_181_1(msp):
    e = msp.new_entity(
        "POLYLINE",
        dxfattribs={
            "flags": 48,
            "m_count": 2,
            "n_count": 6,
        },
    )
    e.append_vertex(
        (25041.94191089287, 29272.95055566061, 0.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25020.29127589287, 29285.45055566061, 0.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25020.29127589287, 29310.45055566061, 0.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25041.94191089287, 29322.95055566061, 0.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25063.59254589287, 29310.45055566061, 0.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25063.59254589287, 29285.45055566061, 0.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25041.94191089287, 29272.95055566061, 50.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25020.29127589287, 29285.45055566061, 50.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25020.29127589287, 29310.45055566061, 50.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25041.94191089287, 29322.95055566061, 50.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25063.59254589287, 29310.45055566061, 50.0), dxfattribs={"flags": 64}
    )
    e.append_vertex(
        (25063.59254589287, 29285.45055566061, 50.0), dxfattribs={"flags": 64}
    )
    return e


def test_from_polyface_182_1(polyface_181_1):
    mesh = MeshVertexMerger.from_polyface(polyface_181_1)
    assert len(mesh.vertices) == 12


@pytest.fixture
def polyface_181_2(msp):
    e = msp.new_entity(
        "POLYLINE",
        dxfattribs={
            "flags": 16,
            "m_count": 6,
            "n_count": 3,
        },
    )
    e.append_vertex(
        (16606.65151901649, 81.88147523282441, 2099.9999999999995),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16606.65151901649, 81.88147523282441, 1199.9999999999998),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16606.65151901649, 81.88147523282441, 1199.9999999999998),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16606.65151901649, 1281.8814752328244, 2099.9999999999995),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16606.65151901649, 1281.8814752328244, 1199.9999999999998),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16606.65151901649, 1281.8814752328244, 1199.9999999999998),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16626.65151901649, 1281.8814752328244, 2099.9999999999995),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16626.65151901649, 1281.8814752328244, 1199.9999999999998),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16606.65151901649, 1281.8814752328244, 1199.9999999999998),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16626.65151901649, 81.88147523282441, 2099.9999999999995),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16626.65151901649, 81.88147523282441, 1199.9999999999998),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16606.65151901649, 81.88147523282441, 1199.9999999999998),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16626.65151901649, 81.88147523282441, 2099.9999999999995),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16626.65151901649, 81.88147523282441, 2099.9999999999995),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16606.65151901649, 81.88147523282441, 2099.9999999999995),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16626.65151901649, 1281.8814752328244, 2099.9999999999995),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16626.65151901649, 1281.8814752328244, 2099.9999999999995),
        dxfattribs={"flags": 64},
    )
    e.append_vertex(
        (16606.65151901649, 1281.8814752328244, 2099.9999999999995),
        dxfattribs={"flags": 64},
    )
    return e


def test_from_polyface_182_2(polyface_181_2):
    mesh = MeshVertexMerger.from_polyface(polyface_181_2)
    assert len(mesh.vertices) == 8
