from pytest import raises
from pathlib import Path
from json import dump, load, dumps, loads
from shutil import copyfile

from rougail_tests.utils import config_to_dict
from rougail import Rougail, RougailConfig
from rougail.error import DictConsistencyError


def type_variable(test_name, namespace=False):
    tmp_file = Path("tmp/tiramisu.py")
    tmp_file.parent.mkdir(exist_ok=True)
    tmp_file.unlink(missing_ok=True)
    #
    result = Path('tests/types/result') / test_name
    result.mkdir(parents=True, exist_ok=True)
    #
    rougailconfig = RougailConfig.copy()
    rougailconfig['types'] = [f'tests/types/types/{test_name}']
    if namespace:
        rougailconfig['main_namespace'] = None
        rougailconfig['main_structural_directories'] = [f'tests/types/structures/{ test_name }']
        tiramisu_file = result / "namespace_tiramisu.py"
        variables_file = result / "namespace_variables.json"
        variables_file_rw = result / "namespace_variables_rw.json"
    else:
        rougailconfig['main_namespace'] = 'NS1'
        rougailconfig['main_structural_directories'] = ['tests/types/structures/main']
        rougailconfig['extra_namespaces'] = {'NS2': [f'tests/types/structures/{ test_name }'],
                                             }
        tiramisu_file = result / "tiramisu.py"
        variables_file = result / "variables.json"
        variables_file_rw = result / "variables_rw.json"
    try:
        rougailconfig['tiramisu_cache'] = str(tmp_file)
    except:
        rougailconfig['cli.tiramisu_cache'] = str(tmp_file)
    rougail = Rougail(rougailconfig=rougailconfig)
    config = rougail.run()
    #
    if not tiramisu_file.is_file():
        copyfile(tmp_file, tiramisu_file)
#        tmp_file.copy(tiramisu_file)
    with tmp_file.open() as fh:
        tiramisu = fh.read()
    with tiramisu_file.open() as fh:
        loaded_tiramisu = fh.read()
    assert loaded_tiramisu == tiramisu, f"error in file {tiramisu_file}"
    tmp_file.unlink()
    #
    configuration = dict(config_to_dict(config.value.get()))
    if not variables_file.is_file():
        with variables_file.open('w') as fh:
            dump(configuration, fh, indent=4)
    with variables_file.open('r') as fh:
        loaded_configuration = load(fh)
    assert loaded_configuration == loads(dumps(configuration)), f"error in file {variables_file}"
    #
    config.property.read_write()
    configuration = dict(config_to_dict(config.value.get()))
    if not variables_file_rw.is_file():
        with variables_file_rw.open('w') as fh:
            dump(configuration, fh, indent=4)
    with variables_file_rw.open('r') as fh:
        loaded_configuration = load(fh)
    assert loaded_configuration == loads(dumps(configuration)), f"error in file {variables_file_rw}"


def test_type_variable():
    type_variable("variable")


def test_type_variable_namespace():
    type_variable("variable", namespace=True)


def test_type_variables():
    type_variable("variables")


def test_type_variables_namespace():
    type_variable("variables", namespace=True)


def test_type_family():
    type_variable("family")


def test_type_family_namespace():
    type_variable("family", namespace=True)


def test_type_family_redefine():
    type_variable("family_redefine")


def test_type_family_redefine_namespace():
    type_variable("family_redefine", namespace=True)


def test_type_family_redefine_2():
    with raises(DictConsistencyError) as err:
        type_variable("family_redefine_family_types")
    assert err.value.errno == 64


def test_type_family_subfamily():
    type_variable("family_subfamily")


def test_type_family_subfamily_namespace():
    type_variable("family_subfamily", namespace=True)


def test_type_variable_hidden():
    type_variable("variable_hidden")


def test_type_variable_hidden_namespace():
    type_variable("variable_hidden", namespace=True)


def test_type_dynfamily():
    type_variable("family_dynfamily")


def test_type_dynfamily_namespace():
    type_variable("family_dynfamily", namespace=True)


def test_type_family_subfamily_add():
    type_variable("family_subfamily_add")


def test_type_family_subfamily_add_namespace():
    type_variable("family_subfamily_add", namespace=True)


def test_type_error_version():
    with raises(DictConsistencyError) as err:
        type_variable("error_version")
    assert err.value.errno == 27


def test_type_family_name_description():
    type_variable("family_name_description")


def test_type_leadership():
    type_variable("leadership")


def test_type_leadership_namespace():
    type_variable("leadership", namespace=True)


def test_type_error_redefine():
    type_variable("error_variable_redefine", namespace=True)


def test_type_secret():
    type_variable("secret_manager")


def test_type_secret_namespace():
    type_variable("secret_manager", namespace=True)


def test_type_family_secret():
    type_variable("family_secret_manager")


def test_type_family_secret_namespace():
    type_variable("family_secret_manager", namespace=True)


def test_type_family_redefine_type():
    type_variable("family_redefine_type")


def test_type_family_redefine_type_namespace():
    type_variable("family_redefine_type", namespace=True)


def test_type_family_param():
    type_variable("family_param")


def test_type_family_param_namespace():
    type_variable("family_param", namespace=True)
