import copy

from utils_ak.numeric import *
from utils_ak.simple_vector import *


from utils_ak.block_tree.parallelepiped_block import ParallelepipedBlock
from utils_ak.block_tree.block import Block
from utils_ak.block_tree.validation import validate_disjoint_by_axis
from utils_ak.block_tree.pushers.pushers import simple_push

from loguru import logger


def dummy_push(
    parent, block, validator, max_tries=24, start_from="last_end", iter_props=None
):
    axis = parent.props["axis"]

    if is_int_like(start_from):
        cur_start = int(float(start_from))
    elif start_from == "beg":
        cur_start = block.props["x_rel"][axis]
    else:
        if not parent.children:
            cur_start = 0
        else:
            if start_from == "last_beg":
                cur_start = max(
                    [child.props["x_rel"][axis] for child in parent.children]
                )
            elif start_from == "last_end":
                cur_start = max(
                    [
                        (child.props["x_rel"] + child.size)[axis]
                        for child in parent.children
                    ]
                )
            else:
                raise Exception("Unknown beg type")

    iter_props = iter_props or [{}]

    cur_x = cast_simple_vector(block.n_dims)

    cur_try = 0

    # logger.debug('Inserting blocks', parent=parent.props['cls'], block=block.props['cls'])

    while cur_try < max_tries:
        dispositions = []
        for props in iter_props:
            # try to push
            props = copy.deepcopy(props)
            cur_x[axis] = cur_start
            props["x"] = cur_x
            # logger.debug('Trying to push from ', cur_start=cur_start)
            res = simple_push(parent, block, validator=validator, new_props=props)

            if isinstance(res, Block):
                # success
                # logger.debug('Success')
                return block
            else:
                assert isinstance(res, dict)

                if "disposition" in res:
                    dispositions.append(res["disposition"])

        disposition = min(dispositions) if len(dispositions) == len(iter_props) else 1
        # logger.debug('Disposition', disposition=disposition)
        cur_start += disposition
    raise Exception("Failed to push element")


def test_dummy_push():
    from utils_ak.loguru import configure_loguru_stdout

    configure_loguru_stdout()

    def brute_validator(parent, block):
        for c in parent.children:
            validate_disjoint_by_axis(c, block, axis=parent.props["axis"])

    logger.debug("Dummy push test")
    root = ParallelepipedBlock("root", n_dims=1, x=[2], axis=0)
    a = ParallelepipedBlock("a", n_dims=1, size=[4], axis=0)
    b = ParallelepipedBlock("b", n_dims=1, size=[3], axis=0)
    dummy_push(root, a, brute_validator)
    dummy_push(root, b, brute_validator, start_from=0)
    logger.debug("Root", root=root)


if __name__ == "__main__":
    test_dummy_push()
