from pytest import raises
import logging

from rougail import Rougail, RougailConfig
from rougail.error import DictConsistencyError
from tiramisu.error import ConflictError

from rougail_tests.utils import config_to_dict
from rougail.config import get_rougail_config

logger = logging.getLogger()
logger.setLevel(logging.INFO)


def test_mode_unconfigured_mode():
    # default variable mode is not in modes_level
    rougailconfig = get_rougail_config(
        backward_compatibility=False, add_extra_options=False
    )
    rougailconfig['main_structural_directories'] = ['tests/personalize_mode/dictionary']
    eolobj = Rougail(rougailconfig=rougailconfig)
    with raises(DictConsistencyError) as err:
        eolobj.converted.annotate()
    assert err.value.errno == 71


def test_mode_invalid_default():
    # default variable mode is not in modes_level
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_structural_directories'] = ['tests/personalize_mode/dictionary']
    rougailconfig['modes_level'] = ['level1', 'level2']
    with raises(ValueError) as err:
        rougailconfig['default_family_mode'] = 'level3'


def test_mode_invalid_default_family():
    # default family mode is not in modes_level
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_structural_directories'] = ['tests/personalize_mode/dictionary']
    rougailconfig['modes_level'] = ['level1', 'level2']
    with raises(ValueError) as err:
        rougailconfig['default_variable_mode'] = 'level3'


def test_personalize_mode():
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_structural_directories'] = ['tests/personalize_mode/dictionary']
    rougailconfig['modes_level'] = ['level1', 'level2']
    rougailconfig['default_variable_mode'] = 'level1'
    rougailconfig['default_family_mode'] = 'level1'
    try:
        rougailconfig['tiramisu_cache'] = None
    except:
        rougailconfig['cli.tiramisu_cache'] = None
    eolobj = Rougail(rougailconfig=rougailconfig)
    eolobj.run()


def test_personalize_mode_unknown():
    # a variable has an unknown mode
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_structural_directories'] = ['tests/personalize_mode/dictionary']
    rougailconfig['modes_level'] = ['level1']
    rougailconfig['default_variable_mode'] = 'level1'
    rougailconfig['default_family_mode'] = 'level1'
    eolobj = Rougail(rougailconfig=rougailconfig)
    with raises(DictConsistencyError) as err:
        eolobj.converted.annotate()
    assert err.value.errno == 71


def test_personalize_mode_unknown2():
    # a variable has an unknown mode
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_structural_directories'] = ['tests/personalize_mode_without_family/dictionary']
    rougailconfig['main_namespace'] = None
    rougailconfig['modes_level'] = ['level1']
    rougailconfig['default_variable_mode'] = 'level1'
    rougailconfig['default_family_mode'] = 'level1'
    eolobj = Rougail(rougailconfig=rougailconfig)
    with raises(DictConsistencyError) as err:
        eolobj.converted.annotate()
    assert err.value.errno == 71


def test_personalize_annotate_twice():
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_structural_directories'] = ['tests/personalize_mode/dictionary']
    rougailconfig['modes_level'] = ['level1', 'level2']
    rougailconfig['default_variable_mode'] = 'level1'
    rougailconfig['default_family_mode'] = 'level1'
    eolobj = Rougail(rougailconfig=rougailconfig)
    eolobj.converted.annotate()
    with raises(DictConsistencyError) as err:
        eolobj.converted.annotate()
    assert err.value.errno == 85


def test_option_params():
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_structural_directories'] = ['tests/default_option_params/structure']
    rougailconfig["define_default_params"] = True
    rougailconfig["default_params.unix_filename.test_existence"] = True
    eolobj = Rougail(rougailconfig=rougailconfig)
    with raises(ValueError):
        eolobj.run()
    eolobj = Rougail(rougailconfig=rougailconfig)
    with raises(ValueError):
        eolobj.run()
    rougailconfig["default_params.unix_filename.test_existence"] = False
    eolobj = Rougail(rougailconfig=rougailconfig)
    eolobj.run()


