"test all types of option default values for options, add new option in a descr"
from .autopath import do_autopath
do_autopath()

import pytest
from tiramisu.setting import owners
from tiramisu.error import PropertiesOptionError, ConfigError, LeadershipError
from tiramisu import IntOption, FloatOption, StrOption, ChoiceOption, \
    BoolOption, OptionDescription, Leadership, Config, undefined, delete_session
from tiramisu.storage import list_sessions
from .config import config_type, get_config, event_loop


owners.addowner("frozenmultifollower")


def make_description():
    gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
    gcdummy = BoolOption('dummy', 'dummy', default=False)
    objspaceoption = ChoiceOption('objspace', 'Object space',
                                  ['std', 'thunk'], 'std')
    booloption = BoolOption('bool', 'Test boolean option', default=True)
    intoption = IntOption('int', 'Test int option', default=0)
    floatoption = FloatOption('float', 'Test float option', default=2.3)
    stroption = StrOption('str', 'Test string option', default="abc")
    boolop = BoolOption('boolop', 'Test boolean option op', default=True)
    wantref_option = BoolOption('wantref', 'Test requires', default=False,
                                requires=['boolop'])
    wantframework_option = BoolOption('wantframework', 'Test requires',
                                      default=False,
                                      requires=['boolop'])

    gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
    descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
                                               wantref_option, stroption,
                                               wantframework_option,
                                               intoption, boolop])
    return descr


