#  Copyright (c) 2021, Manfred Moitzi
#  License: MIT License

import pytest
import ezdxf
from ezdxf.disassemble import recursive_decompose


@pytest.fixture(scope="module")
def doc():
    d = ezdxf.new()
    l0 = d.blocks.new("L0")
    build_level_0(l0)
    l1 = d.blocks.new("L1")
    build_nesting_level_1(l1)
    return d


def build_level_0(l0):
    # Block of 4 lines in 4 different colors
    l0.add_line((1, -1), (1, 1), dxfattribs={"color": 1})
    l0.add_line((1, 1), (-1, 1), dxfattribs={"color": 2})
    l0.add_line((-1, 1), (-1, -1), dxfattribs={"color": 3})
    l0.add_line((-1, -1), (1, -1), dxfattribs={"color": 4})


def scale(sx, sy, sz):
    return {
        "xscale": sx,
        "yscale": sy,
        "zscale": sz,
    }


def build_nesting_level_1(l1, name="L0"):
    l1.add_blockref(name, (0, 0), dxfattribs=scale(1, 1, 1))
    l1.add_blockref(name, (3, 0), dxfattribs=scale(-1, 1, 1))
    l1.add_blockref(name, (6, 0), dxfattribs=scale(1, -1, 1))
    l1.add_blockref(name, (9, 0), dxfattribs=scale(-1, -1, 1))
    l1.add_blockref(name, (0, 3), dxfattribs=scale(1, 1, -1))
    l1.add_blockref(name, (3, 3), dxfattribs=scale(-1, 1, -1))
    l1.add_blockref(name, (6, 3), dxfattribs=scale(1, -1, -1))
    l1.add_blockref(name, (9, 3), dxfattribs=scale(-1, -1, -1))


def count(doc, block_names) -> int:
    count = 1
    for name in block_names:
        block = doc.blocks.get(name)
        count *= len(block)
    return count


def test_decompose_block_level_0(doc):
    l0 = doc.blocks.get("L0")
    result = list(recursive_decompose(l0))
    assert len(result) == count(doc, ["L0"])


REFLECTIONS = [(1, 1, 1), (-1, 1, 1), (1, -1, 1), (1, 1, -1)]
NAMES = [
    "normal",
    "reflect-x",
    "reflect-y",
    "reflect-z",
]


@pytest.mark.parametrize("sx,sy,sz", REFLECTIONS, ids=NAMES)
def test_decompose_block_reference_level_0(doc, sx, sy, sz):
    msp = doc.modelspace()
    msp.delete_all_entities()
    msp.add_blockref("L0", (0, 0), dxfattribs=scale(sx, sy, sz))
    result = list(recursive_decompose(msp))
    assert len(result) == count(doc, ["L0"])


def test_decompose_block_level_1(doc):
    l1 = doc.blocks.get("L1")
    types = [e.dxftype() for e in recursive_decompose(l1)]
    assert len(types) == count(doc, ["L0", "L1"])
    assert set(types) == {"LINE"}, "expected only LINES"


@pytest.mark.parametrize("sx,sy,sz", REFLECTIONS, ids=NAMES)
def test_decompose_block_reference_level_1(doc, sx, sy, sz):
    msp = doc.modelspace()
    msp.delete_all_entities()
    msp.add_blockref("L1", (0, 0), dxfattribs=scale(sx, sy, sz))
    types = [e.dxftype() for e in recursive_decompose(msp)]
    assert len(types) == count(doc, ["L0", "L1"])
    assert set(types) == {"LINE"}, "expected only LINES"


def test_decompose_minsert_level_1(doc):
    nrows = 2
    ncols = 2
    expected_count = count(doc, ["L0", "L1"]) * nrows * ncols

    msp = doc.modelspace()
    msp.delete_all_entities()
    msp.add_blockref(
        "L1",
        (0, 0),
        dxfattribs={
            "row_count": nrows,
            "row_spacing": 5,
            "column_count": ncols,
            "column_spacing": 5,
        },
    )
    types = [e.dxftype() for e in recursive_decompose(msp)]
    assert len(types) == expected_count
    assert set(types) == {"LINE"}, "expected only LINES"


if __name__ == "__main__":
    pytest.main([__file__])