def test_namespace():
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_namespace'] = 'NS1'
    rougailconfig['main_structural_directories'] = ['tests/namespace']
    rougailconfig['extra_namespaces'] = {'NS2': ['tests/namespace'],
                                           'NS3': ['tests/namespace'],
                                           }
    eolobj = Rougail(rougailconfig=rougailconfig)
    assert dict(config_to_dict(eolobj.run().value.get())) ==   {'ns1.var1': 'NS1',
                                                                'ns1.var2': 'NS1',
                                                                'ns2.var1': 'NS2',
                                                                'ns2.var2': 'NS2',
                                                                'ns3.var1': 'NS3',
                                                                'ns3.var2': 'NS3'}
#
#
#def test_duplicate_0():
#    rougailconfig = RougailConfig.copy()
#    rougailconfig['main_namespace'] = None
#    rougailconfig['main_structural_directories'] = ['tests/duplicates/0/']
#    eolobj = Rougail(rougailconfig=rougailconfig)
#    cfg = eolobj.run()
#    cfg.value.get()
#    cfg.option('od.od_val1').value.get()
#    cfg.option('od.od_val2').value.get()


def test_duplicate_1():
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_namespace'] = None
    rougailconfig['main_structural_directories'] = ['tests/duplicates/1/']
    eolobj = Rougail(rougailconfig=rougailconfig)
    cfg = eolobj.run()
    with raises(ConflictError):
        cfg.value.get()
    with raises(ConflictError):
        cfg.option('od.od_val').value.get()


def test_duplicate_2():
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_namespace'] = None
    rougailconfig['main_structural_directories'] = ['tests/duplicates/2/']
    eolobj = Rougail(rougailconfig=rougailconfig)
    cfg = eolobj.run()
    with raises(ConflictError):
        cfg.value.get()
    with raises(ConflictError):
        cfg.option('od.od_val').value.get()


def test_duplicate_3():
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_namespace'] = None
    rougailconfig['main_structural_directories'] = ['tests/duplicates/3/']
    eolobj = Rougail(rougailconfig=rougailconfig)
    cfg = eolobj.run()
    with raises(ConflictError):
        cfg.value.get()
    with raises(ConflictError):
        cfg.option('od.od_val').value.get()
#
#
#def test_duplicate_4():
#    rougailconfig = RougailConfig.copy()
#    rougailconfig['main_namespace'] = None
#    rougailconfig['main_structural_directories'] = ['tests/duplicates/4/']
#    eolobj = Rougail(rougailconfig=rougailconfig)
#    cfg = eolobj.run()
#    with raises(ConflictError):
#        cfg.value.get()
#    with raises(ConflictError):
#        cfg.option('od.od_val').value.get()


def test_duplicate_5():
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_namespace'] = None
    rougailconfig['main_structural_directories'] = ['tests/duplicates/5/']
    eolobj = Rougail(rougailconfig=rougailconfig)
    cfg = eolobj.run()
    with raises(ConflictError):
        cfg.value.get()
    with raises(ConflictError):
        cfg.option('od.od_val').value.get()


def test_isolated_namespace():
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_namespace'] = 'rougail'
    rougailconfig['main_structural_directories'] = ['tests/errors/00_9extra_outside/rougail/']
    rougailconfig['extra_namespaces'] = {'extra':  ['tests/errors/00_9extra_outside/extra/'],
                                         'extra2': ['tests/errors/00_9extra_outside/extra2/'],
                                         }
    rougailconfig["isolated_namespace"] = False
    eolobj = Rougail(rougailconfig=rougailconfig)
    cfg = eolobj.run()
    assert cfg.option('extra.variable').value.get() == 'no'
    assert cfg.option('extra2.variable').value.get() == 'no'


def test_shorthand():
    rougailconfig = RougailConfig.copy()
    rougailconfig['main_namespace'] = None
    rougailconfig['main_structural_directories'] = ['tests/shorthand/']
    eolobj = Rougail(rougailconfig=rougailconfig)
    cfg = eolobj.run()
    results = {"first_variable": "first_variable",
               "second_variable": "second_variable (in place)",
               "third_variable": "third_variable",
               }
    for opt in cfg:
        assert opt.description() == results[opt.name()]