#____________________________________________________________
# default values
@pytest.mark.asyncio
async def test_default_is_none(config_type):
    """
    Most constructors take a ``default`` argument that specifies the default
    value of the option. If this argument is not supplied the default value is
    assumed to be ``None``.
    """
    dummy1 = BoolOption('dummy1', 'doc dummy')
    dummy2 = BoolOption('dummy2', 'doc dummy')
    group = OptionDescription('group', '', [dummy1, dummy2])
    async with await Config(group) as cfg:
        cfg = await get_config(cfg, config_type)
        # so when the default value is not set, there is actually a default value
        assert await cfg.option('dummy1').value.get() is None
        assert await cfg.option('dummy2').value.get() is None
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_set_defaut_value_from_option_object():
    """Options have an available default setting and can give it back"""
    b = BoolOption("boolean", "", default=False)
    assert b.impl_getdefault() is False
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_force_default_on_freeze():
    "a frozen option wich is forced returns his default"
    dummy1 = BoolOption('dummy1', 'doc dummy', default=False, properties=('force_default_on_freeze',))
    dummy2 = BoolOption('dummy2', 'doc dummy', default=True)
    group = OptionDescription('group', '', [dummy1, dummy2])
    async with await Config(group) as cfg_ori:
        await cfg_ori.property.read_write()
        cfg = cfg_ori
        # FIXME cfg = await get_config(cfg_ori, config_type)
        owner = await cfg.owner.get()
        await cfg.option('dummy1').value.set(True)
        await cfg.option('dummy2').value.set(False)
        assert await cfg.option('dummy1').owner.get() == owner
        assert await cfg.option('dummy2').owner.get() == owner
        # if config_type == 'tiramisu-api':
        #     await cfg.send()
        await cfg_ori.option('dummy1').property.add('frozen')
        await cfg_ori.option('dummy2').property.add('frozen')
        # cfg = await get_config(cfg_ori, config_type)
        assert await cfg.option('dummy1').value.get() is False
        assert await cfg.option('dummy2').value.get() is False
        assert await cfg.option('dummy1').owner.isdefault()
        assert await cfg.option('dummy2').owner.get() == owner
        # if config_type == 'tiramisu-api':
        #     await cfg.send()
        with pytest.raises(PropertiesOptionError):
            await cfg_ori.option('dummy2').owner.set('frozen')
        # cfg = await get_config(cfg_ori, config_type)
        with pytest.raises(PropertiesOptionError):
            await cfg.option('dummy1').value.reset()
        # if config_type == 'tiramisu-api':
        #     await cfg.send()
        await cfg_ori.option('dummy1').property.pop('frozen')
        # cfg = await get_config(cfg_ori, config_type)
        await cfg.option('dummy1').value.reset()
        # if config_type == 'tiramisu-api':
        #     await cfg.send()
        await cfg.option('dummy1').property.add('frozen')
        # cfg = await get_config(cfg_ori, config_type)
        with pytest.raises(PropertiesOptionError):
            await cfg.option('dummy2').owner.set('frozen')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_force_default_on_freeze_multi():
    dummy1 = BoolOption('dummy1', 'doc dummy', default=[False], properties=('force_default_on_freeze',), multi=True)
    dummy2 = BoolOption('dummy2', 'doc dummy', default=[True], multi=True)
    group = OptionDescription('group', '', [dummy1, dummy2])
    async with await Config(group) as cfg_ori:
        await cfg_ori.property.read_write()
        cfg = cfg_ori
        # FIXME cfg = await get_config(cfg_ori, config_type)
        await cfg.option('dummy1').value.set([undefined, True])
        await cfg.option('dummy2').value.set([undefined, False])
        owner = await cfg.owner.get()
        assert await cfg.option('dummy1').owner.get() == owner
        assert await cfg.option('dummy2').owner.get() == owner
        # if config_type == 'tiramisu-api':
        #     await cfg.send()
        await cfg_ori.option('dummy1').property.add('frozen')
        await cfg_ori.option('dummy2').property.add('frozen')
        # cfg = await get_config(cfg_ori, config_type)
        assert await cfg.option('dummy1').value.get() == [False]
        assert await cfg.option('dummy2').value.get() == [True, False]
        assert await cfg.option('dummy1').owner.isdefault()
        assert await cfg.option('dummy2').owner.get() == owner
        # if config_type == 'tiramisu-api':
        #     await cfg.send()
        with pytest.raises(PropertiesOptionError):
            await cfg_ori.option('dummy2').owner.set('owner')
        # cfg = await get_config(cfg_ori, config_type)
        with pytest.raises(PropertiesOptionError):
            await cfg.option('dummy2').value.reset()
        # if config_type == 'tiramisu-api':
        #     await cfg.send()
        await cfg_ori.option('dummy1').property.pop('frozen')
        # cfg = await get_config(cfg_ori, config_type)
        await cfg.option('dummy1').value.reset()
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_force_default_on_freeze_leader():
    dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_default_on_freeze',))
    dummy2 = BoolOption('dummy2', 'Test string option', multi=True)
    descr = Leadership("dummy1", "", [dummy1, dummy2])
    descr = OptionDescription("root", "", [descr])
    with pytest.raises(ConfigError):
        await Config(descr, session_id='error')
    await delete_session('error')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_force_metaconfig_on_freeze_leader():
    dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_metaconfig_on_freeze',))
    dummy2 = BoolOption('dummy2', 'Test string option', multi=True)
    descr = Leadership("dummy1", "", [dummy1, dummy2])
    descr = OptionDescription("root", "", [descr])
    with pytest.raises(ConfigError):
        await Config(descr, session_id='error')
    await delete_session('error')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_force_default_on_freeze_leader_frozen():
    dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_default_on_freeze', 'frozen'))
    dummy2 = BoolOption('dummy2', 'Test string option', multi=True)
    descr = Leadership("dummy1", "", [dummy1, dummy2])
    descr = OptionDescription("root", "", [descr])
    async with await Config(descr) as cfg:
        with pytest.raises(LeadershipError):
            await cfg.option('dummy1.dummy1').property.pop('frozen')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_force_metaconfig_on_freeze_leader_frozen():
    dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_metaconfig_on_freeze', 'frozen'))
    dummy2 = BoolOption('dummy2', 'Test string option', multi=True)
    descr = Leadership("dummy1", "", [dummy1, dummy2])
    descr = OptionDescription("root", "", [descr])
    async with await Config(descr) as cfg:
        with pytest.raises(LeadershipError):
            await cfg.option('dummy1.dummy1').property.pop('frozen')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_force_default_on_freeze_follower(config_type):
    dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('notunique',))
    dummy2 = BoolOption('dummy2', 'Test string option', multi=True, properties=('force_default_on_freeze',))
    descr = Leadership("dummy1", "", [dummy1, dummy2])
    descr = OptionDescription("root", "", [descr])
    async with await Config(descr) as cfg_ori:
        await cfg_ori.property.read_write()
        cfg = await get_config(cfg_ori, config_type)
        await cfg.option('dummy1.dummy1').value.set([True])
        await cfg.option('dummy1.dummy2', 0).value.set(False)
        assert await cfg.option('dummy1.dummy1').value.get() == [True]
        assert await cfg.option('dummy1.dummy2', 0).value.get() == False
        assert await cfg.option('dummy1.dummy1').owner.get() == 'user'
        assert await cfg.option('dummy1.dummy2', 0).owner.get() == 'user'
        #
        if config_type == 'tiramisu-api':
            await cfg.send()
        await cfg_ori.option('dummy1.dummy2').property.add('frozen')
        cfg = await get_config(cfg_ori, config_type)
        assert await cfg.option('dummy1.dummy1').value.get() == [True]
        assert await cfg.option('dummy1.dummy2', 0).value.get() == None
        assert await cfg.option('dummy1.dummy1').owner.get() == 'user'
        assert await cfg.option('dummy1.dummy2', 0).owner.isdefault()
        if config_type == 'tiramisu-api':
            await cfg.send()
        with pytest.raises(PropertiesOptionError):
            await cfg_ori.option('dummy1.dummy2', 0).owner.set('frozenmultifollower')
        cfg = await get_config(cfg_ori, config_type)
        #
        if config_type == 'tiramisu-api':
            await cfg.send()
        await cfg_ori.option('dummy1.dummy2').property.pop('frozen')
        cfg = await get_config(cfg_ori, config_type)
        await cfg.option('dummy1.dummy1').value.set([True, True])
        await cfg.option('dummy1.dummy2', 1).value.set(False)
        assert await cfg.option('dummy1.dummy1').value.get() == [True, True]
        assert await cfg.option('dummy1.dummy2', 0).value.get() == False
        assert await cfg.option('dummy1.dummy2', 1).value.get() == False
        #
        if config_type == 'tiramisu-api':
            await cfg.send()
        await cfg_ori.option('dummy1.dummy2').property.add('frozen')
        cfg = await get_config(cfg_ori, config_type)
        assert await cfg.option('dummy1.dummy1').value.get() == [True, True]
        assert await cfg.option('dummy1.dummy2', 0).value.get() == None
        assert await cfg.option('dummy1.dummy2', 1).value.get() == None
        #
        await cfg.option('dummy1.dummy1').value.pop(1)
        assert await cfg.option('dummy1.dummy1').value.get() == [True]
        assert await cfg.option('dummy1.dummy2', 0).value.get() == None
        #
        if config_type == 'tiramisu-api':
            await cfg.send()
        await cfg_ori.option('dummy1.dummy2').property.pop('frozen')
        cfg = await get_config(cfg_ori, config_type)
        assert await cfg.option('dummy1.dummy1').value.get() == [True]
        assert await cfg.option('dummy1.dummy2', 0).value.get() == False
        #
        await cfg.option('dummy1.dummy1').value.set([True, True])
        assert await cfg.option('dummy1.dummy2', 0).value.get() == False
        assert await cfg.option('dummy1.dummy2', 1).value.get() == None
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_overrides_changes_option_value(config_type):
    "with config.override(), the default is changed and the value is changed"
    descr = OptionDescription("test", "", [
        BoolOption("b", "", default=False)])
    async with await Config(descr) as cfg:
        cfg = await get_config(cfg, config_type)
        await cfg.option('b').value.set(True)
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_choice_with_no_default(config_type):
    descr = OptionDescription("test", "", [
        ChoiceOption("backend", "", ("c", "cli"))])
    async with await Config(descr) as cfg:
        cfg = await get_config(cfg, config_type)
        assert await cfg.option('backend').value.get() is None
        await cfg.option('backend').value.set('c')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_choice_with_default(config_type):
    descr = OptionDescription("test", "", [
        ChoiceOption("backend", "", ("c", "cli"), default="cli")])
    async with await Config(descr) as cfg:
        cfg = await get_config(cfg, config_type)
        assert await cfg.option('backend').value.get() == 'cli'
    assert not await list_sessions()